diff options
Diffstat (limited to 'arch/microblaze/include/asm')
55 files changed, 4338 insertions, 0 deletions
diff --git a/arch/microblaze/include/asm/Kbuild b/arch/microblaze/include/asm/Kbuild new file mode 100644 index 000000000..569ba9e67 --- /dev/null +++ b/arch/microblaze/include/asm/Kbuild @@ -0,0 +1,33 @@ +generic-y += barrier.h +generic-y += bitops.h +generic-y += bug.h +generic-y += bugs.h +generic-y += compat.h +generic-y += device.h +generic-y += div64.h +generic-y += dma-mapping.h +generic-y += emergency-restart.h +generic-y += exec.h +generic-y += extable.h +generic-y += fb.h +generic-y += hardirq.h +generic-y += irq_regs.h +generic-y += irq_work.h +generic-y += kdebug.h +generic-y += kmap_types.h +generic-y += kprobes.h +generic-y += linkage.h +generic-y += local.h +generic-y += local64.h +generic-y += mcs_spinlock.h +generic-y += mm-arch-hooks.h +generic-y += parport.h +generic-y += percpu.h +generic-y += preempt.h +generic-y += serial.h +generic-y += syscalls.h +generic-y += topology.h +generic-y += trace_clock.h +generic-y += vga.h +generic-y += word-at-a-time.h +generic-y += xor.h diff --git a/arch/microblaze/include/asm/asm-compat.h b/arch/microblaze/include/asm/asm-compat.h new file mode 100644 index 000000000..c05259ce2 --- /dev/null +++ b/arch/microblaze/include/asm/asm-compat.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_MICROBLAZE_ASM_COMPAT_H +#define _ASM_MICROBLAZE_ASM_COMPAT_H + +#include <asm/types.h> + +#ifdef __ASSEMBLY__ +# define stringify_in_c(...) __VA_ARGS__ +# define ASM_CONST(x) x +#else +/* This version of stringify will deal with commas... */ +# define __stringify_in_c(...) #__VA_ARGS__ +# define stringify_in_c(...) __stringify_in_c(__VA_ARGS__) " " +# define __ASM_CONST(x) x##UL +# define ASM_CONST(x) __ASM_CONST(x) +#endif + +#endif /* _ASM_MICROBLAZE_ASM_COMPAT_H */ diff --git a/arch/microblaze/include/asm/asm-offsets.h b/arch/microblaze/include/asm/asm-offsets.h new file mode 100644 index 000000000..d370ee36a --- /dev/null +++ b/arch/microblaze/include/asm/asm-offsets.h @@ -0,0 +1 @@ +#include <generated/asm-offsets.h> diff --git a/arch/microblaze/include/asm/atomic.h b/arch/microblaze/include/asm/atomic.h new file mode 100644 index 000000000..41e9aff23 --- /dev/null +++ b/arch/microblaze/include/asm/atomic.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_MICROBLAZE_ATOMIC_H +#define _ASM_MICROBLAZE_ATOMIC_H + +#include <asm/cmpxchg.h> +#include <asm-generic/atomic.h> +#include <asm-generic/atomic64.h> + +/* + * Atomically test *v and decrement if it is greater than 0. + * The function returns the old value of *v minus 1. + */ +static inline int atomic_dec_if_positive(atomic_t *v) +{ + unsigned long flags; + int res; + + local_irq_save(flags); + res = v->counter - 1; + if (res >= 0) + v->counter = res; + local_irq_restore(flags); + + return res; +} +#define atomic_dec_if_positive atomic_dec_if_positive + +#endif /* _ASM_MICROBLAZE_ATOMIC_H */ diff --git a/arch/microblaze/include/asm/cache.h b/arch/microblaze/include/asm/cache.h new file mode 100644 index 000000000..4efe96a03 --- /dev/null +++ b/arch/microblaze/include/asm/cache.h @@ -0,0 +1,24 @@ +/* + * Cache operations + * + * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2007-2009 PetaLogix + * Copyright (C) 2003 John Williams <jwilliams@itee.uq.edu.au> + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + */ + +#ifndef _ASM_MICROBLAZE_CACHE_H +#define _ASM_MICROBLAZE_CACHE_H + +#include <asm/registers.h> + +#define L1_CACHE_SHIFT 5 +/* word-granular cache in microblaze */ +#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) + +#define SMP_CACHE_BYTES L1_CACHE_BYTES + +#endif /* _ASM_MICROBLAZE_CACHE_H */ diff --git a/arch/microblaze/include/asm/cacheflush.h b/arch/microblaze/include/asm/cacheflush.h new file mode 100644 index 000000000..b091de77b --- /dev/null +++ b/arch/microblaze/include/asm/cacheflush.h @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2007-2009 PetaLogix + * Copyright (C) 2007 John Williams <john.williams@petalogix.com> + * based on v850 version which was + * Copyright (C) 2001,02,03 NEC Electronics Corporation + * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org> + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + */ + +#ifndef _ASM_MICROBLAZE_CACHEFLUSH_H +#define _ASM_MICROBLAZE_CACHEFLUSH_H + +/* Somebody depends on this; sigh... */ +#include <linux/mm.h> +#include <linux/io.h> + +/* Look at Documentation/core-api/cachetlb.rst */ + +/* + * Cache handling functions. + * Microblaze has a write-through data cache, meaning that the data cache + * never needs to be flushed. The only flushing operations that are + * implemented are to invalidate the instruction cache. These are called + * after loading a user application into memory, we must invalidate the + * 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() 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 ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1 +/* MS: We have to implement it because of rootfs-jffs2 issue on WB */ +#define flush_dcache_page(page) \ +do { \ + unsigned long addr = (unsigned long) page_address(page); /* virtual */ \ + addr = (u32)virt_to_phys((void *)addr); \ + flush_dcache_range((unsigned) (addr), (unsigned) (addr) + PAGE_SIZE); \ +} while (0); + +#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) \ + flush_dcache_range(pfn << PAGE_SHIFT, (pfn << PAGE_SHIFT) + PAGE_SIZE); + +/* 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_range(vma, start, len) do { } while (0) + +static inline void copy_to_user_page(struct vm_area_struct *vma, + struct page *page, unsigned long vaddr, + void *dst, void *src, int len) +{ + u32 addr = virt_to_phys(dst); + memcpy(dst, src, len); + if (vma->vm_flags & VM_EXEC) { + invalidate_icache_range(addr, addr + PAGE_SIZE); + flush_dcache_range(addr, addr + PAGE_SIZE); + } +} + +static inline void copy_from_user_page(struct vm_area_struct *vma, + struct page *page, unsigned long vaddr, + void *dst, void *src, int len) +{ + memcpy(dst, src, len); +} + +#endif /* _ASM_MICROBLAZE_CACHEFLUSH_H */ diff --git a/arch/microblaze/include/asm/checksum.h b/arch/microblaze/include/asm/checksum.h new file mode 100644 index 000000000..adeecebbb --- /dev/null +++ b/arch/microblaze/include/asm/checksum.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2008 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2006 Atmark Techno, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_MICROBLAZE_CHECKSUM_H +#define _ASM_MICROBLAZE_CHECKSUM_H + +/* + * computes the checksum of the TCP/UDP pseudo-header + * returns a 16-bit checksum, already complemented + */ +#define csum_tcpudp_nofold csum_tcpudp_nofold +static inline __wsum +csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len, + __u8 proto, __wsum sum) +{ + __asm__("add %0, %0, %1\n\t" + "addc %0, %0, %2\n\t" + "addc %0, %0, %3\n\t" + "addc %0, %0, r0\n\t" + : "+&d" (sum) + : "d" (saddr), "d" (daddr), +#ifdef __MICROBLAZEEL__ + "d" ((len + proto) << 8) +#else + "d" (len + proto) +#endif +); + return sum; +} + +#include <asm-generic/checksum.h> + +#endif /* _ASM_MICROBLAZE_CHECKSUM_H */ diff --git a/arch/microblaze/include/asm/cmpxchg.h b/arch/microblaze/include/asm/cmpxchg.h new file mode 100644 index 000000000..596300c74 --- /dev/null +++ b/arch/microblaze/include/asm/cmpxchg.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_MICROBLAZE_CMPXCHG_H +#define _ASM_MICROBLAZE_CMPXCHG_H + +#include <linux/irqflags.h> + +void __bad_xchg(volatile void *ptr, int size); + +static inline unsigned long __xchg(unsigned long x, volatile void *ptr, + int size) +{ + unsigned long ret; + unsigned long flags; + + switch (size) { + case 1: + local_irq_save(flags); + ret = *(volatile unsigned char *)ptr; + *(volatile unsigned char *)ptr = x; + local_irq_restore(flags); + break; + + case 4: + local_irq_save(flags); + ret = *(volatile unsigned long *)ptr; + *(volatile unsigned long *)ptr = x; + local_irq_restore(flags); + break; + default: + __bad_xchg(ptr, size), ret = 0; + break; + } + + return ret; +} + +#define xchg(ptr, x) \ + ((__typeof__(*(ptr))) __xchg((unsigned long)(x), (ptr), sizeof(*(ptr)))) + +#include <asm-generic/cmpxchg.h> +#include <asm-generic/cmpxchg-local.h> + +#endif /* _ASM_MICROBLAZE_CMPXCHG_H */ diff --git a/arch/microblaze/include/asm/cpuinfo.h b/arch/microblaze/include/asm/cpuinfo.h new file mode 100644 index 000000000..8f4996730 --- /dev/null +++ b/arch/microblaze/include/asm/cpuinfo.h @@ -0,0 +1,108 @@ +/* + * Generic support for queying CPU info + * + * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2007-2009 PetaLogix + * Copyright (C) 2007 John Williams <jwilliams@itee.uq.edu.au> + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + */ + +#ifndef _ASM_MICROBLAZE_CPUINFO_H +#define _ASM_MICROBLAZE_CPUINFO_H + +#include <linux/of.h> + +/* CPU Version and FPGA Family code conversion table type */ +struct cpu_ver_key { + const char *s; + const unsigned k; +}; + +extern const struct cpu_ver_key cpu_ver_lookup[]; + +struct family_string_key { + const char *s; + const unsigned k; +}; + +extern const struct family_string_key family_string_lookup[]; + +struct cpuinfo { + /* Core CPU configuration */ + u32 use_instr; + u32 use_mult; + u32 use_fpu; + u32 use_exc; + u32 ver_code; + u32 mmu; + u32 mmu_privins; + u32 endian; + + /* CPU caches */ + u32 use_icache; + u32 icache_tagbits; + u32 icache_write; + u32 icache_line_length; + u32 icache_size; + unsigned long icache_base; + unsigned long icache_high; + + u32 use_dcache; + u32 dcache_tagbits; + u32 dcache_write; + u32 dcache_line_length; + u32 dcache_size; + u32 dcache_wb; + unsigned long dcache_base; + unsigned long dcache_high; + + /* Bus connections */ + u32 use_dopb; + u32 use_iopb; + u32 use_dlmb; + u32 use_ilmb; + u32 num_fsl; + + /* CPU interrupt line info */ + u32 irq_edge; + u32 irq_positive; + + u32 area_optimised; + + /* HW debug support */ + u32 hw_debug; + u32 num_pc_brk; + u32 num_rd_brk; + u32 num_wr_brk; + u32 cpu_clock_freq; /* store real freq of cpu */ + + /* FPGA family */ + u32 fpga_family_code; + + /* User define */ + u32 pvr_user1; + u32 pvr_user2; +}; + +extern struct cpuinfo cpuinfo; + +/* fwd declarations of the various CPUinfo populators */ +void setup_cpuinfo(void); +void setup_cpuinfo_clk(void); + +void set_cpuinfo_static(struct cpuinfo *ci, struct device_node *cpu); +void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu); + +static inline unsigned int fcpu(struct device_node *cpu, char *n) +{ + u32 val = 0; + + of_property_read_u32(cpu, n, &val); + + return val; +} + +#endif /* _ASM_MICROBLAZE_CPUINFO_H */ diff --git a/arch/microblaze/include/asm/cputable.h b/arch/microblaze/include/asm/cputable.h new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/arch/microblaze/include/asm/cputable.h @@ -0,0 +1 @@ + diff --git a/arch/microblaze/include/asm/current.h b/arch/microblaze/include/asm/current.h new file mode 100644 index 000000000..29303ed82 --- /dev/null +++ b/arch/microblaze/include/asm/current.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2008-2009 PetaLogix + * Copyright (C) 2006 Atmark Techno, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_MICROBLAZE_CURRENT_H +#define _ASM_MICROBLAZE_CURRENT_H + +/* + * Register used to hold the current task pointer while in the kernel. + * Any `call clobbered' register without a special meaning should be OK, + * but check asm/microblaze/kernel/entry.S to be sure. + */ +#define CURRENT_TASK r31 +# ifndef __ASSEMBLY__ +/* + * Dedicate r31 to keeping the current task pointer + */ +register struct task_struct *current asm("r31"); + +# define get_current() current +# endif /* __ASSEMBLY__ */ + +#endif /* _ASM_MICROBLAZE_CURRENT_H */ diff --git a/arch/microblaze/include/asm/delay.h b/arch/microblaze/include/asm/delay.h new file mode 100644 index 000000000..ea2a9cd9b --- /dev/null +++ b/arch/microblaze/include/asm/delay.h @@ -0,0 +1,90 @@ +/* + * include/asm-microblaze/delay.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2008 Michal Simek + * Copyright (C) 2007 John Williams + * Copyright (C) 2006 Atmark Techno, Inc. + */ + +#ifndef _ASM_MICROBLAZE_DELAY_H +#define _ASM_MICROBLAZE_DELAY_H + +#include <linux/param.h> + +static inline void __delay(unsigned long loops) +{ + asm volatile ("# __delay \n\t" \ + "1: addi %0, %0, -1\t\n" \ + "bneid %0, 1b \t\n" \ + "nop \t\n" + : "=r" (loops) + : "0" (loops)); +} + +/* + * Note that 19 * 226 == 4294 ==~ 2^32 / 10^6, so + * loops = (4294 * usecs * loops_per_jiffy * HZ) / 2^32. + * + * The mul instruction gives us loops = (a * b) / 2^32. + * We choose a = usecs * 19 * HZ and b = loops_per_jiffy * 226 + * because this lets us support a wide range of HZ and + * loops_per_jiffy values without either a or b overflowing 2^32. + * Thus we need usecs * HZ <= (2^32 - 1) / 19 = 226050910 and + * loops_per_jiffy <= (2^32 - 1) / 226 = 19004280 + * (which corresponds to ~3800 bogomips at HZ = 100). + * -- paulus + */ +#define __MAX_UDELAY (226050910UL/HZ) /* maximum udelay argument */ +#define __MAX_NDELAY (4294967295UL/HZ) /* maximum ndelay argument */ + +extern unsigned long loops_per_jiffy; + +static inline void __udelay(unsigned int x) +{ + + unsigned long long tmp = + (unsigned long long)x * (unsigned long long)loops_per_jiffy \ + * 226LL; + unsigned loops = tmp >> 32; + +/* + __asm__("mulxuu %0,%1,%2" : "=r" (loops) : + "r" (x), "r" (loops_per_jiffy * 226)); +*/ + __delay(loops); +} + +extern void __bad_udelay(void); /* deliberately undefined */ +extern void __bad_ndelay(void); /* deliberately undefined */ + +#define udelay(n) \ + ({ \ + if (__builtin_constant_p(n)) { \ + if ((n) / __MAX_UDELAY >= 1) \ + __bad_udelay(); \ + else \ + __udelay((n) * (19 * HZ)); \ + } else { \ + __udelay((n) * (19 * HZ)); \ + } \ + }) + +#define ndelay(n) \ + ({ \ + if (__builtin_constant_p(n)) { \ + if ((n) / __MAX_NDELAY >= 1) \ + __bad_ndelay(); \ + else \ + __udelay((n) * HZ); \ + } else { \ + __udelay((n) * HZ); \ + } \ + }) + +#define muldiv(a, b, c) (((a)*(b))/(c)) + +#endif /* _ASM_MICROBLAZE_DELAY_H */ diff --git a/arch/microblaze/include/asm/dma.h b/arch/microblaze/include/asm/dma.h new file mode 100644 index 000000000..0d73d0c6d --- /dev/null +++ b/arch/microblaze/include/asm/dma.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2006 Atmark Techno, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_MICROBLAZE_DMA_H +#define _ASM_MICROBLAZE_DMA_H + +#ifndef CONFIG_MMU +/* we don't have dma address limit. define it as zero to be + * unlimited. */ +#define MAX_DMA_ADDRESS (0) +#else +/* Virtual address corresponding to last available physical memory address. */ +#define MAX_DMA_ADDRESS (CONFIG_KERNEL_START + memory_size - 1) +#endif + +#ifdef CONFIG_PCI +extern int isa_dma_bridge_buggy; +#else +#define isa_dma_bridge_buggy (0) +#endif + +#endif /* _ASM_MICROBLAZE_DMA_H */ diff --git a/arch/microblaze/include/asm/elf.h b/arch/microblaze/include/asm/elf.h new file mode 100644 index 000000000..659024449 --- /dev/null +++ b/arch/microblaze/include/asm/elf.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2008-2009 PetaLogix + * Copyright (C) 2006 Atmark Techno, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#ifndef _ASM_MICROBLAZE_ELF_H +#define _ASM_MICROBLAZE_ELF_H + +#include <uapi/asm/elf.h> + +#ifndef __uClinux__ +#ifndef ELF_GREG_T +#endif +#ifndef ELF_NGREG +#endif +#ifndef ELF_GREGSET_T +#endif +#ifndef ELF_FPREGSET_T +#endif +#ifdef __MICROBLAZEEL__ +#else +#endif +#define SET_PERSONALITY(ex) \ + set_personality(PER_LINUX_32BIT | (current->personality & (~PER_MASK))) +#endif /* __uClinux__ */ +#endif /* _ASM_MICROBLAZE_ELF_H */ diff --git a/arch/microblaze/include/asm/entry.h b/arch/microblaze/include/asm/entry.h new file mode 100644 index 000000000..596e485ae --- /dev/null +++ b/arch/microblaze/include/asm/entry.h @@ -0,0 +1,37 @@ +/* + * Definitions used by low-level trap handlers + * + * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2007-2009 PetaLogix + * Copyright (C) 2007 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 + * archive for more details. + */ + +#ifndef _ASM_MICROBLAZE_ENTRY_H +#define _ASM_MICROBLAZE_ENTRY_H + +#include <asm/percpu.h> +#include <asm/ptrace.h> +#include <linux/linkage.h> + +/* + * These are per-cpu variables required in entry.S, among other + * places + */ + +#define PER_CPU(var) var + +# ifndef __ASSEMBLY__ +DECLARE_PER_CPU(unsigned int, KSP); /* Saved kernel stack pointer */ +DECLARE_PER_CPU(unsigned int, KM); /* Kernel/user mode */ +DECLARE_PER_CPU(unsigned int, ENTRY_SP); /* Saved SP on kernel entry */ +DECLARE_PER_CPU(unsigned int, R11_SAVE); /* Temp variable for entry */ +DECLARE_PER_CPU(unsigned int, CURRENT_SAVE); /* Saved current pointer */ + +extern asmlinkage void do_notify_resume(struct pt_regs *regs, int in_syscall); +# endif /* __ASSEMBLY__ */ + +#endif /* _ASM_MICROBLAZE_ENTRY_H */ diff --git a/arch/microblaze/include/asm/exceptions.h b/arch/microblaze/include/asm/exceptions.h new file mode 100644 index 000000000..e6a8ddea1 --- /dev/null +++ b/arch/microblaze/include/asm/exceptions.h @@ -0,0 +1,77 @@ +/* + * Preliminary support for HW exception handing for Microblaze + * + * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2008-2009 PetaLogix + * Copyright (C) 2005 John Williams <jwilliams@itee.uq.edu.au> + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + */ + +#ifndef _ASM_MICROBLAZE_EXCEPTIONS_H +#define _ASM_MICROBLAZE_EXCEPTIONS_H + +#ifdef __KERNEL__ + +#ifndef CONFIG_MMU +#define EX_HANDLER_STACK_SIZ (4*19) +#endif + +#ifndef __ASSEMBLY__ + +/* Macros to enable and disable HW exceptions in the MSR */ +/* Define MSR enable bit for HW exceptions */ +#define HWEX_MSR_BIT (1 << 8) + +#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR +#define __enable_hw_exceptions() \ + __asm__ __volatile__ (" msrset r0, %0; \ + nop;" \ + : \ + : "i" (HWEX_MSR_BIT) \ + : "memory") + +#define __disable_hw_exceptions() \ + __asm__ __volatile__ (" msrclr r0, %0; \ + nop;" \ + : \ + : "i" (HWEX_MSR_BIT) \ + : "memory") +#else /* !CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR */ +#define __enable_hw_exceptions() \ + __asm__ __volatile__ (" \ + mfs r12, rmsr; \ + nop; \ + ori r12, r12, %0; \ + mts rmsr, r12; \ + nop;" \ + : \ + : "i" (HWEX_MSR_BIT) \ + : "memory", "r12") + +#define __disable_hw_exceptions() \ + __asm__ __volatile__ (" \ + mfs r12, rmsr; \ + nop; \ + andi r12, r12, ~%0; \ + mts rmsr, r12; \ + nop;" \ + : \ + : "i" (HWEX_MSR_BIT) \ + : "memory", "r12") +#endif /* CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR */ + +asmlinkage void full_exception(struct pt_regs *regs, unsigned int type, + int fsr, int addr); + +asmlinkage void sw_exception(struct pt_regs *regs); +void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig); + +void die(const char *str, struct pt_regs *fp, long err); +void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr); + +#endif /*__ASSEMBLY__ */ +#endif /* __KERNEL__ */ +#endif /* _ASM_MICROBLAZE_EXCEPTIONS_H */ diff --git a/arch/microblaze/include/asm/fixmap.h b/arch/microblaze/include/asm/fixmap.h new file mode 100644 index 000000000..06c0e2b18 --- /dev/null +++ b/arch/microblaze/include/asm/fixmap.h @@ -0,0 +1,69 @@ +/* + * fixmap.h: compile-time virtual memory allocation + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1998 Ingo Molnar + * + * Copyright 2008 Freescale Semiconductor Inc. + * Port to powerpc added by Kumar Gala + * + * Copyright 2011 Michal Simek <monstr@monstr.eu> + * Copyright 2011 PetaLogix Qld Pty Ltd + * Port to Microblaze + */ + +#ifndef _ASM_FIXMAP_H +#define _ASM_FIXMAP_H + +#ifndef __ASSEMBLY__ +#include <linux/kernel.h> +#include <asm/page.h> +#ifdef CONFIG_HIGHMEM +#include <linux/threads.h> +#include <asm/kmap_types.h> +#endif + +#define FIXADDR_TOP ((unsigned long)(-PAGE_SIZE)) + +/* + * Here we define all the compile-time 'special' virtual + * addresses. The point is to have a constant address at + * compile time, but to set the physical address only + * in the boot process. We allocate these special addresses + * from the end of virtual memory (0xfffff000) backwards. + * Also this lets us do fail-safe vmalloc(), we + * can guarantee that these special addresses and + * vmalloc()-ed addresses never overlap. + * + * these 'compile-time allocated' memory buffers are + * fixed-size 4k pages. (or larger if used with an increment + * highger than 1) use fixmap_set(idx,phys) to associate + * physical memory with fixmap indices. + * + * TLB entries of such buffers will not be flushed across + * task switches. + */ +enum fixed_addresses { + FIX_HOLE, +#ifdef CONFIG_HIGHMEM + FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */ + FIX_KMAP_END = FIX_KMAP_BEGIN + (KM_TYPE_NR * num_possible_cpus()) - 1, +#endif + __end_of_fixed_addresses +}; + +extern void __set_fixmap(enum fixed_addresses idx, + phys_addr_t phys, pgprot_t flags); + +#define __FIXADDR_SIZE (__end_of_fixed_addresses << PAGE_SHIFT) +#define FIXADDR_START (FIXADDR_TOP - __FIXADDR_SIZE) + +#define FIXMAP_PAGE_NOCACHE PAGE_KERNEL_CI + +#include <asm-generic/fixmap.h> + +#endif /* !__ASSEMBLY__ */ +#endif diff --git a/arch/microblaze/include/asm/flat.h b/arch/microblaze/include/asm/flat.h new file mode 100644 index 000000000..3d2747d4c --- /dev/null +++ b/arch/microblaze/include/asm/flat.h @@ -0,0 +1,89 @@ +/* + * uClinux flat-format executables + * + * Copyright (C) 2005 John Williams <jwilliams@itee.uq.edu.au> + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + */ + +#ifndef _ASM_MICROBLAZE_FLAT_H +#define _ASM_MICROBLAZE_FLAT_H + +#include <asm/unaligned.h> + +#define flat_argvp_envp_on_stack() 0 +#define flat_old_ram_flag(flags) (flags) +#define flat_reloc_valid(reloc, size) ((reloc) <= (size)) +#define flat_set_persistent(relval, p) 0 + +/* + * Microblaze works a little differently from other arches, because + * of the MICROBLAZE_64 reloc type. Here, a 32 bit address is split + * over two instructions, an 'imm' instruction which provides the top + * 16 bits, then the instruction "proper" which provides the low 16 + * bits. + */ + +/* + * Crack open a symbol reference and extract the address to be + * relocated. rp is a potentially unaligned pointer to the + * reference + */ + +static inline int flat_get_addr_from_rp(u32 __user *rp, u32 relval, u32 flags, + u32 *addr, u32 *persistent) +{ + u32 *p = (__force u32 *)rp; + + /* Is it a split 64/32 reference? */ + if (relval & 0x80000000) { + /* Grab the two halves of the reference */ + u32 val_hi, val_lo; + + val_hi = get_unaligned(p); + val_lo = get_unaligned(p+1); + + /* Crack the address out */ + *addr = ((val_hi & 0xffff) << 16) + (val_lo & 0xffff); + } else { + /* Get the address straight out */ + *addr = get_unaligned(p); + } + + return 0; +} + +/* + * Insert an address into the symbol reference at rp. rp is potentially + * unaligned. + */ + +static inline int +flat_put_addr_at_rp(u32 __user *rp, u32 addr, u32 relval) +{ + u32 *p = (__force u32 *)rp; + /* Is this a split 64/32 reloc? */ + if (relval & 0x80000000) { + /* Get the two "halves" */ + unsigned long val_hi = get_unaligned(p); + unsigned long val_lo = get_unaligned(p + 1); + + /* insert the address */ + val_hi = (val_hi & 0xffff0000) | addr >> 16; + val_lo = (val_lo & 0xffff0000) | (addr & 0xffff); + + /* store the two halves back into memory */ + put_unaligned(val_hi, p); + put_unaligned(val_lo, p+1); + } else { + /* Put it straight in, no messing around */ + put_unaligned(addr, p); + } + return 0; +} + +#define flat_get_relocate_addr(rel) (rel & 0x7fffffff) + +#endif /* _ASM_MICROBLAZE_FLAT_H */ diff --git a/arch/microblaze/include/asm/ftrace.h b/arch/microblaze/include/asm/ftrace.h new file mode 100644 index 000000000..5db7f4489 --- /dev/null +++ b/arch/microblaze/include/asm/ftrace.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_MICROBLAZE_FTRACE +#define _ASM_MICROBLAZE_FTRACE + +#ifdef CONFIG_FUNCTION_TRACER + +#define MCOUNT_ADDR ((unsigned 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 new file mode 100644 index 000000000..2572077b0 --- /dev/null +++ b/arch/microblaze/include/asm/futex.h @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#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) \ + : "r" (uaddr), "i" (-EFAULT), "r" (oparg) \ + ); \ +}) + +static inline int +arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) +{ + int oldval = 0, ret; + + 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("andn %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) + *oval = oldval; + + return ret; +} + +static inline int +futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, + u32 oldval, u32 newval) +{ + int ret = 0, cmp; + u32 prev; + + if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) + return -EFAULT; + + __asm__ __volatile__ ("1: lwx %1, %3, r0; \ + cmp %2, %1, %4; \ + bnei %2, 3f; \ + 2: swx %5, %3, r0; \ + addic %2, r0, 0; \ + bnei %2, 1b; \ + 3: \ + .section .fixup,\"ax\"; \ + 4: brid 3b; \ + addik %0, r0, %6; \ + .previous; \ + .section __ex_table,\"a\"; \ + .word 1b,4b,2b,4b; \ + .previous;" \ + : "+r" (ret), "=&r" (prev), "=&r"(cmp) \ + : "r" (uaddr), "r" (oldval), "r" (newval), "i" (-EFAULT)); + + *uval = prev; + return ret; +} + +#endif /* __KERNEL__ */ + +#endif diff --git a/arch/microblaze/include/asm/hash.h b/arch/microblaze/include/asm/hash.h new file mode 100644 index 000000000..ef4741a40 --- /dev/null +++ b/arch/microblaze/include/asm/hash.h @@ -0,0 +1,82 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_HASH_H +#define _ASM_HASH_H + +/* + * Fortunately, most people who want to run Linux on Microblaze enable + * both multiplier and barrel shifter, but omitting them is technically + * a supported configuration. + * + * With just a barrel shifter, we can implement an efficient constant + * multiply using shifts and adds. GCC can find a 9-step solution, but + * this 6-step solution was found by Yevgen Voronenko's implementation + * of the Hcub algorithm at http://spiral.ece.cmu.edu/mcm/gen.html. + * + * That software is really not designed for a single multiplier this large, + * but if you run it enough times with different seeds, it'll find several + * 6-shift, 6-add sequences for computing x * 0x61C88647. They are all + * c = (x << 19) + x; + * a = (x << 9) + c; + * b = (x << 23) + a; + * return (a<<11) + (b<<6) + (c<<3) - b; + * with variations on the order of the final add. + * + * Without even a shifter, it's hopless; any hash function will suck. + */ + +#if CONFIG_XILINX_MICROBLAZE0_USE_HW_MUL == 0 + +#define HAVE_ARCH__HASH_32 1 + +/* Multiply by GOLDEN_RATIO_32 = 0x61C88647 */ +static inline u32 __attribute_const__ __hash_32(u32 a) +{ +#if CONFIG_XILINX_MICROBLAZE0_USE_BARREL + unsigned int b, c; + + /* Phase 1: Compute three intermediate values */ + b = a << 23; + c = (a << 19) + a; + a = (a << 9) + c; + b += a; + + /* Phase 2: Compute (a << 11) + (b << 6) + (c << 3) - b */ + a <<= 5; + a += b; /* (a << 5) + b */ + a <<= 3; + a += c; /* (a << 8) + (b << 3) + c */ + a <<= 3; + return a - b; /* (a << 11) + (b << 6) + (c << 3) - b */ +#else + /* + * "This is really going to hurt." + * + * Without a barrel shifter, left shifts are implemented as + * repeated additions, and the best we can do is an optimal + * addition-subtraction chain. This one is not known to be + * optimal, but at 37 steps, it's decent for a 31-bit multiplier. + * + * Question: given its size (37*4 = 148 bytes per instance), + * and slowness, is this worth having inline? + */ + unsigned int b, c, d; + + b = a << 4; /* 4 */ + c = b << 1; /* 1 5 */ + b += a; /* 1 6 */ + c += b; /* 1 7 */ + c <<= 3; /* 3 10 */ + c -= a; /* 1 11 */ + d = c << 7; /* 7 18 */ + d += b; /* 1 19 */ + d <<= 8; /* 8 27 */ + d += a; /* 1 28 */ + d <<= 1; /* 1 29 */ + d += b; /* 1 30 */ + d <<= 6; /* 6 36 */ + return d + c; /* 1 37 total instructions*/ +#endif +} + +#endif /* !CONFIG_XILINX_MICROBLAZE0_USE_HW_MUL */ +#endif /* _ASM_HASH_H */ diff --git a/arch/microblaze/include/asm/highmem.h b/arch/microblaze/include/asm/highmem.h new file mode 100644 index 000000000..332c78e15 --- /dev/null +++ b/arch/microblaze/include/asm/highmem.h @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * highmem.h: virtual kernel memory mappings for high memory + * + * Used in CONFIG_HIGHMEM systems for memory pages which + * are not addressable by direct kernel virtual addresses. + * + * Copyright (C) 1999 Gerhard Wichert, Siemens AG + * Gerhard.Wichert@pdb.siemens.de + * + * + * Redesigned the x86 32-bit VM architecture to deal with + * up to 16 Terabyte physical memory. With current x86 CPUs + * we now support up to 64 Gigabytes physical RAM. + * + * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com> + */ +#ifndef _ASM_HIGHMEM_H +#define _ASM_HIGHMEM_H + +#ifdef __KERNEL__ + +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/uaccess.h> +#include <asm/fixmap.h> + +extern pte_t *kmap_pte; +extern pgprot_t kmap_prot; +extern pte_t *pkmap_page_table; + +/* + * Right now we initialize only a single pte table. It can be extended + * easily, subsequent pte tables have to be allocated in one physical + * chunk of RAM. + */ +/* + * We use one full pte table with 4K pages. And with 16K/64K/256K pages pte + * table covers enough memory (32MB/512MB/2GB resp.), so that both FIXMAP + * and PKMAP can be placed in a single pte table. We use 512 pages for PKMAP + * in case of 16K/64K/256K page sizes. + */ + +#define PKMAP_ORDER PTE_SHIFT +#define LAST_PKMAP (1 << PKMAP_ORDER) + +#define PKMAP_BASE ((FIXADDR_START - PAGE_SIZE * (LAST_PKMAP + 1)) \ + & PMD_MASK) + +#define LAST_PKMAP_MASK (LAST_PKMAP - 1) +#define PKMAP_NR(virt) ((virt - PKMAP_BASE) >> PAGE_SHIFT) +#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) + +extern void *kmap_high(struct page *page); +extern void kunmap_high(struct page *page); +extern void *kmap_atomic_prot(struct page *page, pgprot_t prot); +extern void __kunmap_atomic(void *kvaddr); + +static inline void *kmap(struct page *page) +{ + might_sleep(); + if (!PageHighMem(page)) + return page_address(page); + return kmap_high(page); +} + +static inline void kunmap(struct page *page) +{ + BUG_ON(in_interrupt()); + if (!PageHighMem(page)) + return; + kunmap_high(page); +} + +static inline void *kmap_atomic(struct page *page) +{ + return kmap_atomic_prot(page, kmap_prot); +} + +#define flush_cache_kmaps() { flush_icache(); flush_dcache(); } + +#endif /* __KERNEL__ */ + +#endif /* _ASM_HIGHMEM_H */ diff --git a/arch/microblaze/include/asm/hw_irq.h b/arch/microblaze/include/asm/hw_irq.h new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/arch/microblaze/include/asm/hw_irq.h @@ -0,0 +1 @@ + diff --git a/arch/microblaze/include/asm/io.h b/arch/microblaze/include/asm/io.h new file mode 100644 index 000000000..c79681394 --- /dev/null +++ b/arch/microblaze/include/asm/io.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2007-2009 PetaLogix + * Copyright (C) 2006 Atmark Techno, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_MICROBLAZE_IO_H +#define _ASM_MICROBLAZE_IO_H + +#include <asm/byteorder.h> +#include <asm/page.h> +#include <linux/types.h> +#include <linux/mm.h> /* Get struct page {...} */ + +#ifndef CONFIG_PCI +#define _IO_BASE 0 +#define _ISA_MEM_BASE 0 +#else +#define _IO_BASE isa_io_base +#define _ISA_MEM_BASE isa_mem_base +struct pci_dev; +extern void pci_iounmap(struct pci_dev *dev, void __iomem *); +#define pci_iounmap pci_iounmap + +extern unsigned long isa_io_base; +extern resource_size_t isa_mem_base; +#endif + +#define PCI_IOBASE ((void __iomem *)_IO_BASE) +#define IO_SPACE_LIMIT (0xFFFFFFFF) + +#ifdef CONFIG_MMU +#define page_to_bus(page) (page_to_phys(page)) + +extern void iounmap(volatile void __iomem *addr); + +extern void __iomem *ioremap(phys_addr_t address, unsigned long size); +#define ioremap_nocache(addr, size) ioremap((addr), (size)) +#define ioremap_fullcache(addr, size) ioremap((addr), (size)) +#define ioremap_wc(addr, size) ioremap((addr), (size)) +#define ioremap_wt(addr, size) ioremap((addr), (size)) + +#endif /* CONFIG_MMU */ + +/* Big Endian */ +#define out_be32(a, v) __raw_writel((v), (void __iomem __force *)(a)) +#define out_be16(a, v) __raw_writew((v), (a)) + +#define in_be32(a) __raw_readl((const void __iomem __force *)(a)) +#define in_be16(a) __raw_readw(a) + +#define writel_be(v, a) out_be32((__force unsigned *)a, v) +#define readl_be(a) in_be32((__force unsigned *)a) + +/* Little endian */ +#define out_le32(a, v) __raw_writel(__cpu_to_le32(v), (a)) +#define out_le16(a, v) __raw_writew(__cpu_to_le16(v), (a)) + +#define in_le32(a) __le32_to_cpu(__raw_readl(a)) +#define in_le16(a) __le16_to_cpu(__raw_readw(a)) + +/* Byte ops */ +#define out_8(a, v) __raw_writeb((v), (a)) +#define in_8(a) __raw_readb(a) + +#include <asm-generic/io.h> + +#endif /* _ASM_MICROBLAZE_IO_H */ diff --git a/arch/microblaze/include/asm/irq.h b/arch/microblaze/include/asm/irq.h new file mode 100644 index 000000000..d785defee --- /dev/null +++ b/arch/microblaze/include/asm/irq.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2006 Atmark Techno, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_MICROBLAZE_IRQ_H +#define _ASM_MICROBLAZE_IRQ_H + +#define NR_IRQS (32 + 1) +#include <asm-generic/irq.h> + +struct pt_regs; +extern void do_IRQ(struct pt_regs *regs); + +/* should be defined in each interrupt controller driver */ +extern unsigned int xintc_get_irq(void); + +#endif /* _ASM_MICROBLAZE_IRQ_H */ diff --git a/arch/microblaze/include/asm/irqflags.h b/arch/microblaze/include/asm/irqflags.h new file mode 100644 index 000000000..c9a626283 --- /dev/null +++ b/arch/microblaze/include/asm/irqflags.h @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2006 Atmark Techno, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_MICROBLAZE_IRQFLAGS_H +#define _ASM_MICROBLAZE_IRQFLAGS_H + +#include <linux/types.h> +#include <asm/registers.h> + +#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR + +static inline notrace unsigned long arch_local_irq_save(void) +{ + unsigned long flags; + asm volatile(" msrclr %0, %1 \n" + " nop \n" + : "=r"(flags) + : "i"(MSR_IE) + : "memory"); + return flags; +} + +static inline notrace void arch_local_irq_disable(void) +{ + /* this uses r0 without declaring it - is that correct? */ + asm volatile(" msrclr r0, %0 \n" + " nop \n" + : + : "i"(MSR_IE) + : "memory"); +} + +static inline notrace void arch_local_irq_enable(void) +{ + /* this uses r0 without declaring it - is that correct? */ + asm volatile(" msrset r0, %0 \n" + " nop \n" + : + : "i"(MSR_IE) + : "memory"); +} + +#else /* !CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR */ + +static inline notrace unsigned long arch_local_irq_save(void) +{ + unsigned long flags, tmp; + asm volatile (" mfs %0, rmsr \n" + " nop \n" + " andi %1, %0, %2 \n" + " mts rmsr, %1 \n" + " nop \n" + : "=r"(flags), "=r"(tmp) + : "i"(~MSR_IE) + : "memory"); + return flags; +} + +static inline notrace void arch_local_irq_disable(void) +{ + unsigned long tmp; + asm volatile(" mfs %0, rmsr \n" + " nop \n" + " andi %0, %0, %1 \n" + " mts rmsr, %0 \n" + " nop \n" + : "=r"(tmp) + : "i"(~MSR_IE) + : "memory"); +} + +static inline notrace void arch_local_irq_enable(void) +{ + unsigned long tmp; + asm volatile(" mfs %0, rmsr \n" + " nop \n" + " ori %0, %0, %1 \n" + " mts rmsr, %0 \n" + " nop \n" + : "=r"(tmp) + : "i"(MSR_IE) + : "memory"); +} + +#endif /* CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR */ + +static inline notrace unsigned long arch_local_save_flags(void) +{ + unsigned long flags; + asm volatile(" mfs %0, rmsr \n" + " nop \n" + : "=r"(flags) + : + : "memory"); + return flags; +} + +static inline notrace void arch_local_irq_restore(unsigned long flags) +{ + asm volatile(" mts rmsr, %0 \n" + " nop \n" + : + : "r"(flags) + : "memory"); +} + +static inline notrace bool arch_irqs_disabled_flags(unsigned long flags) +{ + return (flags & MSR_IE) == 0; +} + +static inline notrace bool arch_irqs_disabled(void) +{ + return arch_irqs_disabled_flags(arch_local_save_flags()); +} + +#endif /* _ASM_MICROBLAZE_IRQFLAGS_H */ diff --git a/arch/microblaze/include/asm/kgdb.h b/arch/microblaze/include/asm/kgdb.h new file mode 100644 index 000000000..8dc5ebb07 --- /dev/null +++ b/arch/microblaze/include/asm/kgdb.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifdef __KERNEL__ +#ifndef __MICROBLAZE_KGDB_H__ +#define __MICROBLAZE_KGDB_H__ + +#ifndef __ASSEMBLY__ + +#define CACHE_FLUSH_IS_SAFE 1 +#define BUFMAX 2048 + +/* + * 32 32-bit general purpose registers (r0-r31) + * 6 32-bit special registers (pc, msr, ear, esr, fsr, btr) + * 12 32-bit PVR + * 7 32-bit MMU Regs (redr, rpid, rzpr, rtlbx, rtlbsx, rtlblo, rtlbhi) + * ------ + * 57 registers + */ +#define NUMREGBYTES (57 * 4) + +#define BREAK_INSTR_SIZE 4 +static inline void arch_kgdb_breakpoint(void) +{ + __asm__ __volatile__("brki r16, 0x18;"); +} + +struct pt_regs; +asmlinkage void microblaze_kgdb_break(struct pt_regs *regs); + +#endif /* __ASSEMBLY__ */ +#endif /* __MICROBLAZE_KGDB_H__ */ +#endif /* __KERNEL__ */ diff --git a/arch/microblaze/include/asm/mmu.h b/arch/microblaze/include/asm/mmu.h new file mode 100644 index 000000000..1f9edddf7 --- /dev/null +++ b/arch/microblaze/include/asm/mmu.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2008-2009 PetaLogix + * Copyright (C) 2006 Atmark Techno, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_MICROBLAZE_MMU_H +#define _ASM_MICROBLAZE_MMU_H + +# ifndef CONFIG_MMU +# include <asm-generic/mmu.h> +# else /* CONFIG_MMU */ +# ifdef __KERNEL__ +# ifndef __ASSEMBLY__ + +/* Default "unsigned long" context */ +typedef unsigned long mm_context_t; + +/* Hardware Page Table Entry */ +typedef struct _PTE { + unsigned long v:1; /* Entry is valid */ + unsigned long vsid:24; /* Virtual segment identifier */ + unsigned long h:1; /* Hash algorithm indicator */ + unsigned long api:6; /* Abbreviated page index */ + unsigned long rpn:20; /* Real (physical) page number */ + unsigned long :3; /* Unused */ + unsigned long r:1; /* Referenced */ + unsigned long c:1; /* Changed */ + unsigned long w:1; /* Write-thru cache mode */ + unsigned long i:1; /* Cache inhibited */ + unsigned long m:1; /* Memory coherence */ + unsigned long g:1; /* Guarded */ + unsigned long :1; /* Unused */ + unsigned long pp:2; /* Page protection */ +} PTE; + +/* Values for PP (assumes Ks=0, Kp=1) */ +# define PP_RWXX 0 /* Supervisor read/write, User none */ +# define PP_RWRX 1 /* Supervisor read/write, User read */ +# define PP_RWRW 2 /* Supervisor read/write, User read/write */ +# define PP_RXRX 3 /* Supervisor read, User read */ + +/* Segment Register */ +typedef struct _SEGREG { + unsigned long t:1; /* Normal or I/O type */ + unsigned long ks:1; /* Supervisor 'key' (normally 0) */ + unsigned long kp:1; /* User 'key' (normally 1) */ + unsigned long n:1; /* No-execute */ + unsigned long :4; /* Unused */ + unsigned long vsid:24; /* Virtual Segment Identifier */ +} SEGREG; + +extern void _tlbie(unsigned long va); /* invalidate a TLB entry */ +extern void _tlbia(void); /* invalidate all TLB entries */ + +/* + * tlb_skip size stores actual number skipped TLBs from TLB0 - every directy TLB + * mapping has to increase tlb_skip size. + */ +extern u32 tlb_skip; +# endif /* __ASSEMBLY__ */ + +/* + * The MicroBlaze processor has a TLB architecture identical to PPC-40x. The + * instruction and data sides share a unified, 64-entry, semi-associative + * TLB which is maintained totally under software control. In addition, the + * instruction side has a hardware-managed, 2,4, or 8-entry, fully-associative + * TLB which serves as a first level to the shared TLB. These two TLBs are + * known as the UTLB and ITLB, respectively. + */ + +# define MICROBLAZE_TLB_SIZE 64 + +/* For cases when you want to skip some TLB entries */ +# define MICROBLAZE_TLB_SKIP 0 + +/* Use the last TLB for temporary access to LMB */ +# define MICROBLAZE_LMB_TLB_ID 63 + +/* + * TLB entries are defined by a "high" tag portion and a "low" data + * portion. The data portion is 32-bits. + * + * TLB entries are managed entirely under software control by reading, + * writing, and searching using the MTS and MFS instructions. + */ + +# define TLB_LO 1 +# define TLB_HI 0 +# define TLB_DATA TLB_LO +# define TLB_TAG TLB_HI + +/* Tag portion */ +# define TLB_EPN_MASK 0xFFFFFC00 /* Effective Page Number */ +# define TLB_PAGESZ_MASK 0x00000380 +# define TLB_PAGESZ(x) (((x) & 0x7) << 7) +# define PAGESZ_1K 0 +# define PAGESZ_4K 1 +# define PAGESZ_16K 2 +# define PAGESZ_64K 3 +# define PAGESZ_256K 4 +# define PAGESZ_1M 5 +# define PAGESZ_4M 6 +# define PAGESZ_16M 7 +# define TLB_VALID 0x00000040 /* Entry is valid */ + +/* Data portion */ +# define TLB_RPN_MASK 0xFFFFFC00 /* Real Page Number */ +# define TLB_PERM_MASK 0x00000300 +# define TLB_EX 0x00000200 /* Instruction execution allowed */ +# define TLB_WR 0x00000100 /* Writes permitted */ +# define TLB_ZSEL_MASK 0x000000F0 +# define TLB_ZSEL(x) (((x) & 0xF) << 4) +# define TLB_ATTR_MASK 0x0000000F +# define TLB_W 0x00000008 /* Caching is write-through */ +# define TLB_I 0x00000004 /* Caching is inhibited */ +# define TLB_M 0x00000002 /* Memory is coherent */ +# define TLB_G 0x00000001 /* Memory is guarded from prefetch */ + +# endif /* __KERNEL__ */ +# endif /* CONFIG_MMU */ +#endif /* _ASM_MICROBLAZE_MMU_H */ diff --git a/arch/microblaze/include/asm/mmu_context.h b/arch/microblaze/include/asm/mmu_context.h new file mode 100644 index 000000000..f74f9da07 --- /dev/null +++ b/arch/microblaze/include/asm/mmu_context.h @@ -0,0 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifdef CONFIG_MMU +# include <asm/mmu_context_mm.h> +#else +# include <asm-generic/mmu_context.h> +#endif diff --git a/arch/microblaze/include/asm/mmu_context_mm.h b/arch/microblaze/include/asm/mmu_context_mm.h new file mode 100644 index 000000000..97559fe0b --- /dev/null +++ b/arch/microblaze/include/asm/mmu_context_mm.h @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2008-2009 PetaLogix + * Copyright (C) 2006 Atmark Techno, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_MICROBLAZE_MMU_CONTEXT_H +#define _ASM_MICROBLAZE_MMU_CONTEXT_H + +#include <linux/atomic.h> +#include <linux/mm_types.h> +#include <linux/sched.h> + +#include <asm/bitops.h> +#include <asm/mmu.h> +#include <asm-generic/mm_hooks.h> + +# ifdef __KERNEL__ +/* + * This function defines the mapping from contexts to VSIDs (virtual + * segment IDs). We use a skew on both the context and the high 4 bits + * of the 32-bit virtual address (the "effective segment ID") in order + * to spread out the entries in the MMU hash table. + */ +# define CTX_TO_VSID(ctx, va) (((ctx) * (897 * 16) + ((va) >> 28) * 0x111) \ + & 0xffffff) + +/* + MicroBlaze has 256 contexts, so we can just rotate through these + as a way of "switching" contexts. If the TID of the TLB is zero, + the PID/TID comparison is disabled, so we can use a TID of zero + to represent all kernel pages as shared among all contexts. + */ + +static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) +{ +} + +# define NO_CONTEXT 256 +# define LAST_CONTEXT 255 +# define FIRST_CONTEXT 1 + +/* + * Set the current MMU context. + * This is done byloading up the segment registers for the user part of the + * address space. + * + * Since the PGD is immediately available, it is much faster to simply + * pass this along as a second parameter, which is required for 8xx and + * can be used for debugging on all processors (if you happen to have + * an Abatron). + */ +extern void set_context(mm_context_t context, pgd_t *pgd); + +/* + * Bitmap of contexts in use. + * The size of this bitmap is LAST_CONTEXT + 1 bits. + */ +extern unsigned long context_map[]; + +/* + * This caches the next context number that we expect to be free. + * Its use is an optimization only, we can't rely on this context + * number to be free, but it usually will be. + */ +extern mm_context_t next_mmu_context; + +/* + * Since we don't have sufficient contexts to give one to every task + * that could be in the system, we need to be able to steal contexts. + * These variables support that. + */ +extern atomic_t nr_free_contexts; +extern struct mm_struct *context_mm[LAST_CONTEXT+1]; +extern void steal_context(void); + +/* + * Get a new mmu context for the address space described by `mm'. + */ +static inline void get_mmu_context(struct mm_struct *mm) +{ + mm_context_t ctx; + + if (mm->context != NO_CONTEXT) + return; + while (atomic_dec_if_positive(&nr_free_contexts) < 0) + steal_context(); + ctx = next_mmu_context; + while (test_and_set_bit(ctx, context_map)) { + ctx = find_next_zero_bit(context_map, LAST_CONTEXT+1, ctx); + if (ctx > LAST_CONTEXT) + ctx = 0; + } + next_mmu_context = (ctx + 1) & LAST_CONTEXT; + mm->context = ctx; + context_mm[ctx] = mm; +} + +/* + * Set up the context for a new address space. + */ +# define init_new_context(tsk, mm) (((mm)->context = NO_CONTEXT), 0) + +/* + * We're finished using the context for an address space. + */ +static inline void destroy_context(struct mm_struct *mm) +{ + if (mm->context != NO_CONTEXT) { + clear_bit(mm->context, context_map); + mm->context = NO_CONTEXT; + atomic_inc(&nr_free_contexts); + } +} + +static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, + struct task_struct *tsk) +{ + tsk->thread.pgdir = next->pgd; + get_mmu_context(next); + set_context(next->context, next->pgd); +} + +/* + * After we have set current->mm to a new value, this activates + * the context for the new mm so we see the new mappings. + */ +static inline void activate_mm(struct mm_struct *active_mm, + struct mm_struct *mm) +{ + current->thread.pgdir = mm->pgd; + get_mmu_context(mm); + set_context(mm->context, mm->pgd); +} + +extern void mmu_context_init(void); + +# endif /* __KERNEL__ */ +#endif /* _ASM_MICROBLAZE_MMU_CONTEXT_H */ diff --git a/arch/microblaze/include/asm/module.h b/arch/microblaze/include/asm/module.h new file mode 100644 index 000000000..7be1347fc --- /dev/null +++ b/arch/microblaze/include/asm/module.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2006 Atmark Techno, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_MICROBLAZE_MODULE_H +#define _ASM_MICROBLAZE_MODULE_H + +#include <asm-generic/module.h> + +/* Microblaze Relocations */ +#define R_MICROBLAZE_NONE 0 +#define R_MICROBLAZE_32 1 +#define R_MICROBLAZE_32_PCREL 2 +#define R_MICROBLAZE_64_PCREL 3 +#define R_MICROBLAZE_32_PCREL_LO 4 +#define R_MICROBLAZE_64 5 +#define R_MICROBLAZE_32_LO 6 +#define R_MICROBLAZE_SRO32 7 +#define R_MICROBLAZE_SRW32 8 +#define R_MICROBLAZE_64_NONE 9 +#define R_MICROBLAZE_32_SYM_OP_SYM 10 +/* Keep this the last entry. */ +#define R_MICROBLAZE_NUM 11 + +typedef struct { volatile int counter; } module_t; + +#endif /* _ASM_MICROBLAZE_MODULE_H */ diff --git a/arch/microblaze/include/asm/page.h b/arch/microblaze/include/asm/page.h new file mode 100644 index 000000000..d506bb089 --- /dev/null +++ b/arch/microblaze/include/asm/page.h @@ -0,0 +1,212 @@ +/* + * VM ops + * + * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2008-2009 PetaLogix + * Copyright (C) 2006 Atmark Techno, Inc. + * Changes for MMU support: + * Copyright (C) 2007 Xilinx, Inc. All rights reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_MICROBLAZE_PAGE_H +#define _ASM_MICROBLAZE_PAGE_H + +#include <linux/pfn.h> +#include <asm/setup.h> +#include <asm/asm-compat.h> +#include <linux/const.h> + +#ifdef __KERNEL__ + +/* PAGE_SHIFT determines the page size */ +#if defined(CONFIG_MICROBLAZE_64K_PAGES) +#define PAGE_SHIFT 16 +#elif defined(CONFIG_MICROBLAZE_16K_PAGES) +#define PAGE_SHIFT 14 +#else +#define PAGE_SHIFT 12 +#endif +#define PAGE_SIZE (ASM_CONST(1) << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE-1)) + +#define LOAD_OFFSET ASM_CONST((CONFIG_KERNEL_START-CONFIG_KERNEL_BASE_ADDR)) + +#define PTE_SHIFT (PAGE_SHIFT - 2) /* 1024 ptes per page */ + +#ifndef __ASSEMBLY__ + +/* MS be sure that SLAB allocates aligned objects */ +#define ARCH_DMA_MINALIGN L1_CACHE_BYTES + +#define ARCH_SLAB_MINALIGN L1_CACHE_BYTES + +#define PAGE_UP(addr) (((addr)+((PAGE_SIZE)-1))&(~((PAGE_SIZE)-1))) +#define PAGE_DOWN(addr) ((addr)&(~((PAGE_SIZE)-1))) + +#ifndef CONFIG_MMU +/* + * PAGE_OFFSET -- the first address of the first page of memory. When not + * using MMU this corresponds to the first free page in physical memory (aligned + * on a page boundary). + */ +extern unsigned int __page_offset; +#define PAGE_OFFSET __page_offset + +#else /* CONFIG_MMU */ + +/* + * PAGE_OFFSET -- the first address of the first page of memory. With MMU + * it is set to the kernel start address (aligned on a page boundary). + * + * CONFIG_KERNEL_START is defined in arch/microblaze/config.in and used + * in arch/microblaze/Makefile. + */ +#define PAGE_OFFSET CONFIG_KERNEL_START + +/* + * The basic type of a PTE - 32 bit physical addressing. + */ +typedef unsigned long pte_basic_t; +#define PTE_FMT "%.8lx" + +#endif /* CONFIG_MMU */ + +# define copy_page(to, from) memcpy((to), (from), PAGE_SIZE) +# define clear_page(pgaddr) memset((pgaddr), 0, PAGE_SIZE) + +# define clear_user_page(pgaddr, vaddr, page) memset((pgaddr), 0, PAGE_SIZE) +# define copy_user_page(vto, vfrom, vaddr, topg) \ + memcpy((vto), (vfrom), PAGE_SIZE) + +/* + * These are used to make use of C type-checking.. + */ +typedef struct page *pgtable_t; +typedef struct { unsigned long pte; } pte_t; +typedef struct { unsigned long pgprot; } pgprot_t; +/* FIXME this can depend on linux kernel version */ +# ifdef CONFIG_MMU +typedef struct { unsigned long pmd; } pmd_t; +typedef struct { unsigned long pgd; } pgd_t; +# else /* CONFIG_MMU */ +typedef struct { unsigned long ste[64]; } pmd_t; +typedef struct { pmd_t pue[1]; } pud_t; +typedef struct { pud_t p4e[1]; } p4d_t; +typedef struct { p4d_t pge[1]; } pgd_t; +# endif /* CONFIG_MMU */ + +# define pte_val(x) ((x).pte) +# define pgprot_val(x) ((x).pgprot) + +# ifdef CONFIG_MMU +# define pmd_val(x) ((x).pmd) +# define pgd_val(x) ((x).pgd) +# else /* CONFIG_MMU */ +# define pmd_val(x) ((x).ste[0]) +# define pud_val(x) ((x).pue[0]) +# define pgd_val(x) ((x).pge[0]) +# endif /* CONFIG_MMU */ + +# define __pte(x) ((pte_t) { (x) }) +# define __pmd(x) ((pmd_t) { (x) }) +# define __pgd(x) ((pgd_t) { (x) }) +# define __pgprot(x) ((pgprot_t) { (x) }) + +/** + * Conversions for virtual address, physical address, pfn, and struct + * page are defined in the following files. + * + * virt -+ + * | asm-microblaze/page.h + * phys -+ + * | linux/pfn.h + * pfn -+ + * | asm-generic/memory_model.h + * page -+ + * + */ + +extern unsigned long max_low_pfn; +extern unsigned long min_low_pfn; +extern unsigned long max_pfn; + +extern unsigned long memory_start; +extern unsigned long memory_size; +extern unsigned long lowmem_size; + +extern unsigned long kernel_tlb; + +extern int page_is_ram(unsigned long pfn); + +# define phys_to_pfn(phys) (PFN_DOWN(phys)) +# define pfn_to_phys(pfn) (PFN_PHYS(pfn)) + +# define virt_to_pfn(vaddr) (phys_to_pfn((__pa(vaddr)))) +# define pfn_to_virt(pfn) __va(pfn_to_phys((pfn))) + +# ifdef CONFIG_MMU + +# define virt_to_page(kaddr) (pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)) +# define page_to_virt(page) __va(page_to_pfn(page) << PAGE_SHIFT) +# define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) + +# else /* CONFIG_MMU */ +# define virt_to_page(vaddr) (pfn_to_page(virt_to_pfn(vaddr))) +# define page_to_virt(page) (pfn_to_virt(page_to_pfn(page))) +# define page_to_phys(page) (pfn_to_phys(page_to_pfn(page))) +# define page_to_bus(page) (page_to_phys(page)) +# define phys_to_page(paddr) (pfn_to_page(phys_to_pfn(paddr))) +# endif /* CONFIG_MMU */ + +# ifndef CONFIG_MMU +# 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) +# define pfn_valid(pfn) ((pfn) < (max_mapnr + ARCH_PFN_OFFSET)) +# endif /* CONFIG_MMU */ + +# endif /* __ASSEMBLY__ */ + +#define virt_addr_valid(vaddr) (pfn_valid(virt_to_pfn(vaddr))) + +# define __pa(x) __virt_to_phys((unsigned long)(x)) +# define __va(x) ((void *)__phys_to_virt((unsigned long)(x))) + +/* Convert between virtual and physical address for MMU. */ +/* Handle MicroBlaze processor with virtual memory. */ +#ifndef CONFIG_MMU +#define __virt_to_phys(addr) addr +#define __phys_to_virt(addr) addr +#define tophys(rd, rs) addik rd, rs, 0 +#define tovirt(rd, rs) addik rd, rs, 0 +#else +#define __virt_to_phys(addr) \ + ((addr) + CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START) +#define __phys_to_virt(addr) \ + ((addr) + CONFIG_KERNEL_START - CONFIG_KERNEL_BASE_ADDR) +#define tophys(rd, rs) \ + addik rd, rs, (CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START) +#define tovirt(rd, rs) \ + addik rd, rs, (CONFIG_KERNEL_START - CONFIG_KERNEL_BASE_ADDR) +#endif /* CONFIG_MMU */ + +#define TOPHYS(addr) __virt_to_phys(addr) + +#ifdef CONFIG_MMU + +#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ + VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) +#endif /* CONFIG_MMU */ + +#endif /* __KERNEL__ */ + +#include <asm-generic/memory_model.h> +#include <asm-generic/getorder.h> + +#endif /* _ASM_MICROBLAZE_PAGE_H */ diff --git a/arch/microblaze/include/asm/pci-bridge.h b/arch/microblaze/include/asm/pci-bridge.h new file mode 100644 index 000000000..cb5d39794 --- /dev/null +++ b/arch/microblaze/include/asm/pci-bridge.h @@ -0,0 +1,144 @@ +#ifndef _ASM_MICROBLAZE_PCI_BRIDGE_H +#define _ASM_MICROBLAZE_PCI_BRIDGE_H +#ifdef __KERNEL__ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include <linux/pci.h> +#include <linux/list.h> +#include <linux/ioport.h> + +struct device_node; + +#ifdef CONFIG_PCI +extern struct list_head hose_list; +extern int pcibios_vaddr_is_ioport(void __iomem *address); +#else +static inline int pcibios_vaddr_is_ioport(void __iomem *address) +{ + return 0; +} +#endif + +/* + * Structure of a PCI controller (host bridge) + */ +struct pci_controller { + struct pci_bus *bus; + char is_dynamic; + struct device_node *dn; + struct list_head list_node; + struct device *parent; + + int first_busno; + int last_busno; + + int self_busno; + + void __iomem *io_base_virt; + resource_size_t io_base_phys; + + resource_size_t pci_io_size; + + /* Some machines (PReP) have a non 1:1 mapping of + * the PCI memory space in the CPU bus space + */ + resource_size_t pci_mem_offset; + + /* Some machines have a special region to forward the ISA + * "memory" cycles such as VGA memory regions. Left to 0 + * if unsupported + */ + resource_size_t isa_mem_phys; + resource_size_t isa_mem_size; + + struct pci_ops *ops; + unsigned int __iomem *cfg_addr; + void __iomem *cfg_data; + + /* + * Used for variants of PCI indirect handling and possible quirks: + * SET_CFG_TYPE - used on 4xx or any PHB that does explicit type0/1 + * EXT_REG - provides access to PCI-e extended registers + * SURPRESS_PRIMARY_BUS - we suppress the setting of PCI_PRIMARY_BUS + * on Freescale PCI-e controllers since they used the PCI_PRIMARY_BUS + * to determine which bus number to match on when generating type0 + * config cycles + * NO_PCIE_LINK - the Freescale PCI-e controllers have issues with + * hanging if we don't have link and try to do config cycles to + * anything but the PHB. Only allow talking to the PHB if this is + * set. + * BIG_ENDIAN - cfg_addr is a big endian register + * BROKEN_MRM - the 440EPx/GRx chips have an errata that causes hangs + * on the PLB4. Effectively disable MRM commands by setting this. + */ +#define INDIRECT_TYPE_SET_CFG_TYPE 0x00000001 +#define INDIRECT_TYPE_EXT_REG 0x00000002 +#define INDIRECT_TYPE_SURPRESS_PRIMARY_BUS 0x00000004 +#define INDIRECT_TYPE_NO_PCIE_LINK 0x00000008 +#define INDIRECT_TYPE_BIG_ENDIAN 0x00000010 +#define INDIRECT_TYPE_BROKEN_MRM 0x00000020 + u32 indirect_type; + + /* Currently, we limit ourselves to 1 IO range and 3 mem + * ranges since the common pci_bus structure can't handle more + */ + struct resource io_resource; + struct resource mem_resources[3]; + int global_number; /* PCI domain number */ +}; + +#ifdef CONFIG_PCI +static inline struct pci_controller *pci_bus_to_host(const struct pci_bus *bus) +{ + return bus->sysdata; +} + +static inline int isa_vaddr_is_ioport(void __iomem *address) +{ + /* No specific ISA handling on ppc32 at this stage, it + * all goes through PCI + */ + return 0; +} +#endif /* CONFIG_PCI */ + +/* These are used for config access before all the PCI probing + has been done. */ +extern int early_read_config_byte(struct pci_controller *hose, int bus, + int dev_fn, int where, u8 *val); +extern int early_read_config_word(struct pci_controller *hose, int bus, + int dev_fn, int where, u16 *val); +extern int early_read_config_dword(struct pci_controller *hose, int bus, + int dev_fn, int where, u32 *val); +extern int early_write_config_byte(struct pci_controller *hose, int bus, + int dev_fn, int where, u8 val); +extern int early_write_config_word(struct pci_controller *hose, int bus, + int dev_fn, int where, u16 val); +extern int early_write_config_dword(struct pci_controller *hose, int bus, + int dev_fn, int where, u32 val); + +extern int early_find_capability(struct pci_controller *hose, int bus, + int dev_fn, int cap); + +extern void setup_indirect_pci(struct pci_controller *hose, + resource_size_t cfg_addr, + resource_size_t cfg_data, u32 flags); + +/* Get the PCI host controller for an OF device */ +extern struct pci_controller *pci_find_hose_for_OF_device( + struct device_node *node); + +/* Fill up host controller resources from the OF node */ +extern void pci_process_bridge_OF_ranges(struct pci_controller *hose, + struct device_node *dev, int primary); + +/* Allocate & free a PCI host bridge structure */ +extern struct pci_controller *pcibios_alloc_controller(struct device_node *dev); +extern void pcibios_free_controller(struct pci_controller *phb); + +#endif /* __KERNEL__ */ +#endif /* _ASM_MICROBLAZE_PCI_BRIDGE_H */ diff --git a/arch/microblaze/include/asm/pci.h b/arch/microblaze/include/asm/pci.h new file mode 100644 index 000000000..859c19828 --- /dev/null +++ b/arch/microblaze/include/asm/pci.h @@ -0,0 +1,82 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Based on powerpc version + */ + +#ifndef __ASM_MICROBLAZE_PCI_H +#define __ASM_MICROBLAZE_PCI_H +#ifdef __KERNEL__ + +#include <linux/types.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/dma-mapping.h> +#include <linux/pci.h> +#include <linux/scatterlist.h> + +#include <asm/io.h> +#include <asm/pci-bridge.h> + +#define PCIBIOS_MIN_IO 0x1000 +#define PCIBIOS_MIN_MEM 0x10000000 + +/* Values for the `which' argument to sys_pciconfig_iobase syscall. */ +#define IOBASE_BRIDGE_NUMBER 0 +#define IOBASE_MEMORY 1 +#define IOBASE_IO 2 +#define IOBASE_ISA_IO 3 +#define IOBASE_ISA_MEM 4 + +#define pcibios_scan_all_fns(a, b) 0 + +/* + * Set this to 1 if you want the kernel to re-assign all PCI + * bus numbers (don't do that on ppc64 yet !) + */ +#define pcibios_assign_all_busses() 0 + +extern int pci_domain_nr(struct pci_bus *bus); + +/* Decide whether to display the domain number in /proc */ +extern int pci_proc_domain(struct pci_bus *bus); + +struct vm_area_struct; + +/* Tell PCI code what kind of PCI resource mappings we support */ +#define HAVE_PCI_MMAP 1 +#define ARCH_GENERIC_PCI_MMAP_RESOURCE 1 +#define arch_can_pci_mmap_io() 1 + +extern int pci_legacy_read(struct pci_bus *bus, loff_t port, u32 *val, + size_t count); +extern int pci_legacy_write(struct pci_bus *bus, loff_t port, u32 val, + size_t count); +extern int pci_mmap_legacy_page_range(struct pci_bus *bus, + struct vm_area_struct *vma, + enum pci_mmap_state mmap_state); + +#define HAVE_PCI_LEGACY 1 + +extern void pcibios_resource_survey(void); + +struct file; +extern pgprot_t pci_phys_mem_access_prot(struct file *file, + unsigned long pfn, + unsigned long size, + pgprot_t prot); + +#define HAVE_ARCH_PCI_RESOURCE_TO_USER + +/* This part of code was originally in xilinx-pci.h */ +#ifdef CONFIG_PCI_XILINX +extern void __init xilinx_pci_init(void); +#else +static inline void __init xilinx_pci_init(void) { return; } +#endif + +#endif /* __KERNEL__ */ +#endif /* __ASM_MICROBLAZE_PCI_H */ diff --git a/arch/microblaze/include/asm/pgalloc.h b/arch/microblaze/include/asm/pgalloc.h new file mode 100644 index 000000000..7c89390c0 --- /dev/null +++ b/arch/microblaze/include/asm/pgalloc.h @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2008-2009 PetaLogix + * Copyright (C) 2006 Atmark Techno, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_MICROBLAZE_PGALLOC_H +#define _ASM_MICROBLAZE_PGALLOC_H + +#ifdef CONFIG_MMU + +#include <linux/kernel.h> /* For min/max macros */ +#include <linux/highmem.h> +#include <asm/setup.h> +#include <asm/io.h> +#include <asm/page.h> +#include <asm/cache.h> +#include <asm/pgtable.h> + +#define PGDIR_ORDER 0 + +/* + * This is handled very differently on MicroBlaze since out page tables + * are all 0's and I want to be able to use these zero'd pages elsewhere + * as well - it gives us quite a speedup. + * -- Cort + */ +extern struct pgtable_cache_struct { + unsigned long *pgd_cache; + unsigned long *pte_cache; + unsigned long pgtable_cache_sz; +} quicklists; + +#define pgd_quicklist (quicklists.pgd_cache) +#define pmd_quicklist ((unsigned long *)0) +#define pte_quicklist (quicklists.pte_cache) +#define pgtable_cache_size (quicklists.pgtable_cache_sz) + +extern unsigned long *zero_cache; /* head linked list of pre-zero'd pages */ +extern atomic_t zero_sz; /* # currently pre-zero'd pages */ +extern atomic_t zeropage_hits; /* # zero'd pages request that we've done */ +extern atomic_t zeropage_calls; /* # zero'd pages request that've been made */ +extern atomic_t zerototal; /* # pages zero'd over time */ + +#define zero_quicklist (zero_cache) +#define zero_cache_sz (zero_sz) +#define zero_cache_calls (zeropage_calls) +#define zero_cache_hits (zeropage_hits) +#define zero_cache_total (zerototal) + +/* + * return a pre-zero'd page from the list, + * return NULL if none available -- Cort + */ +extern unsigned long get_zero_page_fast(void); + +extern void __bad_pte(pmd_t *pmd); + +static inline pgd_t *get_pgd_slow(void) +{ + pgd_t *ret; + + ret = (pgd_t *)__get_free_pages(GFP_KERNEL, PGDIR_ORDER); + if (ret != NULL) + clear_page(ret); + return ret; +} + +static inline pgd_t *get_pgd_fast(void) +{ + unsigned long *ret; + + ret = pgd_quicklist; + if (ret != NULL) { + pgd_quicklist = (unsigned long *)(*ret); + ret[0] = 0; + pgtable_cache_size--; + } else + ret = (unsigned long *)get_pgd_slow(); + return (pgd_t *)ret; +} + +static inline void free_pgd_fast(pgd_t *pgd) +{ + *(unsigned long **)pgd = pgd_quicklist; + pgd_quicklist = (unsigned long *) pgd; + pgtable_cache_size++; +} + +static inline void free_pgd_slow(pgd_t *pgd) +{ + free_page((unsigned long)pgd); +} + +#define pgd_free(mm, pgd) free_pgd_fast(pgd) +#define pgd_alloc(mm) get_pgd_fast() + +#define pmd_pgtable(pmd) pmd_page(pmd) + +/* + * We don't have any real pmd's, and this code never triggers because + * the pgd will always be present.. + */ +#define pmd_alloc_one_fast(mm, address) ({ BUG(); ((pmd_t *)1); }) +#define pmd_alloc_one(mm, address) ({ BUG(); ((pmd_t *)2); }) + +extern pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr); + +static inline struct page *pte_alloc_one(struct mm_struct *mm, + unsigned long address) +{ + struct page *ptepage; + +#ifdef CONFIG_HIGHPTE + int flags = GFP_KERNEL | __GFP_HIGHMEM; +#else + int flags = GFP_KERNEL; +#endif + + ptepage = alloc_pages(flags, 0); + if (!ptepage) + return NULL; + clear_highpage(ptepage); + if (!pgtable_page_ctor(ptepage)) { + __free_page(ptepage); + return NULL; + } + return ptepage; +} + +static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, + unsigned long address) +{ + unsigned long *ret; + + ret = pte_quicklist; + if (ret != NULL) { + pte_quicklist = (unsigned long *)(*ret); + ret[0] = 0; + pgtable_cache_size--; + } + return (pte_t *)ret; +} + +static inline void pte_free_fast(pte_t *pte) +{ + *(unsigned long **)pte = pte_quicklist; + pte_quicklist = (unsigned long *) pte; + pgtable_cache_size++; +} + +static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte) +{ + free_page((unsigned long)pte); +} + +static inline void pte_free_slow(struct page *ptepage) +{ + __free_page(ptepage); +} + +static inline void pte_free(struct mm_struct *mm, struct page *ptepage) +{ + pgtable_page_dtor(ptepage); + __free_page(ptepage); +} + +#define __pte_free_tlb(tlb, pte, addr) pte_free((tlb)->mm, (pte)) + +#define pmd_populate(mm, pmd, pte) \ + (pmd_val(*(pmd)) = (unsigned long)page_address(pte)) + +#define pmd_populate_kernel(mm, pmd, pte) \ + (pmd_val(*(pmd)) = (unsigned long) (pte)) + +/* + * We don't have any real pmd's, and this code never triggers because + * 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) 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) + +#endif /* _ASM_MICROBLAZE_PGALLOC_H */ diff --git a/arch/microblaze/include/asm/pgtable.h b/arch/microblaze/include/asm/pgtable.h new file mode 100644 index 000000000..2ca598534 --- /dev/null +++ b/arch/microblaze/include/asm/pgtable.h @@ -0,0 +1,561 @@ +/* + * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2008-2009 PetaLogix + * Copyright (C) 2006 Atmark Techno, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_MICROBLAZE_PGTABLE_H +#define _ASM_MICROBLAZE_PGTABLE_H + +#include <asm/setup.h> + +#ifndef __ASSEMBLY__ +extern int mem_init_done; +#endif + +#ifndef CONFIG_MMU + +#define pgd_present(pgd) (1) /* pages are always present on non MMU */ +#define pgd_none(pgd) (0) +#define pgd_bad(pgd) (0) +#define pgd_clear(pgdp) +#define kern_addr_valid(addr) (1) +#define pmd_offset(a, b) ((void *) 0) + +#define PAGE_NONE __pgprot(0) /* these mean nothing to non MMU */ +#define PAGE_SHARED __pgprot(0) /* these mean nothing to non MMU */ +#define PAGE_COPY __pgprot(0) /* these mean nothing to non MMU */ +#define PAGE_READONLY __pgprot(0) /* these mean nothing to non MMU */ +#define PAGE_KERNEL __pgprot(0) /* these mean nothing to non MMU */ + +#define pgprot_noncached(x) (x) +#define pgprot_writecombine pgprot_noncached +#define pgprot_device pgprot_noncached + +#define __swp_type(x) (0) +#define __swp_offset(x) (0) +#define __swp_entry(typ, off) ((swp_entry_t) { ((typ) | ((off) << 7)) }) +#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) +#define __swp_entry_to_pte(x) ((pte_t) { (x).val }) + +#define ZERO_PAGE(vaddr) ({ BUG(); NULL; }) + +#define swapper_pg_dir ((pgd_t *) NULL) + +#define pgtable_cache_init() do {} while (0) + +#define arch_enter_lazy_cpu_mode() do {} while (0) + +#define pgprot_noncached_wc(prot) prot + +/* + * All 32bit addresses are effectively valid for vmalloc... + * Sort of meaningless for non-VM targets. + */ +#define VMALLOC_START 0 +#define VMALLOC_END 0xffffffff + +#else /* CONFIG_MMU */ + +#include <asm-generic/4level-fixup.h> + +#define __PAGETABLE_PMD_FOLDED 1 + +#ifdef __KERNEL__ +#ifndef __ASSEMBLY__ + +#include <linux/sched.h> +#include <linux/threads.h> +#include <asm/processor.h> /* For TASK_SIZE */ +#include <asm/mmu.h> +#include <asm/page.h> + +#define FIRST_USER_ADDRESS 0UL + +extern unsigned long va_to_phys(unsigned long address); +extern pte_t *va_to_pte(unsigned long address); + +/* + * The following only work if pte_present() is true. + * Undefined behaviour if not.. + */ + +static inline int pte_special(pte_t pte) { return 0; } + +static inline pte_t pte_mkspecial(pte_t pte) { return pte; } + +/* Start and end of the vmalloc area. */ +/* Make sure to map the vmalloc area above the pinned kernel memory area + of 32Mb. */ +#define VMALLOC_START (CONFIG_KERNEL_START + CONFIG_LOWMEM_SIZE) +#define VMALLOC_END ioremap_bot + +#endif /* __ASSEMBLY__ */ + +/* + * Macro to mark a page protection value as "uncacheable". + */ + +#define _PAGE_CACHE_CTL (_PAGE_GUARDED | _PAGE_NO_CACHE | \ + _PAGE_WRITETHRU) + +#define pgprot_noncached(prot) \ + (__pgprot((pgprot_val(prot) & ~_PAGE_CACHE_CTL) | \ + _PAGE_NO_CACHE | _PAGE_GUARDED)) + +#define pgprot_noncached_wc(prot) \ + (__pgprot((pgprot_val(prot) & ~_PAGE_CACHE_CTL) | \ + _PAGE_NO_CACHE)) + +/* + * The MicroBlaze MMU is identical to the PPC-40x MMU, and uses a hash + * table containing PTEs, together with a set of 16 segment registers, to + * define the virtual to physical address mapping. + * + * We use the hash table as an extended TLB, i.e. a cache of currently + * active mappings. We maintain a two-level page table tree, much + * like that used by the i386, for the sake of the Linux memory + * management code. Low-level assembler code in hashtable.S + * (procedure hash_page) is responsible for extracting ptes from the + * tree and putting them into the hash table when necessary, and + * updating the accessed and modified bits in the page table tree. + */ + +/* + * The MicroBlaze processor has a TLB architecture identical to PPC-40x. The + * instruction and data sides share a unified, 64-entry, semi-associative + * TLB which is maintained totally under software control. In addition, the + * instruction side has a hardware-managed, 2,4, or 8-entry, fully-associative + * TLB which serves as a first level to the shared TLB. These two TLBs are + * known as the UTLB and ITLB, respectively (see "mmu.h" for definitions). + */ + +/* + * The normal case is that PTEs are 32-bits and we have a 1-page + * 1024-entry pgdir pointing to 1-page 1024-entry PTE pages. -- paulus + * + */ + +/* PMD_SHIFT determines the size of the area mapped by the PTE pages */ +#define PMD_SHIFT (PAGE_SHIFT + PTE_SHIFT) +#define PMD_SIZE (1UL << PMD_SHIFT) +#define PMD_MASK (~(PMD_SIZE-1)) + +/* PGDIR_SHIFT determines what a top-level page table entry can map */ +#define PGDIR_SHIFT PMD_SHIFT +#define PGDIR_SIZE (1UL << PGDIR_SHIFT) +#define PGDIR_MASK (~(PGDIR_SIZE-1)) + +/* + * entries per page directory level: our page-table tree is two-level, so + * we don't really have any PMD directory. + */ +#define PTRS_PER_PTE (1 << PTE_SHIFT) +#define PTRS_PER_PMD 1 +#define PTRS_PER_PGD (1 << (32 - PGDIR_SHIFT)) + +#define USER_PTRS_PER_PGD (TASK_SIZE / PGDIR_SIZE) +#define FIRST_USER_PGD_NR 0 + +#define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT) +#define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS) + +#define pte_ERROR(e) \ + printk(KERN_ERR "%s:%d: bad pte "PTE_FMT".\n", \ + __FILE__, __LINE__, pte_val(e)) +#define pmd_ERROR(e) \ + printk(KERN_ERR "%s:%d: bad pmd %08lx.\n", \ + __FILE__, __LINE__, pmd_val(e)) +#define pgd_ERROR(e) \ + printk(KERN_ERR "%s:%d: bad pgd %08lx.\n", \ + __FILE__, __LINE__, pgd_val(e)) + +/* + * Bits in a linux-style PTE. These match the bits in the + * (hardware-defined) PTE as closely as possible. + */ + +/* There are several potential gotchas here. The hardware TLBLO + * field looks like this: + * + * 0 1 2 3 4 ... 18 19 20 21 22 23 24 25 26 27 28 29 30 31 + * RPN..................... 0 0 EX WR ZSEL....... W I M G + * + * Where possible we make the Linux PTE bits match up with this + * + * - bits 20 and 21 must be cleared, because we use 4k pages (4xx can + * support down to 1k pages), this is done in the TLBMiss exception + * handler. + * - We use only zones 0 (for kernel pages) and 1 (for user pages) + * of the 16 available. Bit 24-26 of the TLB are cleared in the TLB + * miss handler. Bit 27 is PAGE_USER, thus selecting the correct + * zone. + * - PRESENT *must* be in the bottom two bits because swap cache + * entries use the top 30 bits. Because 4xx doesn't support SMP + * anyway, M is irrelevant so we borrow it for PAGE_PRESENT. Bit 30 + * is cleared in the TLB miss handler before the TLB entry is loaded. + * - All other bits of the PTE are loaded into TLBLO without + * * modification, leaving us only the bits 20, 21, 24, 25, 26, 30 for + * software PTE bits. We actually use use bits 21, 24, 25, and + * 30 respectively for the software bits: ACCESSED, DIRTY, RW, and + * PRESENT. + */ + +/* Definitions for MicroBlaze. */ +#define _PAGE_GUARDED 0x001 /* G: page is guarded from prefetch */ +#define _PAGE_PRESENT 0x002 /* software: PTE contains a translation */ +#define _PAGE_NO_CACHE 0x004 /* I: caching is inhibited */ +#define _PAGE_WRITETHRU 0x008 /* W: caching is write-through */ +#define _PAGE_USER 0x010 /* matches one of the zone permission bits */ +#define _PAGE_RW 0x040 /* software: Writes permitted */ +#define _PAGE_DIRTY 0x080 /* software: dirty page */ +#define _PAGE_HWWRITE 0x100 /* hardware: Dirty & RW, set in exception */ +#define _PAGE_HWEXEC 0x200 /* hardware: EX permission */ +#define _PAGE_ACCESSED 0x400 /* software: R: page referenced */ +#define _PMD_PRESENT PAGE_MASK + +/* + * Some bits are unused... + */ +#ifndef _PAGE_HASHPTE +#define _PAGE_HASHPTE 0 +#endif +#ifndef _PTE_NONE_MASK +#define _PTE_NONE_MASK 0 +#endif +#ifndef _PAGE_SHARED +#define _PAGE_SHARED 0 +#endif +#ifndef _PAGE_EXEC +#define _PAGE_EXEC 0 +#endif + +#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY) + +/* + * Note: the _PAGE_COHERENT bit automatically gets set in the hardware + * PTE if CONFIG_SMP is defined (hash_page does this); there is no need + * to have it in the Linux PTE, and in fact the bit could be reused for + * another purpose. -- paulus. + */ +#define _PAGE_BASE (_PAGE_PRESENT | _PAGE_ACCESSED) +#define _PAGE_WRENABLE (_PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE) + +#define _PAGE_KERNEL \ + (_PAGE_BASE | _PAGE_WRENABLE | _PAGE_SHARED | _PAGE_HWEXEC) + +#define _PAGE_IO (_PAGE_KERNEL | _PAGE_NO_CACHE | _PAGE_GUARDED) + +#define PAGE_NONE __pgprot(_PAGE_BASE) +#define PAGE_READONLY __pgprot(_PAGE_BASE | _PAGE_USER) +#define PAGE_READONLY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC) +#define PAGE_SHARED __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW) +#define PAGE_SHARED_X \ + __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW | _PAGE_EXEC) +#define PAGE_COPY __pgprot(_PAGE_BASE | _PAGE_USER) +#define PAGE_COPY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC) + +#define PAGE_KERNEL __pgprot(_PAGE_KERNEL) +#define PAGE_KERNEL_RO __pgprot(_PAGE_BASE | _PAGE_SHARED) +#define PAGE_KERNEL_CI __pgprot(_PAGE_IO) + +/* + * We consider execute permission the same as read. + * Also, write permissions imply read permissions. + */ +#define __P000 PAGE_NONE +#define __P001 PAGE_READONLY_X +#define __P010 PAGE_COPY +#define __P011 PAGE_COPY_X +#define __P100 PAGE_READONLY +#define __P101 PAGE_READONLY_X +#define __P110 PAGE_COPY +#define __P111 PAGE_COPY_X + +#define __S000 PAGE_NONE +#define __S001 PAGE_READONLY_X +#define __S010 PAGE_SHARED +#define __S011 PAGE_SHARED_X +#define __S100 PAGE_READONLY +#define __S101 PAGE_READONLY_X +#define __S110 PAGE_SHARED +#define __S111 PAGE_SHARED_X + +#ifndef __ASSEMBLY__ +/* + * ZERO_PAGE is a global shared page that is always zero: used + * for zero-mapped memory areas etc.. + */ +extern unsigned long empty_zero_page[1024]; +#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) + +#endif /* __ASSEMBLY__ */ + +#define pte_none(pte) ((pte_val(pte) & ~_PTE_NONE_MASK) == 0) +#define pte_present(pte) (pte_val(pte) & _PAGE_PRESENT) +#define pte_clear(mm, addr, ptep) \ + do { set_pte_at((mm), (addr), (ptep), __pte(0)); } while (0) + +#define pmd_none(pmd) (!pmd_val(pmd)) +#define pmd_bad(pmd) ((pmd_val(pmd) & _PMD_PRESENT) == 0) +#define pmd_present(pmd) ((pmd_val(pmd) & _PMD_PRESENT) != 0) +#define pmd_clear(pmdp) do { pmd_val(*(pmdp)) = 0; } while (0) + +#define pte_page(x) (mem_map + (unsigned long) \ + ((pte_val(x) - memory_start) >> PAGE_SHIFT)) +#define PFN_SHIFT_OFFSET (PAGE_SHIFT) + +#define pte_pfn(x) (pte_val(x) >> PFN_SHIFT_OFFSET) + +#define pfn_pte(pfn, prot) \ + __pte(((pte_basic_t)(pfn) << PFN_SHIFT_OFFSET) | pgprot_val(prot)) + +#ifndef __ASSEMBLY__ +/* + * The "pgd_xxx()" functions here are trivial for a folded two-level + * setup: the pgd is never bad, and a pmd always exists (as it's folded + * into the pgd entry) + */ +static inline int pgd_none(pgd_t pgd) { return 0; } +static inline int pgd_bad(pgd_t pgd) { return 0; } +static inline int pgd_present(pgd_t pgd) { return 1; } +#define pgd_clear(xp) do { } while (0) +#define pgd_page(pgd) \ + ((unsigned long) __va(pgd_val(pgd) & PAGE_MASK)) + +/* + * The following only work if pte_present() is true. + * Undefined behaviour if not.. + */ +static inline int pte_read(pte_t pte) { return pte_val(pte) & _PAGE_USER; } +static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW; } +static inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_EXEC; } +static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; } +static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } + +static inline void pte_uncache(pte_t pte) { pte_val(pte) |= _PAGE_NO_CACHE; } +static inline void pte_cache(pte_t pte) { pte_val(pte) &= ~_PAGE_NO_CACHE; } + +static inline pte_t pte_rdprotect(pte_t pte) \ + { pte_val(pte) &= ~_PAGE_USER; return pte; } +static inline pte_t pte_wrprotect(pte_t pte) \ + { pte_val(pte) &= ~(_PAGE_RW | _PAGE_HWWRITE); return pte; } +static inline pte_t pte_exprotect(pte_t pte) \ + { pte_val(pte) &= ~_PAGE_EXEC; return pte; } +static inline pte_t pte_mkclean(pte_t pte) \ + { pte_val(pte) &= ~(_PAGE_DIRTY | _PAGE_HWWRITE); return pte; } +static inline pte_t pte_mkold(pte_t pte) \ + { pte_val(pte) &= ~_PAGE_ACCESSED; return pte; } + +static inline pte_t pte_mkread(pte_t pte) \ + { pte_val(pte) |= _PAGE_USER; return pte; } +static inline pte_t pte_mkexec(pte_t pte) \ + { pte_val(pte) |= _PAGE_USER | _PAGE_EXEC; return pte; } +static inline pte_t pte_mkwrite(pte_t pte) \ + { pte_val(pte) |= _PAGE_RW; return pte; } +static inline pte_t pte_mkdirty(pte_t pte) \ + { pte_val(pte) |= _PAGE_DIRTY; return pte; } +static inline pte_t pte_mkyoung(pte_t pte) \ + { pte_val(pte) |= _PAGE_ACCESSED; return pte; } + +/* + * Conversion functions: convert a page and protection to a page entry, + * and a page entry and page directory to the page they refer to. + */ + +static inline pte_t mk_pte_phys(phys_addr_t physpage, pgprot_t pgprot) +{ + pte_t pte; + pte_val(pte) = physpage | pgprot_val(pgprot); + return pte; +} + +#define mk_pte(page, pgprot) \ +({ \ + pte_t pte; \ + pte_val(pte) = (((page - mem_map) << PAGE_SHIFT) + memory_start) | \ + pgprot_val(pgprot); \ + pte; \ +}) + +static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) +{ + pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); + return pte; +} + +/* + * Atomic PTE updates. + * + * pte_update clears and sets bit atomically, and returns + * the old pte value. + * The ((unsigned long)(p+1) - 4) hack is to get to the least-significant + * 32 bits of the PTE regardless of whether PTEs are 32 or 64 bits. + */ +static inline unsigned long pte_update(pte_t *p, unsigned long clr, + unsigned long set) +{ + unsigned long flags, old, tmp; + + raw_local_irq_save(flags); + + __asm__ __volatile__( "lw %0, %2, r0 \n" + "andn %1, %0, %3 \n" + "or %1, %1, %4 \n" + "sw %1, %2, r0 \n" + : "=&r" (old), "=&r" (tmp) + : "r" ((unsigned long)(p + 1) - 4), "r" (clr), "r" (set) + : "cc"); + + raw_local_irq_restore(flags); + + return old; +} + +/* + * set_pte stores a linux PTE into the linux page table. + */ +static inline void set_pte(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, pte_t pte) +{ + *ptep = pte; +} + +static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, pte_t pte) +{ + *ptep = pte; +} + +#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG +static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, + unsigned long address, pte_t *ptep) +{ + return (pte_update(ptep, _PAGE_ACCESSED, 0) & _PAGE_ACCESSED) != 0; +} + +static inline int ptep_test_and_clear_dirty(struct mm_struct *mm, + unsigned long addr, pte_t *ptep) +{ + return (pte_update(ptep, \ + (_PAGE_DIRTY | _PAGE_HWWRITE), 0) & _PAGE_DIRTY) != 0; +} + +#define __HAVE_ARCH_PTEP_GET_AND_CLEAR +static inline pte_t ptep_get_and_clear(struct mm_struct *mm, + unsigned long addr, pte_t *ptep) +{ + return __pte(pte_update(ptep, ~_PAGE_HASHPTE, 0)); +} + +/*static inline void ptep_set_wrprotect(struct mm_struct *mm, + unsigned long addr, pte_t *ptep) +{ + pte_update(ptep, (_PAGE_RW | _PAGE_HWWRITE), 0); +}*/ + +static inline void ptep_mkdirty(struct mm_struct *mm, + unsigned long addr, pte_t *ptep) +{ + pte_update(ptep, 0, _PAGE_DIRTY); +} + +/*#define pte_same(A,B) (((pte_val(A) ^ pte_val(B)) & ~_PAGE_HASHPTE) == 0)*/ + +/* Convert pmd entry to page */ +/* our pmd entry is an effective address of pte table*/ +/* returns effective address of the pmd entry*/ +#define pmd_page_kernel(pmd) ((unsigned long) (pmd_val(pmd) & PAGE_MASK)) + +/* returns struct *page of the pmd entry*/ +#define pmd_page(pmd) (pfn_to_page(__pa(pmd_val(pmd)) >> PAGE_SHIFT)) + +/* to find an entry in a kernel page-table-directory */ +#define pgd_offset_k(address) pgd_offset(&init_mm, address) + +/* to find an entry in a page-table-directory */ +#define pgd_index(address) ((address) >> PGDIR_SHIFT) +#define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address)) + +/* Find an entry in the second-level page table.. */ +static inline pmd_t *pmd_offset(pgd_t *dir, unsigned long address) +{ + return (pmd_t *) dir; +} + +/* Find an entry in the third-level page table.. */ +#define pte_index(address) \ + (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) +#define pte_offset_kernel(dir, addr) \ + ((pte_t *) pmd_page_kernel(*(dir)) + pte_index(addr)) +#define pte_offset_map(dir, addr) \ + ((pte_t *) kmap_atomic(pmd_page(*(dir))) + pte_index(addr)) + +#define pte_unmap(pte) kunmap_atomic(pte) + +extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; + +/* + * Encode and decode a swap entry. + * Note that the bits we use in a PTE for representing a swap entry + * must not include the _PAGE_PRESENT bit, or the _PAGE_HASHPTE bit + * (if used). -- paulus + */ +#define __swp_type(entry) ((entry).val & 0x3f) +#define __swp_offset(entry) ((entry).val >> 6) +#define __swp_entry(type, offset) \ + ((swp_entry_t) { (type) | ((offset) << 6) }) +#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) >> 2 }) +#define __swp_entry_to_pte(x) ((pte_t) { (x).val << 2 }) + +extern unsigned long iopa(unsigned long addr); + +/* Values for nocacheflag and cmode */ +/* These are not used by the APUS kernel_map, but prevents + * compilation errors. + */ +#define IOMAP_FULL_CACHING 0 +#define IOMAP_NOCACHE_SER 1 +#define IOMAP_NOCACHE_NONSER 2 +#define IOMAP_NO_COPYBACK 3 + +/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */ +#define kern_addr_valid(addr) (1) + +/* + * No page table caches to initialise + */ +#define pgtable_cache_init() do { } while (0) + +void do_page_fault(struct pt_regs *regs, unsigned long address, + unsigned long error_code); + +void mapin_ram(void); +int map_page(unsigned long va, phys_addr_t pa, int flags); + +extern int mem_init_done; + +asmlinkage void __init mmu_init(void); + +void __init *early_get_page(void); + +#endif /* __ASSEMBLY__ */ +#endif /* __KERNEL__ */ + +#endif /* CONFIG_MMU */ + +#ifndef __ASSEMBLY__ +#include <asm-generic/pgtable.h> + +extern unsigned long ioremap_bot, ioremap_base; + +unsigned long consistent_virt_to_pfn(void *vaddr); + +void setup_memory(void); +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_MICROBLAZE_PGTABLE_H */ diff --git a/arch/microblaze/include/asm/processor.h b/arch/microblaze/include/asm/processor.h new file mode 100644 index 000000000..330d55686 --- /dev/null +++ b/arch/microblaze/include/asm/processor.h @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2008-2009 PetaLogix + * Copyright (C) 2006 Atmark Techno, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_MICROBLAZE_PROCESSOR_H +#define _ASM_MICROBLAZE_PROCESSOR_H + +#include <asm/ptrace.h> +#include <asm/setup.h> +#include <asm/registers.h> +#include <asm/entry.h> +#include <asm/current.h> + +# ifndef __ASSEMBLY__ +/* from kernel/cpu/mb.c */ +extern const struct seq_operations cpuinfo_op; + +# define cpu_relax() barrier() + +#define task_pt_regs(tsk) \ + (((struct pt_regs *)(THREAD_SIZE + task_stack_page(tsk))) - 1) + +/* Do necessary setup to start up a newly executed thread. */ +void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long usp); + +extern void ret_from_fork(void); +extern void ret_from_kernel_thread(void); + +# endif /* __ASSEMBLY__ */ + +# ifndef CONFIG_MMU +/* + * User space process size: memory size + * + * TASK_SIZE on MMU cpu is usually 1GB. However, on no-MMU arch, both + * user processes and the kernel is on the same memory region. They + * both share the memory space and that is limited by the amount of + * physical memory. thus, we set TASK_SIZE == amount of total memory. + */ +# define TASK_SIZE (0x81000000 - 0x80000000) + +/* + * Default implementation of macro that returns current + * instruction pointer ("program counter"). + */ +# define current_text_addr() ({ __label__ _l; _l: &&_l; }) + +/* + * This decides where the kernel will search for a free chunk of vm + * space during mmap's. We won't be using it + */ +# define TASK_UNMAPPED_BASE 0 + +/* definition in include/linux/sched.h */ +struct task_struct; + +/* thread_struct is gone. use thread_info instead. */ +struct thread_struct { }; +# define INIT_THREAD { } + +/* Free all resources held by a thread. */ +static inline void release_thread(struct task_struct *dead_task) +{ +} + +extern unsigned long get_wchan(struct task_struct *p); + +# define KSTK_EIP(tsk) (0) +# define KSTK_ESP(tsk) (0) + +# else /* CONFIG_MMU */ + +/* + * This is used to define STACK_TOP, and with MMU it must be below + * kernel base to select the correct PGD when handling MMU exceptions. + */ +# define TASK_SIZE (CONFIG_KERNEL_START) + +/* + * This decides where the kernel will search for a free chunk of vm + * space during mmap's. + */ +# define TASK_UNMAPPED_BASE (TASK_SIZE / 8 * 3) + +# define THREAD_KSP 0 + +# ifndef __ASSEMBLY__ + +/* + * Default implementation of macro that returns current + * instruction pointer ("program counter"). + */ +# define current_text_addr() ({ __label__ _l; _l: &&_l; }) + +/* If you change this, you must change the associated assembly-languages + * constants defined below, THREAD_*. + */ +struct thread_struct { + /* kernel stack pointer (must be first field in structure) */ + unsigned long ksp; + unsigned long ksp_limit; /* if ksp <= ksp_limit stack overflow */ + void *pgdir; /* root of page-table tree */ + struct pt_regs *regs; /* Pointer to saved register state */ +}; + +# define INIT_THREAD { \ + .ksp = sizeof init_stack + (unsigned long)init_stack, \ + .pgdir = swapper_pg_dir, \ +} + +/* Free all resources held by a thread. */ +static inline void release_thread(struct task_struct *dead_task) +{ +} + +unsigned long get_wchan(struct task_struct *p); + +/* The size allocated for kernel stacks. This _must_ be a power of two! */ +# define KERNEL_STACK_SIZE 0x2000 + +/* Return some info about the user process TASK. */ +# define task_tos(task) ((unsigned long)(task) + KERNEL_STACK_SIZE) +# define task_regs(task) ((struct pt_regs *)task_tos(task) - 1) + +# define task_pt_regs_plus_args(tsk) \ + ((void *)task_pt_regs(tsk)) + +# define task_sp(task) (task_regs(task)->r1) +# define task_pc(task) (task_regs(task)->pc) +/* Grotty old names for some. */ +# define KSTK_EIP(task) (task_pc(task)) +# define KSTK_ESP(task) (task_sp(task)) + +/* FIXME */ +# define deactivate_mm(tsk, mm) do { } while (0) + +# define STACK_TOP TASK_SIZE +# define STACK_TOP_MAX STACK_TOP + +#ifdef CONFIG_DEBUG_FS +extern struct dentry *of_debugfs_root; +#endif + +# endif /* __ASSEMBLY__ */ +# endif /* CONFIG_MMU */ +#endif /* _ASM_MICROBLAZE_PROCESSOR_H */ diff --git a/arch/microblaze/include/asm/ptrace.h b/arch/microblaze/include/asm/ptrace.h new file mode 100644 index 000000000..5b18ec124 --- /dev/null +++ b/arch/microblaze/include/asm/ptrace.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2006 Atmark Techno, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#ifndef _ASM_MICROBLAZE_PTRACE_H +#define _ASM_MICROBLAZE_PTRACE_H + +#include <uapi/asm/ptrace.h> + +#ifndef __ASSEMBLY__ +#define kernel_mode(regs) ((regs)->pt_mode) +#define user_mode(regs) (!kernel_mode(regs)) + +#define instruction_pointer(regs) ((regs)->pc) +#define profile_pc(regs) instruction_pointer(regs) +#define user_stack_pointer(regs) ((regs)->r1) + +static inline long regs_return_value(struct pt_regs *regs) +{ + return regs->r3; +} + +#endif /* __ASSEMBLY__ */ +#endif /* _ASM_MICROBLAZE_PTRACE_H */ diff --git a/arch/microblaze/include/asm/pvr.h b/arch/microblaze/include/asm/pvr.h new file mode 100644 index 000000000..4bbdb4c03 --- /dev/null +++ b/arch/microblaze/include/asm/pvr.h @@ -0,0 +1,227 @@ +/* + * Support for the MicroBlaze PVR (Processor Version Register) + * + * Copyright (C) 2009 - 2011 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2007 John Williams <john.williams@petalogix.com> + * Copyright (C) 2007 - 2011 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. + */ + +#ifndef _ASM_MICROBLAZE_PVR_H +#define _ASM_MICROBLAZE_PVR_H + +#define PVR_MSR_BIT 0x400 + +struct pvr_s { + unsigned pvr[12]; +}; + +/* The following taken from Xilinx's standalone BSP pvr.h */ + +/* Basic PVR mask */ +#define PVR0_PVR_FULL_MASK 0x80000000 +#define PVR0_USE_BARREL_MASK 0x40000000 +#define PVR0_USE_DIV_MASK 0x20000000 +#define PVR0_USE_HW_MUL_MASK 0x10000000 +#define PVR0_USE_FPU_MASK 0x08000000 +#define PVR0_USE_EXC_MASK 0x04000000 +#define PVR0_USE_ICACHE_MASK 0x02000000 +#define PVR0_USE_DCACHE_MASK 0x01000000 +#define PVR0_USE_MMU 0x00800000 +#define PVR0_USE_BTC 0x00400000 +#define PVR0_ENDI 0x00200000 +#define PVR0_VERSION_MASK 0x0000FF00 +#define PVR0_USER1_MASK 0x000000FF + +/* User 2 PVR mask */ +#define PVR1_USER2_MASK 0xFFFFFFFF + +/* Configuration PVR masks */ +#define PVR2_D_OPB_MASK 0x80000000 /* or AXI */ +#define PVR2_D_LMB_MASK 0x40000000 +#define PVR2_I_OPB_MASK 0x20000000 /* or AXI */ +#define PVR2_I_LMB_MASK 0x10000000 +#define PVR2_INTERRUPT_IS_EDGE_MASK 0x08000000 +#define PVR2_EDGE_IS_POSITIVE_MASK 0x04000000 +#define PVR2_D_PLB_MASK 0x02000000 /* new */ +#define PVR2_I_PLB_MASK 0x01000000 /* new */ +#define PVR2_INTERCONNECT 0x00800000 /* new */ +#define PVR2_USE_EXTEND_FSL 0x00080000 /* new */ +#define PVR2_USE_FSL_EXC 0x00040000 /* new */ +#define PVR2_USE_MSR_INSTR 0x00020000 +#define PVR2_USE_PCMP_INSTR 0x00010000 +#define PVR2_AREA_OPTIMISED 0x00008000 +#define PVR2_USE_BARREL_MASK 0x00004000 +#define PVR2_USE_DIV_MASK 0x00002000 +#define PVR2_USE_HW_MUL_MASK 0x00001000 +#define PVR2_USE_FPU_MASK 0x00000800 +#define PVR2_USE_MUL64_MASK 0x00000400 +#define PVR2_USE_FPU2_MASK 0x00000200 /* new */ +#define PVR2_USE_IPLBEXC 0x00000100 +#define PVR2_USE_DPLBEXC 0x00000080 +#define PVR2_OPCODE_0x0_ILL_MASK 0x00000040 +#define PVR2_UNALIGNED_EXC_MASK 0x00000020 +#define PVR2_ILL_OPCODE_EXC_MASK 0x00000010 +#define PVR2_IOPB_BUS_EXC_MASK 0x00000008 /* or AXI */ +#define PVR2_DOPB_BUS_EXC_MASK 0x00000004 /* or AXI */ +#define PVR2_DIV_ZERO_EXC_MASK 0x00000002 +#define PVR2_FPU_EXC_MASK 0x00000001 + +/* Debug and exception PVR masks */ +#define PVR3_DEBUG_ENABLED_MASK 0x80000000 +#define PVR3_NUMBER_OF_PC_BRK_MASK 0x1E000000 +#define PVR3_NUMBER_OF_RD_ADDR_BRK_MASK 0x00380000 +#define PVR3_NUMBER_OF_WR_ADDR_BRK_MASK 0x0000E000 +#define PVR3_FSL_LINKS_MASK 0x00000380 + +/* ICache config PVR masks */ +#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 /* 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 + +/* ICache high address PVR mask */ +#define PVR7_ICACHE_HIGHADDR_MASK 0xFFFFFFFF + +/* DCache base address PVR mask */ +#define PVR8_DCACHE_BASEADDR_MASK 0xFFFFFFFF + +/* DCache high address PVR mask */ +#define PVR9_DCACHE_HIGHADDR_MASK 0xFFFFFFFF + +/* Target family PVR mask */ +#define PVR10_TARGET_FAMILY_MASK 0xFF000000 + +/* MMU description */ +#define PVR11_USE_MMU 0xC0000000 +#define PVR11_MMU_ITLB_SIZE 0x38000000 +#define PVR11_MMU_DTLB_SIZE 0x07000000 +#define PVR11_MMU_TLB_ACCESS 0x00C00000 +#define PVR11_MMU_ZONES 0x003C0000 +#define PVR11_MMU_PRIVINS 0x00010000 +/* MSR Reset value PVR mask */ +#define PVR11_MSR_RESET_VALUE_MASK 0x000007FF + +/* PVR access macros */ +#define PVR_IS_FULL(_pvr) (_pvr.pvr[0] & PVR0_PVR_FULL_MASK) +#define PVR_USE_BARREL(_pvr) (_pvr.pvr[0] & PVR0_USE_BARREL_MASK) +#define PVR_USE_DIV(_pvr) (_pvr.pvr[0] & PVR0_USE_DIV_MASK) +#define PVR_USE_HW_MUL(_pvr) (_pvr.pvr[0] & PVR0_USE_HW_MUL_MASK) +#define PVR_USE_FPU(_pvr) (_pvr.pvr[0] & PVR0_USE_FPU_MASK) +#define PVR_USE_FPU2(_pvr) (_pvr.pvr[2] & PVR2_USE_FPU2_MASK) +#define PVR_USE_ICACHE(_pvr) (_pvr.pvr[0] & PVR0_USE_ICACHE_MASK) +#define PVR_USE_DCACHE(_pvr) (_pvr.pvr[0] & PVR0_USE_DCACHE_MASK) +#define PVR_VERSION(_pvr) ((_pvr.pvr[0] & PVR0_VERSION_MASK) >> 8) +#define PVR_USER1(_pvr) (_pvr.pvr[0] & PVR0_USER1_MASK) +#define PVR_USER2(_pvr) (_pvr.pvr[1] & PVR1_USER2_MASK) + +#define PVR_D_OPB(_pvr) (_pvr.pvr[2] & PVR2_D_OPB_MASK) +#define PVR_D_LMB(_pvr) (_pvr.pvr[2] & PVR2_D_LMB_MASK) +#define PVR_I_OPB(_pvr) (_pvr.pvr[2] & PVR2_I_OPB_MASK) +#define PVR_I_LMB(_pvr) (_pvr.pvr[2] & PVR2_I_LMB_MASK) +#define PVR_INTERRUPT_IS_EDGE(_pvr) \ + (_pvr.pvr[2] & PVR2_INTERRUPT_IS_EDGE_MASK) +#define PVR_EDGE_IS_POSITIVE(_pvr) \ + (_pvr.pvr[2] & PVR2_EDGE_IS_POSITIVE_MASK) +#define PVR_USE_MSR_INSTR(_pvr) (_pvr.pvr[2] & PVR2_USE_MSR_INSTR) +#define PVR_USE_PCMP_INSTR(_pvr) (_pvr.pvr[2] & PVR2_USE_PCMP_INSTR) +#define PVR_AREA_OPTIMISED(_pvr) (_pvr.pvr[2] & PVR2_AREA_OPTIMISED) +#define PVR_USE_MUL64(_pvr) (_pvr.pvr[2] & PVR2_USE_MUL64_MASK) +#define PVR_OPCODE_0x0_ILLEGAL(_pvr) \ + (_pvr.pvr[2] & PVR2_OPCODE_0x0_ILL_MASK) +#define PVR_UNALIGNED_EXCEPTION(_pvr) \ + (_pvr.pvr[2] & PVR2_UNALIGNED_EXC_MASK) +#define PVR_ILL_OPCODE_EXCEPTION(_pvr) \ + (_pvr.pvr[2] & PVR2_ILL_OPCODE_EXC_MASK) +#define PVR_IOPB_BUS_EXCEPTION(_pvr) \ + (_pvr.pvr[2] & PVR2_IOPB_BUS_EXC_MASK) +#define PVR_DOPB_BUS_EXCEPTION(_pvr) \ + (_pvr.pvr[2] & PVR2_DOPB_BUS_EXC_MASK) +#define PVR_DIV_ZERO_EXCEPTION(_pvr) \ + (_pvr.pvr[2] & PVR2_DIV_ZERO_EXC_MASK) +#define PVR_FPU_EXCEPTION(_pvr) (_pvr.pvr[2] & PVR2_FPU_EXC_MASK) +#define PVR_FSL_EXCEPTION(_pvr) (_pvr.pvr[2] & PVR2_USE_EXTEND_FSL) + +#define PVR_DEBUG_ENABLED(_pvr) (_pvr.pvr[3] & PVR3_DEBUG_ENABLED_MASK) +#define PVR_NUMBER_OF_PC_BRK(_pvr) \ + ((_pvr.pvr[3] & PVR3_NUMBER_OF_PC_BRK_MASK) >> 25) +#define PVR_NUMBER_OF_RD_ADDR_BRK(_pvr) \ + ((_pvr.pvr[3] & PVR3_NUMBER_OF_RD_ADDR_BRK_MASK) >> 19) +#define PVR_NUMBER_OF_WR_ADDR_BRK(_pvr) \ + ((_pvr.pvr[3] & PVR3_NUMBER_OF_WR_ADDR_BRK_MASK) >> 13) +#define PVR_FSL_LINKS(_pvr) ((_pvr.pvr[3] & PVR3_FSL_LINKS_MASK) >> 7) + +#define PVR_ICACHE_ADDR_TAG_BITS(_pvr) \ + ((_pvr.pvr[4] & PVR4_ICACHE_ADDR_TAG_BITS_MASK) >> 26) +#define PVR_ICACHE_USE_FSL(_pvr) \ + (_pvr.pvr[4] & PVR4_ICACHE_USE_FSL_MASK) +#define PVR_ICACHE_ALLOW_WR(_pvr) \ + (_pvr.pvr[4] & PVR4_ICACHE_ALLOW_WR_MASK) +#define PVR_ICACHE_LINE_LEN(_pvr) \ + (1 << ((_pvr.pvr[4] & PVR4_ICACHE_LINE_LEN_MASK) >> 21)) +#define PVR_ICACHE_BYTE_SIZE(_pvr) \ + (1 << ((_pvr.pvr[4] & PVR4_ICACHE_BYTE_SIZE_MASK) >> 16)) + +#define PVR_DCACHE_ADDR_TAG_BITS(_pvr) \ + ((_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) +#define PVR_DCACHE_BASEADDR(_pvr) \ + (_pvr.pvr[8] & PVR8_DCACHE_BASEADDR_MASK) +#define PVR_DCACHE_HIGHADDR(_pvr) \ + (_pvr.pvr[9] & PVR9_DCACHE_HIGHADDR_MASK) + +#define PVR_TARGET_FAMILY(_pvr) \ + ((_pvr.pvr[10] & PVR10_TARGET_FAMILY_MASK) >> 24) + +#define PVR_MSR_RESET_VALUE(_pvr) \ + (_pvr.pvr[11] & PVR11_MSR_RESET_VALUE_MASK) + +/* mmu */ +#define PVR_USE_MMU(_pvr) ((_pvr.pvr[11] & PVR11_USE_MMU) >> 30) +#define PVR_MMU_ITLB_SIZE(_pvr) (_pvr.pvr[11] & PVR11_MMU_ITLB_SIZE) +#define PVR_MMU_DTLB_SIZE(_pvr) (_pvr.pvr[11] & PVR11_MMU_DTLB_SIZE) +#define PVR_MMU_TLB_ACCESS(_pvr) (_pvr.pvr[11] & PVR11_MMU_TLB_ACCESS) +#define PVR_MMU_ZONES(_pvr) (_pvr.pvr[11] & PVR11_MMU_ZONES) +#define PVR_MMU_PRIVINS(pvr) (pvr.pvr[11] & PVR11_MMU_PRIVINS) + +/* endian */ +#define PVR_ENDIAN(_pvr) (_pvr.pvr[0] & PVR0_ENDI) + +int cpu_has_pvr(void); +void get_pvr(struct pvr_s *pvr); + +#endif /* _ASM_MICROBLAZE_PVR_H */ diff --git a/arch/microblaze/include/asm/registers.h b/arch/microblaze/include/asm/registers.h new file mode 100644 index 000000000..68c3afb73 --- /dev/null +++ b/arch/microblaze/include/asm/registers.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2008-2009 PetaLogix + * Copyright (C) 2006 Atmark Techno, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_MICROBLAZE_REGISTERS_H +#define _ASM_MICROBLAZE_REGISTERS_H + +#define MSR_BE (1<<0) /* 0x001 */ +#define MSR_IE (1<<1) /* 0x002 */ +#define MSR_C (1<<2) /* 0x004 */ +#define MSR_BIP (1<<3) /* 0x008 */ +#define MSR_FSL (1<<4) /* 0x010 */ +#define MSR_ICE (1<<5) /* 0x020 */ +#define MSR_DZ (1<<6) /* 0x040 */ +#define MSR_DCE (1<<7) /* 0x080 */ +#define MSR_EE (1<<8) /* 0x100 */ +#define MSR_EIP (1<<9) /* 0x200 */ +#define MSR_CC (1<<31) + +/* Floating Point Status Register (FSR) Bits */ +#define FSR_IO (1<<4) /* Invalid operation */ +#define FSR_DZ (1<<3) /* Divide-by-zero */ +#define FSR_OF (1<<2) /* Overflow */ +#define FSR_UF (1<<1) /* Underflow */ +#define FSR_DO (1<<0) /* Denormalized operand error */ + +# ifdef CONFIG_MMU +/* Machine State Register (MSR) Fields */ +# define MSR_UM (1<<11) /* User Mode */ +# define MSR_UMS (1<<12) /* User Mode Save */ +# define MSR_VM (1<<13) /* Virtual Mode */ +# define MSR_VMS (1<<14) /* Virtual Mode Save */ + +# define MSR_KERNEL (MSR_EE | MSR_VM) +/* # define MSR_USER (MSR_KERNEL | MSR_UM | MSR_IE) */ +# define MSR_KERNEL_VMS (MSR_EE | MSR_VMS) +/* # define MSR_USER_VMS (MSR_KERNEL_VMS | MSR_UMS | MSR_IE) */ + +/* Exception State Register (ESR) Fields */ +# define ESR_DIZ (1<<11) /* Zone Protection */ +# define ESR_S (1<<10) /* Store instruction */ + +# endif /* CONFIG_MMU */ +#endif /* _ASM_MICROBLAZE_REGISTERS_H */ diff --git a/arch/microblaze/include/asm/seccomp.h b/arch/microblaze/include/asm/seccomp.h new file mode 100644 index 000000000..95cdcabee --- /dev/null +++ b/arch/microblaze/include/asm/seccomp.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_MICROBLAZE_SECCOMP_H +#define _ASM_MICROBLAZE_SECCOMP_H + +#include <linux/unistd.h> + +#define __NR_seccomp_sigreturn __NR_sigreturn + +#include <asm-generic/seccomp.h> + +#endif /* _ASM_MICROBLAZE_SECCOMP_H */ diff --git a/arch/microblaze/include/asm/sections.h b/arch/microblaze/include/asm/sections.h new file mode 100644 index 000000000..1b281d3ea --- /dev/null +++ b/arch/microblaze/include/asm/sections.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2008-2009 PetaLogix + * Copyright (C) 2006 Atmark Techno, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_MICROBLAZE_SECTIONS_H +#define _ASM_MICROBLAZE_SECTIONS_H + +#include <asm-generic/sections.h> + +# ifndef __ASSEMBLY__ +extern char _ssbss[], _esbss[]; +extern unsigned long __ivt_start[], __ivt_end[]; + +extern u32 _fdt_start[], _fdt_end[]; + +# endif /* !__ASSEMBLY__ */ +#endif /* _ASM_MICROBLAZE_SECTIONS_H */ diff --git a/arch/microblaze/include/asm/setup.h b/arch/microblaze/include/asm/setup.h new file mode 100644 index 000000000..ce9b7b786 --- /dev/null +++ b/arch/microblaze/include/asm/setup.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2007-2009 PetaLogix + * Copyright (C) 2006 Atmark Techno, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#ifndef _ASM_MICROBLAZE_SETUP_H +#define _ASM_MICROBLAZE_SETUP_H + +#include <uapi/asm/setup.h> + +# ifndef __ASSEMBLY__ +extern unsigned int boot_cpuid; /* move to smp.h */ + +extern char cmd_line[COMMAND_LINE_SIZE]; + +extern char *klimit; + +# ifdef CONFIG_MMU +extern void mmu_reset(void); +# endif /* CONFIG_MMU */ + +void time_init(void); +void init_IRQ(void); +void machine_early_init(const char *cmdline, unsigned int ram, + unsigned int fdt, unsigned int msr, unsigned int tlb0, + unsigned int tlb1); + +void machine_restart(char *cmd); +void machine_shutdown(void); +void machine_halt(void); +void machine_power_off(void); + +extern void *zalloc_maybe_bootmem(size_t size, gfp_t mask); + +# endif /* __ASSEMBLY__ */ +#endif /* _ASM_MICROBLAZE_SETUP_H */ diff --git a/arch/microblaze/include/asm/string.h b/arch/microblaze/include/asm/string.h new file mode 100644 index 000000000..aec2f5929 --- /dev/null +++ b/arch/microblaze/include/asm/string.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2006 Atmark Techno, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_MICROBLAZE_STRING_H +#define _ASM_MICROBLAZE_STRING_H + +#ifdef __KERNEL__ + +#define __HAVE_ARCH_MEMSET +#define __HAVE_ARCH_MEMCPY +#define __HAVE_ARCH_MEMMOVE + +extern void *memset(void *, int, __kernel_size_t); +extern void *memcpy(void *, const void *, __kernel_size_t); +extern void *memmove(void *, const void *, __kernel_size_t); + +#endif /* __KERNEL__ */ + +#endif /* _ASM_MICROBLAZE_STRING_H */ diff --git a/arch/microblaze/include/asm/switch_to.h b/arch/microblaze/include/asm/switch_to.h new file mode 100644 index 000000000..f45baa2c5 --- /dev/null +++ b/arch/microblaze/include/asm/switch_to.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2006 Atmark Techno, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_MICROBLAZE_SWITCH_TO_H +#define _ASM_MICROBLAZE_SWITCH_TO_H + +struct task_struct; +struct thread_info; + +extern struct task_struct *_switch_to(struct thread_info *prev, + struct thread_info *next); + +#define switch_to(prev, next, last) \ + do { \ + (last) = _switch_to(task_thread_info(prev), \ + task_thread_info(next)); \ + } while (0) + +#endif /* _ASM_MICROBLAZE_SWITCH_TO_H */ diff --git a/arch/microblaze/include/asm/syscall.h b/arch/microblaze/include/asm/syscall.h new file mode 100644 index 000000000..220decd60 --- /dev/null +++ b/arch/microblaze/include/asm/syscall.h @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_MICROBLAZE_SYSCALL_H +#define __ASM_MICROBLAZE_SYSCALL_H + +#include <uapi/linux/audit.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <asm/ptrace.h> + +/* The system call number is given by the user in R12 */ +static inline long syscall_get_nr(struct task_struct *task, + struct pt_regs *regs) +{ + return regs->r12; +} + +static inline void syscall_rollback(struct task_struct *task, + struct pt_regs *regs) +{ + /* TODO. */ +} + +static inline long syscall_get_error(struct task_struct *task, + struct pt_regs *regs) +{ + return IS_ERR_VALUE(regs->r3) ? regs->r3 : 0; +} + +static inline long syscall_get_return_value(struct task_struct *task, + struct pt_regs *regs) +{ + return regs->r3; +} + +static inline void syscall_set_return_value(struct task_struct *task, + struct pt_regs *regs, + int error, long val) +{ + if (error) + regs->r3 = -error; + else + regs->r3 = val; +} + +static inline microblaze_reg_t microblaze_get_syscall_arg(struct pt_regs *regs, + unsigned int n) +{ + switch (n) { + case 5: return regs->r10; + case 4: return regs->r9; + case 3: return regs->r8; + case 2: return regs->r7; + case 1: return regs->r6; + case 0: return regs->r5; + default: + BUG(); + } + return ~0; +} + +static inline void microblaze_set_syscall_arg(struct pt_regs *regs, + unsigned int n, + unsigned long val) +{ + switch (n) { + case 5: + regs->r10 = val; + case 4: + regs->r9 = val; + case 3: + regs->r8 = val; + case 2: + regs->r7 = val; + case 1: + regs->r6 = val; + case 0: + regs->r5 = val; + default: + BUG(); + } +} + +static inline void syscall_get_arguments(struct task_struct *task, + struct pt_regs *regs, + unsigned int i, unsigned int n, + unsigned long *args) +{ + while (n--) + *args++ = microblaze_get_syscall_arg(regs, i++); +} + +static inline void syscall_set_arguments(struct task_struct *task, + struct pt_regs *regs, + unsigned int i, unsigned int n, + const unsigned long *args) +{ + while (n--) + microblaze_set_syscall_arg(regs, i++, *args++); +} + +asmlinkage unsigned long do_syscall_trace_enter(struct pt_regs *regs); +asmlinkage void do_syscall_trace_leave(struct pt_regs *regs); + +static inline int syscall_get_arch(void) +{ + return AUDIT_ARCH_MICROBLAZE; +} +#endif /* __ASM_MICROBLAZE_SYSCALL_H */ diff --git a/arch/microblaze/include/asm/thread_info.h b/arch/microblaze/include/asm/thread_info.h new file mode 100644 index 000000000..9afe4b5bd --- /dev/null +++ b/arch/microblaze/include/asm/thread_info.h @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2006 Atmark Techno, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_MICROBLAZE_THREAD_INFO_H +#define _ASM_MICROBLAZE_THREAD_INFO_H + +#ifdef __KERNEL__ + +/* we have 8k stack */ +#define THREAD_SHIFT 13 +#define THREAD_SIZE (1 << THREAD_SHIFT) +#define THREAD_SIZE_ORDER 1 + +#ifndef __ASSEMBLY__ +# include <linux/types.h> +# include <asm/processor.h> + +/* + * low level task data that entry.S needs immediate access to + * - this struct should fit entirely inside of one cache line + * - this struct shares the supervisor stack pages + * - if the contents of this structure are changed, the assembly constants + * must also be changed + */ + +struct cpu_context { + __u32 r1; /* stack pointer */ + __u32 r2; + /* dedicated registers */ + __u32 r13; + __u32 r14; + __u32 r15; + __u32 r16; + __u32 r17; + __u32 r18; + /* non-volatile registers */ + __u32 r19; + __u32 r20; + __u32 r21; + __u32 r22; + __u32 r23; + __u32 r24; + __u32 r25; + __u32 r26; + __u32 r27; + __u32 r28; + __u32 r29; + __u32 r30; + /* r31 is used as current task pointer */ + /* special purpose registers */ + __u32 msr; + __u32 ear; + __u32 esr; + __u32 fsr; +}; + +typedef struct { + unsigned long seg; +} mm_segment_t; + +struct thread_info { + struct task_struct *task; /* main task structure */ + unsigned long flags; /* low level flags */ + unsigned long status; /* thread-synchronous flags */ + __u32 cpu; /* current CPU */ + __s32 preempt_count; /* 0 => preemptable,< 0 => BUG*/ + mm_segment_t addr_limit; /* thread address space */ + + struct cpu_context cpu_context; +}; + +/* + * macros/functions for gaining access to the thread information structure + */ +#define INIT_THREAD_INFO(tsk) \ +{ \ + .task = &tsk, \ + .flags = 0, \ + .cpu = 0, \ + .preempt_count = INIT_PREEMPT_COUNT, \ + .addr_limit = KERNEL_DS, \ +} + +/* how to get the thread information struct from C */ +static inline struct thread_info *current_thread_info(void) +{ + register unsigned long sp asm("r1"); + + return (struct thread_info *)(sp & ~(THREAD_SIZE-1)); +} + +/* thread information allocation */ +#endif /* __ASSEMBLY__ */ + +/* + * thread information flags + * - these are process state flags that various assembly files may + * need to access + * - pending work-to-be-done flags are in LSW + * - other flags in MSW + */ +#define TIF_SYSCALL_TRACE 0 /* syscall trace active */ +#define TIF_NOTIFY_RESUME 1 /* resumption notification requested */ +#define TIF_SIGPENDING 2 /* signal pending */ +#define TIF_NEED_RESCHED 3 /* rescheduling necessary */ +/* restore singlestep on return to user mode */ +#define TIF_SINGLESTEP 4 +#define TIF_MEMDIE 6 /* is terminating due to OOM killer */ +#define TIF_SYSCALL_AUDIT 9 /* syscall auditing active */ +#define TIF_SECCOMP 10 /* secure computing */ + +/* true if poll_idle() is polling TIF_NEED_RESCHED */ +#define TIF_POLLING_NRFLAG 16 + +#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) +#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) +#define _TIF_SIGPENDING (1 << TIF_SIGPENDING) +#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) +#define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP) +#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) +#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) +#define _TIF_SECCOMP (1 << TIF_SECCOMP) + +/* work to do in syscall trace */ +#define _TIF_WORK_SYSCALL_MASK (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP | \ + _TIF_SYSCALL_AUDIT | _TIF_SECCOMP) + +/* work to do on interrupt/exception return */ +#define _TIF_WORK_MASK 0x0000FFFE + +/* work to do on any return to u-space */ +#define _TIF_ALLWORK_MASK 0x0000FFFF + +/* + * Thread-synchronous status. + * + * This is different from the flags in that nobody else + * ever touches our thread-synchronous status, so we don't + * have to worry about atomic accesses. + */ +/* FPU was used by this task this quantum (SMP) */ +#define TS_USEDFPU 0x0001 + +#endif /* __KERNEL__ */ +#endif /* _ASM_MICROBLAZE_THREAD_INFO_H */ diff --git a/arch/microblaze/include/asm/timex.h b/arch/microblaze/include/asm/timex.h new file mode 100644 index 000000000..befcf3de5 --- /dev/null +++ b/arch/microblaze/include/asm/timex.h @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2006 Atmark Techno, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_MICROBLAZE_TIMEX_H +#define _ASM_MICROBLAZE_TIMEX_H + +#include <asm-generic/timex.h> + +#define CLOCK_TICK_RATE 1000 /* Timer input freq. */ + +#endif /* _ASM_TIMEX_H */ diff --git a/arch/microblaze/include/asm/tlb.h b/arch/microblaze/include/asm/tlb.h new file mode 100644 index 000000000..99b6ded54 --- /dev/null +++ b/arch/microblaze/include/asm/tlb.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2008-2009 PetaLogix + * Copyright (C) 2006 Atmark Techno, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_MICROBLAZE_TLB_H +#define _ASM_MICROBLAZE_TLB_H + +#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm) + +#include <linux/pagemap.h> + +#ifdef CONFIG_MMU +#define tlb_start_vma(tlb, vma) do { } while (0) +#define tlb_end_vma(tlb, vma) do { } while (0) +#define __tlb_remove_tlb_entry(tlb, pte, address) do { } while (0) +#endif + +#include <asm-generic/tlb.h> + +#endif /* _ASM_MICROBLAZE_TLB_H */ diff --git a/arch/microblaze/include/asm/tlbflush.h b/arch/microblaze/include/asm/tlbflush.h new file mode 100644 index 000000000..2e1353c2d --- /dev/null +++ b/arch/microblaze/include/asm/tlbflush.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2008-2009 PetaLogix + * Copyright (C) 2006 Atmark Techno, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_MICROBLAZE_TLBFLUSH_H +#define _ASM_MICROBLAZE_TLBFLUSH_H + +#ifdef CONFIG_MMU + +#include <linux/sched.h> +#include <linux/threads.h> +#include <asm/processor.h> /* For TASK_SIZE */ +#include <asm/mmu.h> +#include <asm/page.h> +#include <asm/pgalloc.h> + +extern void _tlbie(unsigned long address); +extern void _tlbia(void); + +#define __tlbia() { preempt_disable(); _tlbia(); preempt_enable(); } +#define __tlbie(x) { _tlbie(x); } + +static inline void local_flush_tlb_all(void) + { __tlbia(); } +static inline void local_flush_tlb_mm(struct mm_struct *mm) + { __tlbia(); } +static inline void local_flush_tlb_page(struct vm_area_struct *vma, + unsigned long vmaddr) + { __tlbie(vmaddr); } +static inline void local_flush_tlb_range(struct vm_area_struct *vma, + unsigned long start, unsigned long end) + { __tlbia(); } + +#define flush_tlb_kernel_range(start, end) do { } while (0) + +#define update_mmu_cache(vma, addr, ptep) do { } while (0) + +#define flush_tlb_all local_flush_tlb_all +#define flush_tlb_mm local_flush_tlb_mm +#define flush_tlb_page local_flush_tlb_page +#define flush_tlb_range local_flush_tlb_range + +/* + * This is called in munmap when we have freed up some page-table + * pages. We don't need to do anything here, there's nothing special + * about our page-table pages. -- paulus + */ +static inline void flush_tlb_pgtables(struct mm_struct *mm, + unsigned long start, unsigned long end) { } + +#else /* CONFIG_MMU */ + +#define flush_tlb() BUG() +#define flush_tlb_all() BUG() +#define flush_tlb_mm(mm) BUG() +#define flush_tlb_page(vma, addr) BUG() +#define flush_tlb_range(mm, start, end) BUG() +#define flush_tlb_pgtables(mm, start, end) BUG() +#define flush_tlb_kernel_range(start, end) BUG() + +#endif /* CONFIG_MMU */ + +#endif /* _ASM_MICROBLAZE_TLBFLUSH_H */ diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h new file mode 100644 index 000000000..81f16aadb --- /dev/null +++ b/arch/microblaze/include/asm/uaccess.h @@ -0,0 +1,380 @@ +/* + * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2008-2009 PetaLogix + * Copyright (C) 2006 Atmark Techno, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_MICROBLAZE_UACCESS_H +#define _ASM_MICROBLAZE_UACCESS_H + +#include <linux/kernel.h> +#include <linux/mm.h> + +#include <asm/mmu.h> +#include <asm/page.h> +#include <asm/pgtable.h> +#include <asm/extable.h> +#include <linux/string.h> + +/* + * On Microblaze the fs value is actually the top of the corresponding + * address space. + * + * The fs value determines whether argument validity checking should be + * performed or not. If get_fs() == USER_DS, checking is performed, with + * get_fs() == KERNEL_DS, checking is bypassed. + * + * For historical reasons, these macros are grossly misnamed. + * + * For non-MMU arch like Microblaze, KERNEL_DS and USER_DS is equal. + */ +# define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) + +# ifndef CONFIG_MMU +# define KERNEL_DS MAKE_MM_SEG(0) +# define USER_DS KERNEL_DS +# else +# define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF) +# define USER_DS MAKE_MM_SEG(TASK_SIZE - 1) +# endif + +# define get_ds() (KERNEL_DS) +# define get_fs() (current_thread_info()->addr_limit) +# define set_fs(val) (current_thread_info()->addr_limit = (val)) + +# define segment_eq(a, b) ((a).seg == (b).seg) + +#ifndef CONFIG_MMU + +/* Check against bounds of physical memory */ +static inline int ___range_ok(unsigned long addr, unsigned long size) +{ + return ((addr < memory_start) || + ((addr + size - 1) > (memory_start + memory_size - 1))); +} + +#define __range_ok(addr, size) \ + ___range_ok((unsigned long)(addr), (unsigned long)(size)) + +#define access_ok(type, addr, size) (__range_ok((addr), (size)) == 0) + +#else + +static inline int access_ok(int type, const void __user *addr, + unsigned long size) +{ + if (!size) + goto ok; + + if ((get_fs().seg < ((unsigned long)addr)) || + (get_fs().seg < ((unsigned long)addr + size - 1))) { + pr_devel("ACCESS fail: %s at 0x%08x (size 0x%x), seg 0x%08x\n", + type ? "WRITE" : "READ ", (__force u32)addr, (u32)size, + (u32)get_fs().seg); + return 0; + } +ok: + pr_devel("ACCESS OK: %s at 0x%08x (size 0x%x), seg 0x%08x\n", + type ? "WRITE" : "READ ", (__force u32)addr, (u32)size, + (u32)get_fs().seg); + return 1; +} +#endif + +#ifdef CONFIG_MMU +# define __FIXUP_SECTION ".section .fixup,\"ax\"\n" +# define __EX_TABLE_SECTION ".section __ex_table,\"a\"\n" +#else +# define __FIXUP_SECTION ".section .discard,\"ax\"\n" +# define __EX_TABLE_SECTION ".section .discard,\"ax\"\n" +#endif + +extern unsigned long __copy_tofrom_user(void __user *to, + const void __user *from, unsigned long size); + +/* Return: number of not copied bytes, i.e. 0 if OK or non-zero if fail. */ +static inline unsigned long __must_check __clear_user(void __user *to, + unsigned long n) +{ + /* normal memset with two words to __ex_table */ + __asm__ __volatile__ ( \ + "1: sb r0, %1, r0;" \ + " addik %0, %0, -1;" \ + " bneid %0, 1b;" \ + " addik %1, %1, 1;" \ + "2: " \ + __EX_TABLE_SECTION \ + ".word 1b,2b;" \ + ".previous;" \ + : "=r"(n), "=r"(to) \ + : "0"(n), "1"(to) + ); + return n; +} + +static inline unsigned long __must_check clear_user(void __user *to, + unsigned long n) +{ + might_fault(); + if (unlikely(!access_ok(VERIFY_WRITE, to, n))) + return n; + + return __clear_user(to, n); +} + +/* put_user and get_user macros */ +extern long __user_bad(void); + +#define __get_user_asm(insn, __gu_ptr, __gu_val, __gu_err) \ +({ \ + __asm__ __volatile__ ( \ + "1:" insn " %1, %2, r0;" \ + " addk %0, r0, r0;" \ + "2: " \ + __FIXUP_SECTION \ + "3: brid 2b;" \ + " addik %0, r0, %3;" \ + ".previous;" \ + __EX_TABLE_SECTION \ + ".word 1b,3b;" \ + ".previous;" \ + : "=&r"(__gu_err), "=r"(__gu_val) \ + : "r"(__gu_ptr), "i"(-EFAULT) \ + ); \ +}) + +/** + * get_user: - Get a simple variable from user space. + * @x: Variable to store result. + * @ptr: Source address, in user space. + * + * Context: User context only. This function may sleep if pagefaults are + * enabled. + * + * This macro copies a single simple variable from user space to kernel + * space. It supports simple types like char and int, but not larger + * data types like structures or arrays. + * + * @ptr must have pointer-to-simple-variable type, and the result of + * dereferencing @ptr must be assignable to @x without a cast. + * + * Returns zero on success, or -EFAULT on error. + * On error, the variable @x is set to zero. + */ +#define get_user(x, ptr) \ + __get_user_check((x), (ptr), sizeof(*(ptr))) + +#define __get_user_check(x, ptr, size) \ +({ \ + unsigned long __gu_val = 0; \ + const typeof(*(ptr)) __user *__gu_addr = (ptr); \ + int __gu_err = 0; \ + \ + if (access_ok(VERIFY_READ, __gu_addr, size)) { \ + switch (size) { \ + case 1: \ + __get_user_asm("lbu", __gu_addr, __gu_val, \ + __gu_err); \ + break; \ + case 2: \ + __get_user_asm("lhu", __gu_addr, __gu_val, \ + __gu_err); \ + break; \ + case 4: \ + __get_user_asm("lw", __gu_addr, __gu_val, \ + __gu_err); \ + break; \ + default: \ + __gu_err = __user_bad(); \ + break; \ + } \ + } else { \ + __gu_err = -EFAULT; \ + } \ + x = (__force typeof(*(ptr)))__gu_val; \ + __gu_err; \ +}) + +#define __get_user(x, ptr) \ +({ \ + unsigned long __gu_val = 0; \ + /*unsigned long __gu_ptr = (unsigned long)(ptr);*/ \ + long __gu_err; \ + switch (sizeof(*(ptr))) { \ + case 1: \ + __get_user_asm("lbu", (ptr), __gu_val, __gu_err); \ + break; \ + case 2: \ + __get_user_asm("lhu", (ptr), __gu_val, __gu_err); \ + break; \ + case 4: \ + __get_user_asm("lw", (ptr), __gu_val, __gu_err); \ + break; \ + default: \ + /* __gu_val = 0; __gu_err = -EINVAL;*/ __gu_err = __user_bad();\ + } \ + x = (__force __typeof__(*(ptr))) __gu_val; \ + __gu_err; \ +}) + + +#define __put_user_asm(insn, __gu_ptr, __gu_val, __gu_err) \ +({ \ + __asm__ __volatile__ ( \ + "1:" insn " %1, %2, r0;" \ + " addk %0, r0, r0;" \ + "2: " \ + __FIXUP_SECTION \ + "3: brid 2b;" \ + " addik %0, r0, %3;" \ + ".previous;" \ + __EX_TABLE_SECTION \ + ".word 1b,3b;" \ + ".previous;" \ + : "=&r"(__gu_err) \ + : "r"(__gu_val), "r"(__gu_ptr), "i"(-EFAULT) \ + ); \ +}) + +#define __put_user_asm_8(__gu_ptr, __gu_val, __gu_err) \ +({ \ + __asm__ __volatile__ (" lwi %0, %1, 0;" \ + "1: swi %0, %2, 0;" \ + " lwi %0, %1, 4;" \ + "2: swi %0, %2, 4;" \ + " addk %0, r0, r0;" \ + "3: " \ + __FIXUP_SECTION \ + "4: brid 3b;" \ + " addik %0, r0, %3;" \ + ".previous;" \ + __EX_TABLE_SECTION \ + ".word 1b,4b,2b,4b;" \ + ".previous;" \ + : "=&r"(__gu_err) \ + : "r"(&__gu_val), "r"(__gu_ptr), "i"(-EFAULT) \ + ); \ +}) + +/** + * put_user: - Write a simple value into user space. + * @x: Value to copy to user space. + * @ptr: Destination address, in user space. + * + * Context: User context only. This function may sleep if pagefaults are + * enabled. + * + * This macro copies a single simple value from kernel space to user + * space. It supports simple types like char and int, but not larger + * data types like structures or arrays. + * + * @ptr must have pointer-to-simple-variable type, and @x must be assignable + * to the result of dereferencing @ptr. + * + * Returns zero on success, or -EFAULT on error. + */ +#define put_user(x, ptr) \ + __put_user_check((x), (ptr), sizeof(*(ptr))) + +#define __put_user_check(x, ptr, size) \ +({ \ + typeof(*(ptr)) volatile __pu_val = x; \ + typeof(*(ptr)) __user *__pu_addr = (ptr); \ + int __pu_err = 0; \ + \ + if (access_ok(VERIFY_WRITE, __pu_addr, size)) { \ + switch (size) { \ + case 1: \ + __put_user_asm("sb", __pu_addr, __pu_val, \ + __pu_err); \ + break; \ + case 2: \ + __put_user_asm("sh", __pu_addr, __pu_val, \ + __pu_err); \ + break; \ + case 4: \ + __put_user_asm("sw", __pu_addr, __pu_val, \ + __pu_err); \ + break; \ + case 8: \ + __put_user_asm_8(__pu_addr, __pu_val, __pu_err);\ + break; \ + default: \ + __pu_err = __user_bad(); \ + break; \ + } \ + } else { \ + __pu_err = -EFAULT; \ + } \ + __pu_err; \ +}) + +#define __put_user(x, ptr) \ +({ \ + __typeof__(*(ptr)) volatile __gu_val = (x); \ + long __gu_err = 0; \ + switch (sizeof(__gu_val)) { \ + case 1: \ + __put_user_asm("sb", (ptr), __gu_val, __gu_err); \ + break; \ + case 2: \ + __put_user_asm("sh", (ptr), __gu_val, __gu_err); \ + break; \ + case 4: \ + __put_user_asm("sw", (ptr), __gu_val, __gu_err); \ + break; \ + case 8: \ + __put_user_asm_8((ptr), __gu_val, __gu_err); \ + break; \ + default: \ + /*__gu_err = -EINVAL;*/ __gu_err = __user_bad(); \ + } \ + __gu_err; \ +}) + +static inline unsigned long +raw_copy_from_user(void *to, const void __user *from, unsigned long n) +{ + return __copy_tofrom_user((__force void __user *)to, from, n); +} + +static inline unsigned long +raw_copy_to_user(void __user *to, const void *from, unsigned long n) +{ + return __copy_tofrom_user(to, (__force const void __user *)from, n); +} +#define INLINE_COPY_FROM_USER +#define INLINE_COPY_TO_USER + +/* + * Copy a null terminated string from userspace. + */ +extern int __strncpy_user(char *to, const char __user *from, int len); + +static inline long +strncpy_from_user(char *dst, const char __user *src, long count) +{ + if (!access_ok(VERIFY_READ, src, 1)) + return -EFAULT; + return __strncpy_user(dst, src, count); +} + +/* + * Return the size of a string (including the ending 0) + * + * Return 0 on exception, a value greater than N if too long + */ +extern int __strnlen_user(const char __user *sstr, int len); + +static inline long strnlen_user(const char __user *src, long n) +{ + if (!access_ok(VERIFY_READ, src, 1)) + return 0; + return __strnlen_user(src, n); +} + +#endif /* _ASM_MICROBLAZE_UACCESS_H */ diff --git a/arch/microblaze/include/asm/unaligned.h b/arch/microblaze/include/asm/unaligned.h new file mode 100644 index 000000000..b162ed880 --- /dev/null +++ b/arch/microblaze/include/asm/unaligned.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2008 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2006 Atmark Techno, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_MICROBLAZE_UNALIGNED_H +#define _ASM_MICROBLAZE_UNALIGNED_H + +# ifdef __KERNEL__ + +# ifdef __MICROBLAZEEL__ +# include <linux/unaligned/le_struct.h> +# include <linux/unaligned/be_byteshift.h> +# define get_unaligned __get_unaligned_le +# define put_unaligned __put_unaligned_le +# else +# include <linux/unaligned/be_struct.h> +# include <linux/unaligned/le_byteshift.h> +# define get_unaligned __get_unaligned_be +# define put_unaligned __put_unaligned_be +# endif + +# include <linux/unaligned/generic.h> + +# endif /* __KERNEL__ */ +#endif /* _ASM_MICROBLAZE_UNALIGNED_H */ diff --git a/arch/microblaze/include/asm/unistd.h b/arch/microblaze/include/asm/unistd.h new file mode 100644 index 000000000..a62d09420 --- /dev/null +++ b/arch/microblaze/include/asm/unistd.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2007-2008 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2006 Atmark Techno, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#ifndef _ASM_MICROBLAZE_UNISTD_H +#define _ASM_MICROBLAZE_UNISTD_H + +#include <uapi/asm/unistd.h> + +#ifndef __ASSEMBLY__ + +/* #define __ARCH_WANT_OLD_READDIR */ +/* #define __ARCH_WANT_OLD_STAT */ +#define __ARCH_WANT_STAT64 +#define __ARCH_WANT_SYS_ALARM +#define __ARCH_WANT_SYS_GETHOSTNAME +#define __ARCH_WANT_SYS_PAUSE +#define __ARCH_WANT_SYS_SIGNAL +#define __ARCH_WANT_SYS_TIME +#define __ARCH_WANT_SYS_UTIME +#define __ARCH_WANT_SYS_WAITPID +#define __ARCH_WANT_SYS_SOCKETCALL +#define __ARCH_WANT_SYS_FADVISE64 +#define __ARCH_WANT_SYS_GETPGRP +#define __ARCH_WANT_SYS_LLSEEK +#define __ARCH_WANT_SYS_NICE +/* #define __ARCH_WANT_SYS_OLD_GETRLIMIT */ +#define __ARCH_WANT_SYS_OLDUMOUNT +#define __ARCH_WANT_SYS_SIGPENDING +#define __ARCH_WANT_SYS_SIGPROCMASK +#define __ARCH_WANT_SYS_CLONE +#define __ARCH_WANT_SYS_VFORK +#define __ARCH_WANT_SYS_FORK + +#endif /* __ASSEMBLY__ */ + +#define __NR_syscalls 401 + +#endif /* _ASM_MICROBLAZE_UNISTD_H */ diff --git a/arch/microblaze/include/asm/unwind.h b/arch/microblaze/include/asm/unwind.h new file mode 100644 index 000000000..d248b7de4 --- /dev/null +++ b/arch/microblaze/include/asm/unwind.h @@ -0,0 +1,29 @@ +/* + * Backtrace support for Microblaze + * + * Copyright (C) 2010 Digital Design Corporation + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef __MICROBLAZE_UNWIND_H +#define __MICROBLAZE_UNWIND_H + +struct stack_trace; + +struct trap_handler_info { + unsigned long start_addr; + unsigned long end_addr; + const char *trap_name; +}; +extern struct trap_handler_info microblaze_trap_handlers; + +extern const char _hw_exception_handler; +extern const char ex_handler_unhandled; + +void microblaze_unwind(struct task_struct *task, struct stack_trace *trace); + +#endif /* __MICROBLAZE_UNWIND_H */ + diff --git a/arch/microblaze/include/asm/user.h b/arch/microblaze/include/asm/user.h new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/arch/microblaze/include/asm/user.h @@ -0,0 +1 @@ + |