From: Paul Mundt This patch adds sh64 support. This is a bit overdue, as this was on the should-fix list, though we weren't done debugging and finishing off the port until just recently (I did a port against 2.5.68 but it wasn't in any shape to be merged). sh64 is already in 2.4 and has been for quite awhile, so this is mostly just a forward port of that code to 2.6 with appropriate bug fixes, etc. along the way. There isn't much in the way of new features that have been added to the port yet, though I have added rough hugetlb and oprofile support. This patch doesn't really touch any common code, with the exception of an ifdef or two for keyboard support and an ifdef in fb.h to omit sh64 from the __raw_xxx() wrapping that sh does. The only other common driver changes were to sh-sci for serial support, but those bits were already merged with the latest batch of sh-sci updates. Beyond that, the port is completely isolated. Signed-off-by: Richard Curnow Signed-off-by: Paul Mundt Signed-off-by: Andrew Morton --- 25-akpm/arch/sh64/Kconfig | 320 +++ 25-akpm/arch/sh64/Makefile | 112 + 25-akpm/arch/sh64/boot/Makefile | 20 25-akpm/arch/sh64/boot/compressed/Makefile | 46 25-akpm/arch/sh64/boot/compressed/cache.c | 39 25-akpm/arch/sh64/boot/compressed/head.S | 164 + 25-akpm/arch/sh64/boot/compressed/install.sh | 56 25-akpm/arch/sh64/boot/compressed/misc.c | 251 ++ 25-akpm/arch/sh64/boot/compressed/vmlinux.lds.S | 65 25-akpm/arch/sh64/configs/cayman_defconfig | 660 +++++++ 25-akpm/arch/sh64/defconfig | 660 +++++++ 25-akpm/arch/sh64/kernel/Makefile | 38 25-akpm/arch/sh64/kernel/alphanum.c | 45 25-akpm/arch/sh64/kernel/asm-offsets.c | 33 25-akpm/arch/sh64/kernel/dma.c | 297 +++ 25-akpm/arch/sh64/kernel/early_printk.c | 107 + 25-akpm/arch/sh64/kernel/entry.S | 2101 ++++++++++++++++++++++++ 25-akpm/arch/sh64/kernel/fpu.c | 170 + 25-akpm/arch/sh64/kernel/head.S | 373 ++++ 25-akpm/arch/sh64/kernel/init_task.c | 45 25-akpm/arch/sh64/kernel/irq.c | 720 ++++++++ 25-akpm/arch/sh64/kernel/irq_intc.c | 272 +++ 25-akpm/arch/sh64/kernel/led.c | 41 25-akpm/arch/sh64/kernel/pci-dma.c | 50 25-akpm/arch/sh64/kernel/pci_sh5.c | 546 ++++++ 25-akpm/arch/sh64/kernel/pci_sh5.h | 107 + 25-akpm/arch/sh64/kernel/pcibios.c | 168 + 25-akpm/arch/sh64/kernel/process.c | 963 +++++++++++ 25-akpm/arch/sh64/kernel/ptrace.c | 362 ++++ 25-akpm/arch/sh64/kernel/semaphore.c | 140 + 25-akpm/arch/sh64/kernel/setup.c | 400 ++++ 25-akpm/arch/sh64/kernel/sh_ksyms.c | 84 25-akpm/arch/sh64/kernel/signal.c | 737 ++++++++ 25-akpm/arch/sh64/kernel/switchto.S | 199 ++ 25-akpm/arch/sh64/kernel/sys_sh64.c | 286 +++ 25-akpm/arch/sh64/kernel/syscalls.S | 340 +++ 25-akpm/arch/sh64/kernel/time.c | 637 +++++++ 25-akpm/arch/sh64/kernel/traps.c | 958 ++++++++++ 25-akpm/arch/sh64/kernel/unwind.c | 326 +++ 25-akpm/arch/sh64/kernel/vmlinux.lds.S | 183 ++ 25-akpm/arch/sh64/lib/Makefile | 19 25-akpm/arch/sh64/lib/c-checksum.c | 231 ++ 25-akpm/arch/sh64/lib/copy_user_memcpy.S | 213 ++ 25-akpm/arch/sh64/lib/dbg.c | 394 ++++ 25-akpm/arch/sh64/lib/io.c | 207 ++ 25-akpm/arch/sh64/lib/memcpy.c | 82 25-akpm/arch/sh64/lib/old-checksum.c | 17 25-akpm/arch/sh64/lib/page_clear.S | 51 25-akpm/arch/sh64/lib/page_copy.S | 82 25-akpm/arch/sh64/lib/panic.c | 58 25-akpm/arch/sh64/lib/udelay.c | 60 25-akpm/arch/sh64/mach-cayman/Makefile | 11 25-akpm/arch/sh64/mach-cayman/irq.c | 196 ++ 25-akpm/arch/sh64/mach-cayman/led.c | 51 25-akpm/arch/sh64/mach-cayman/setup.c | 209 ++ 25-akpm/arch/sh64/mach-harp/Makefile | 14 25-akpm/arch/sh64/mach-harp/setup.c | 139 + 25-akpm/arch/sh64/mach-romram/Makefile | 14 25-akpm/arch/sh64/mach-romram/setup.c | 142 + 25-akpm/arch/sh64/mach-sim/Makefile | 14 25-akpm/arch/sh64/mach-sim/setup.c | 164 + 25-akpm/arch/sh64/mm/Makefile | 44 25-akpm/arch/sh64/mm/cache.c | 1055 ++++++++++++ 25-akpm/arch/sh64/mm/extable.c | 80 25-akpm/arch/sh64/mm/fault.c | 591 ++++++ 25-akpm/arch/sh64/mm/hugetlbpage.c | 264 +++ 25-akpm/arch/sh64/mm/init.c | 199 ++ 25-akpm/arch/sh64/mm/ioremap.c | 469 +++++ 25-akpm/arch/sh64/mm/tlb.c | 166 + 25-akpm/arch/sh64/mm/tlbmiss.c | 282 +++ 25-akpm/arch/sh64/oprofile/Kconfig | 23 25-akpm/arch/sh64/oprofile/Makefile | 12 25-akpm/arch/sh64/oprofile/op_model_null.c | 23 25-akpm/drivers/char/keyboard.c | 2 25-akpm/drivers/input/serio/i8042-io.h | 2 25-akpm/include/asm-sh64/a.out.h | 37 25-akpm/include/asm-sh64/atomic.h | 126 + 25-akpm/include/asm-sh64/bitops.h | 518 +++++ 25-akpm/include/asm-sh64/bug.h | 7 25-akpm/include/asm-sh64/bugs.h | 38 25-akpm/include/asm-sh64/byteorder.h | 49 25-akpm/include/asm-sh64/cache.h | 141 + 25-akpm/include/asm-sh64/cacheflush.h | 44 25-akpm/include/asm-sh64/cayman.h | 20 25-akpm/include/asm-sh64/checksum.h | 95 + 25-akpm/include/asm-sh64/cpumask.h | 6 25-akpm/include/asm-sh64/current.h | 28 25-akpm/include/asm-sh64/delay.h | 11 25-akpm/include/asm-sh64/div64.h | 6 25-akpm/include/asm-sh64/dma-mapping.h | 163 + 25-akpm/include/asm-sh64/dma.h | 41 25-akpm/include/asm-sh64/elf.h | 101 + 25-akpm/include/asm-sh64/errno.h | 6 25-akpm/include/asm-sh64/fcntl.h | 7 25-akpm/include/asm-sh64/hardirq.h | 7 25-akpm/include/asm-sh64/hardware.h | 45 25-akpm/include/asm-sh64/hdreg.h | 6 25-akpm/include/asm-sh64/hw_irq.h | 16 25-akpm/include/asm-sh64/ide.h | 30 25-akpm/include/asm-sh64/io.h | 217 ++ 25-akpm/include/asm-sh64/ioctl.h | 83 25-akpm/include/asm-sh64/ioctls.h | 111 + 25-akpm/include/asm-sh64/ipc.h | 6 25-akpm/include/asm-sh64/ipcbuf.h | 40 25-akpm/include/asm-sh64/irq.h | 148 + 25-akpm/include/asm-sh64/keyboard.h | 74 25-akpm/include/asm-sh64/kmap_types.h | 7 25-akpm/include/asm-sh64/linkage.h | 7 25-akpm/include/asm-sh64/local.h | 7 25-akpm/include/asm-sh64/mc146818rtc.h | 7 25-akpm/include/asm-sh64/mman.h | 6 25-akpm/include/asm-sh64/mmu.h | 7 25-akpm/include/asm-sh64/mmu_context.h | 209 ++ 25-akpm/include/asm-sh64/module.h | 12 25-akpm/include/asm-sh64/msgbuf.h | 42 25-akpm/include/asm-sh64/namei.h | 24 25-akpm/include/asm-sh64/page.h | 137 + 25-akpm/include/asm-sh64/param.h | 43 25-akpm/include/asm-sh64/pci.h | 110 + 25-akpm/include/asm-sh64/percpu.h | 6 25-akpm/include/asm-sh64/pgalloc.h | 202 ++ 25-akpm/include/asm-sh64/pgtable.h | 498 +++++ 25-akpm/include/asm-sh64/platform.h | 69 25-akpm/include/asm-sh64/poll.h | 36 25-akpm/include/asm-sh64/posix_types.h | 131 + 25-akpm/include/asm-sh64/processor.h | 292 +++ 25-akpm/include/asm-sh64/ptrace.h | 36 25-akpm/include/asm-sh64/registers.h | 106 + 25-akpm/include/asm-sh64/resource.h | 47 25-akpm/include/asm-sh64/scatterlist.h | 23 25-akpm/include/asm-sh64/sections.h | 7 25-akpm/include/asm-sh64/segment.h | 6 25-akpm/include/asm-sh64/semaphore-helper.h | 101 + 25-akpm/include/asm-sh64/semaphore.h | 146 + 25-akpm/include/asm-sh64/sembuf.h | 36 25-akpm/include/asm-sh64/serial.h | 33 25-akpm/include/asm-sh64/shmbuf.h | 53 25-akpm/include/asm-sh64/shmparam.h | 20 25-akpm/include/asm-sh64/sigcontext.h | 30 25-akpm/include/asm-sh64/siginfo.h | 6 25-akpm/include/asm-sh64/signal.h | 185 ++ 25-akpm/include/asm-sh64/smp.h | 15 25-akpm/include/asm-sh64/smplock.h | 77 25-akpm/include/asm-sh64/socket.h | 6 25-akpm/include/asm-sh64/sockios.h | 24 25-akpm/include/asm-sh64/softirq.h | 30 25-akpm/include/asm-sh64/spinlock.h | 17 25-akpm/include/asm-sh64/stat.h | 88 + 25-akpm/include/asm-sh64/statfs.h | 6 25-akpm/include/asm-sh64/string.h | 21 25-akpm/include/asm-sh64/system.h | 194 ++ 25-akpm/include/asm-sh64/termbits.h | 6 25-akpm/include/asm-sh64/termios.h | 117 + 25-akpm/include/asm-sh64/thread_info.h | 82 25-akpm/include/asm-sh64/timex.h | 36 25-akpm/include/asm-sh64/tlb.h | 92 + 25-akpm/include/asm-sh64/tlbflush.h | 31 25-akpm/include/asm-sh64/topology.h | 6 25-akpm/include/asm-sh64/types.h | 76 25-akpm/include/asm-sh64/uaccess.h | 317 +++ 25-akpm/include/asm-sh64/ucontext.h | 23 25-akpm/include/asm-sh64/unaligned.h | 28 25-akpm/include/asm-sh64/unistd.h | 555 ++++++ 25-akpm/include/asm-sh64/user.h | 71 25-akpm/include/linux/fb.h | 2 165 files changed, 25533 insertions(+), 2 deletions(-) diff -puN /dev/null arch/sh64/boot/compressed/cache.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/boot/compressed/cache.c 2004-06-28 13:30:30.630147352 -0700 @@ -0,0 +1,39 @@ +/* + * arch/shmedia/boot/compressed/cache.c -- simple cache management functions + * + * Code extracted from sh-ipl+g, sh-stub.c, which has the copyright: + * + * This is originally based on an m68k software stub written by Glenn + * Engel at HP, but has changed quite a bit. + * + * Modifications for the SH by Ben Lee and Steve Chamberlain + * +**************************************************************************** + + THIS SOFTWARE IS NOT COPYRIGHTED + + HP offers the following for use in the public domain. HP makes no + warranty with regard to the software or it's performance and the + user accepts the software "AS IS" with all faults. + + HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD + TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +****************************************************************************/ + +#define CACHE_ENABLE 0 +#define CACHE_DISABLE 1 + +int cache_control(unsigned int command) +{ + volatile unsigned int *p = (volatile unsigned int *) 0x80000000; + int i; + + for (i = 0; i < (32 * 1024); i += 32) { + (void *) *p; + p += (32 / sizeof (int)); + } + + return 0; +} diff -puN /dev/null arch/sh64/boot/compressed/head.S --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/boot/compressed/head.S 2004-06-28 13:30:30.631147200 -0700 @@ -0,0 +1,164 @@ +/* + * 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. + * + * arch/shmedia/boot/compressed/head.S + * + * Copied from + * arch/shmedia/kernel/head.S + * which carried the copyright: + * Copyright (C) 2000, 2001 Paolo Alberelli + * + * Modification for compressed loader: + * Copyright (C) 2002 Stuart Menefy (stuart.menefy@st.com) + */ + +#include +#include +#include +#include + +/* + * Fixed TLB entries to identity map the beginning of RAM + */ +#define MMUIR_TEXT_H 0x0000000000000003 | CONFIG_MEMORY_START + /* Enabled, Shared, ASID 0, Eff. Add. 0xA0000000 */ +#define MMUIR_TEXT_L 0x000000000000009a | CONFIG_MEMORY_START + /* 512 Mb, Cacheable (Write-back), execute, Not User, Ph. Add. */ + +#define MMUDR_CACHED_H 0x0000000000000003 | CONFIG_MEMORY_START + /* Enabled, Shared, ASID 0, Eff. Add. 0xA0000000 */ +#define MMUDR_CACHED_L 0x000000000000015a | CONFIG_MEMORY_START + /* 512 Mb, Cacheable (Write-back), read/write, Not User, Ph. Add. */ + +#define ICCR0_INIT_VAL ICCR0_ON | ICCR0_ICI /* ICE + ICI */ +#define ICCR1_INIT_VAL ICCR1_NOLOCK /* No locking */ + +#if 1 +#define OCCR0_INIT_VAL OCCR0_ON | OCCR0_OCI | OCCR0_WB /* OCE + OCI + WB */ +#else +#define OCCR0_INIT_VAL OCCR0_OFF +#endif +#define OCCR1_INIT_VAL OCCR1_NOLOCK /* No locking */ + + .text + + .global startup +startup: + /* + * Prevent speculative fetch on device memory due to + * uninitialized target registers. + * This must be executed before the first branch. + */ + ptabs/u ZERO, tr0 + ptabs/u ZERO, tr1 + ptabs/u ZERO, tr2 + ptabs/u ZERO, tr3 + ptabs/u ZERO, tr4 + ptabs/u ZERO, tr5 + ptabs/u ZERO, tr6 + ptabs/u ZERO, tr7 + synci + + /* + * Set initial TLB entries for cached and uncached regions. + * Note: PTA/BLINK is PIC code, PTABS/BLINK isn't ! + */ + /* Clear ITLBs */ + pta 1f, tr1 + movi ITLB_FIXED, r21 + movi ITLB_LAST_VAR_UNRESTRICTED+TLB_STEP, r22 +1: putcfg r21, 0, ZERO /* Clear MMUIR[n].PTEH.V */ + addi r21, TLB_STEP, r21 + bne r21, r22, tr1 + + /* Clear DTLBs */ + pta 1f, tr1 + movi DTLB_FIXED, r21 + movi DTLB_LAST_VAR_UNRESTRICTED+TLB_STEP, r22 +1: putcfg r21, 0, ZERO /* Clear MMUDR[n].PTEH.V */ + addi r21, TLB_STEP, r21 + bne r21, r22, tr1 + + /* Map one big (512Mb) page for ITLB */ + movi ITLB_FIXED, r21 + movi MMUIR_TEXT_L, r22 /* PTEL first */ + putcfg r21, 1, r22 /* Set MMUIR[0].PTEL */ + movi MMUIR_TEXT_H, r22 /* PTEH last */ + putcfg r21, 0, r22 /* Set MMUIR[0].PTEH */ + + /* Map one big CACHED (512Mb) page for DTLB */ + movi DTLB_FIXED, r21 + movi MMUDR_CACHED_L, r22 /* PTEL first */ + putcfg r21, 1, r22 /* Set MMUDR[0].PTEL */ + movi MMUDR_CACHED_H, r22 /* PTEH last */ + putcfg r21, 0, r22 /* Set MMUDR[0].PTEH */ + + /* ICache */ + movi ICCR_BASE, r21 + movi ICCR0_INIT_VAL, r22 + movi ICCR1_INIT_VAL, r23 + putcfg r21, ICCR_REG0, r22 + putcfg r21, ICCR_REG1, r23 + synci + + /* OCache */ + movi OCCR_BASE, r21 + movi OCCR0_INIT_VAL, r22 + movi OCCR1_INIT_VAL, r23 + putcfg r21, OCCR_REG0, r22 + putcfg r21, OCCR_REG1, r23 + synco + + /* + * Enable the MMU. + * From here-on code can be non-PIC. + */ + movi SR_HARMLESS | SR_ENABLE_MMU, r22 + putcon r22, SSR + movi 1f, r22 + putcon r22, SPC + synco + rte /* And now go into the hyperspace ... */ +1: /* ... that's the next instruction ! */ + + /* Set initial stack pointer */ + movi datalabel stack_start, r0 + ld.l r0, 0, r15 + + /* + * Clear bss + */ + pt 1f, tr1 + movi datalabel __bss_start, r22 + movi datalabel _end, r23 +1: st.l r22, 0, ZERO + addi r22, 4, r22 + bne r22, r23, tr1 + + /* + * Decompress the kernel. + */ + pt decompress_kernel, tr0 + blink tr0, r18 + + /* + * Disable the MMU. + */ + movi SR_HARMLESS, r22 + putcon r22, SSR + movi 1f, r22 + putcon r22, SPC + synco + rte /* And now go into the hyperspace ... */ +1: /* ... that's the next instruction ! */ + + /* Jump into the decompressed kernel */ + movi datalabel (CONFIG_MEMORY_START + 0x2000)+1, r19 + ptabs r19, tr0 + blink tr0, r18 + + /* Shouldn't return here, but just in case, loop forever */ + pt 1f, tr0 +1: blink tr0, ZERO diff -puN /dev/null arch/sh64/boot/compressed/install.sh --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/boot/compressed/install.sh 2004-06-28 13:30:30.631147200 -0700 @@ -0,0 +1,56 @@ +#!/bin/sh +# +# arch/sh/boot/install.sh +# +# 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) 1995 by Linus Torvalds +# +# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin +# Adapted from code in arch/i386/boot/install.sh by Russell King +# Adapted from code in arch/arm/boot/install.sh by Stuart Menefy +# +# "make install" script for sh architecture +# +# Arguments: +# $1 - kernel version +# $2 - kernel image file +# $3 - kernel map file +# $4 - default install path (blank if root directory) +# + +# User may have a custom install script + +if [ -x /sbin/installkernel ]; then + exec /sbin/installkernel "$@" +fi + +if [ "$2" = "zImage" ]; then +# Compressed install + echo "Installing compressed kernel" + if [ -f $4/vmlinuz-$1 ]; then + mv $4/vmlinuz-$1 $4/vmlinuz.old + fi + + if [ -f $4/System.map-$1 ]; then + mv $4/System.map-$1 $4/System.old + fi + + cat $2 > $4/vmlinuz-$1 + cp $3 $4/System.map-$1 +else +# Normal install + echo "Installing normal kernel" + if [ -f $4/vmlinux-$1 ]; then + mv $4/vmlinux-$1 $4/vmlinux.old + fi + + if [ -f $4/System.map ]; then + mv $4/System.map $4/System.old + fi + + cat $2 > $4/vmlinux-$1 + cp $3 $4/System.map +fi diff -puN /dev/null arch/sh64/boot/compressed/Makefile --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/boot/compressed/Makefile 2004-06-28 13:30:30.632147048 -0700 @@ -0,0 +1,46 @@ +# +# linux/arch/sh64/boot/compressed/Makefile +# +# 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) 2002 Stuart Menefy +# Copyright (C) 2004 Paul Mundt +# +# create a compressed vmlinux image from the original vmlinux +# + +targets := vmlinux vmlinux.bin vmlinux.bin.gz \ + head.o misc.o cache.o piggy.o vmlinux.lds.o + +EXTRA_AFLAGS := -traditional + +OBJECTS := $(obj)/head.o $(obj)/misc.o $(obj)/cache.o + +# +# ZIMAGE_OFFSET is the load offset of the compression loader +# (4M for the kernel plus 64K for this loader) +# +ZIMAGE_OFFSET = $(shell printf "0x%8x" $$[$(CONFIG_MEMORY_START)+0x400000+0x10000]) + +LDFLAGS_vmlinux := -Ttext $(ZIMAGE_OFFSET) -e startup \ + -T $(obj)/../../kernel/vmlinux.lds.s \ + --no-warn-mismatch + +$(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o FORCE + $(call if_changed,ld) + @: + +$(obj)/vmlinux.bin: vmlinux FORCE + $(call if_changed,objcopy) + +$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE + $(call if_changed,gzip) + +LDFLAGS_piggy.o := -r --format binary --oformat elf32-sh64-linux -T +OBJCOPYFLAGS += -R .empty_zero_page + +$(obj)/piggy.o: $(obj)/vmlinux.lds.s $(obj)/vmlinux.bin.gz FORCE + $(call if_changed,ld) + diff -puN /dev/null arch/sh64/boot/compressed/misc.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/boot/compressed/misc.c 2004-06-28 13:30:30.633146896 -0700 @@ -0,0 +1,251 @@ +/* + * arch/shmedia/boot/compressed/misc.c + * + * This is a collection of several routines from gzip-1.0.3 + * adapted for Linux. + * + * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994 + * + * Adapted for SHmedia from sh by Stuart Menefy, May 2002 + */ + +#include +#include + +/* cache.c */ +#define CACHE_ENABLE 0 +#define CACHE_DISABLE 1 +int cache_control(unsigned int command); + +/* + * gzip declarations + */ + +#define OF(args) args +#define STATIC static + +#undef memset +#undef memcpy +#define memzero(s, n) memset ((s), 0, (n)) + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + +#define WSIZE 0x8000 /* Window size must be at least 32k, */ + /* and a power of two */ + +static uch *inbuf; /* input buffer */ +static uch window[WSIZE]; /* Sliding window buffer */ + +static unsigned insize = 0; /* valid bytes in inbuf */ +static unsigned inptr = 0; /* index of next byte to be processed in inbuf */ +static unsigned outcnt = 0; /* bytes in output buffer */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ +#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ +#define RESERVED 0xC0 /* bit 6,7: reserved */ + +#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) + +/* Diagnostic functions */ +#ifdef DEBUG +# define Assert(cond,msg) {if(!(cond)) error(msg);} +# define Trace(x) fprintf x +# define Tracev(x) {if (verbose) fprintf x ;} +# define Tracevv(x) {if (verbose>1) fprintf x ;} +# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} +# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + +static int fill_inbuf(void); +static void flush_window(void); +static void error(char *m); +static void gzip_mark(void **); +static void gzip_release(void **); + +extern char input_data[]; +extern int input_len; + +static long bytes_out = 0; +static uch *output_data; +static unsigned long output_ptr = 0; + +static void *malloc(int size); +static void free(void *where); +static void error(char *m); +static void gzip_mark(void **); +static void gzip_release(void **); + +static void puts(const char *); + +extern int _text; /* Defined in vmlinux.lds.S */ +extern int _end; +static unsigned long free_mem_ptr; +static unsigned long free_mem_end_ptr; + +#define HEAP_SIZE 0x10000 + +#include "../../../../lib/inflate.c" + +static void *malloc(int size) +{ + void *p; + + if (size < 0) + error("Malloc error\n"); + if (free_mem_ptr == 0) + error("Memory error\n"); + + free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */ + + p = (void *) free_mem_ptr; + free_mem_ptr += size; + + if (free_mem_ptr >= free_mem_end_ptr) + error("\nOut of memory\n"); + + return p; +} + +static void free(void *where) +{ /* Don't care */ +} + +static void gzip_mark(void **ptr) +{ + *ptr = (void *) free_mem_ptr; +} + +static void gzip_release(void **ptr) +{ + free_mem_ptr = (long) *ptr; +} + +void puts(const char *s) +{ +} + +void *memset(void *s, int c, size_t n) +{ + int i; + char *ss = (char *) s; + + for (i = 0; i < n; i++) + ss[i] = c; + return s; +} + +void *memcpy(void *__dest, __const void *__src, size_t __n) +{ + int i; + char *d = (char *) __dest, *s = (char *) __src; + + for (i = 0; i < __n; i++) + d[i] = s[i]; + return __dest; +} + +/* =========================================================================== + * Fill the input buffer. This is called only when the buffer is empty + * and at least one byte is really needed. + */ +static int fill_inbuf(void) +{ + if (insize != 0) { + error("ran out of input data\n"); + } + + inbuf = input_data; + insize = input_len; + inptr = 1; + return inbuf[0]; +} + +/* =========================================================================== + * Write the output window window[0..outcnt-1] and update crc and bytes_out. + * (Used for the decompressed data only.) + */ +static void flush_window(void) +{ + ulg c = crc; /* temporary variable */ + unsigned n; + uch *in, *out, ch; + + in = window; + out = &output_data[output_ptr]; + for (n = 0; n < outcnt; n++) { + ch = *out++ = *in++; + c = crc_32_tab[((int) c ^ ch) & 0xff] ^ (c >> 8); + } + crc = c; + bytes_out += (ulg) outcnt; + output_ptr += (ulg) outcnt; + outcnt = 0; + puts("."); +} + +static void error(char *x) +{ + puts("\n\n"); + puts(x); + puts("\n\n -- System halted"); + + while (1) ; /* Halt */ +} + +#define STACK_SIZE (4096) +long __attribute__ ((aligned(8))) user_stack[STACK_SIZE]; +long *stack_start = &user_stack[STACK_SIZE]; + +void decompress_kernel(void) +{ + output_data = (uch *) (CONFIG_MEMORY_START + 0x2000); + free_mem_ptr = (unsigned long) &_end; + free_mem_end_ptr = free_mem_ptr + HEAP_SIZE; + + makecrc(); + puts("Uncompressing Linux... "); + cache_control(CACHE_ENABLE); + gunzip(); + puts("\n"); + +#if 0 + /* When booting from ROM may want to do something like this if the + * boot loader doesn't. + */ + + /* Set up the parameters and command line */ + { + volatile unsigned int *parambase = + (int *) (CONFIG_MEMORY_START + 0x1000); + + parambase[0] = 0x1; /* MOUNT_ROOT_RDONLY */ + parambase[1] = 0x0; /* RAMDISK_FLAGS */ + parambase[2] = 0x0200; /* ORIG_ROOT_DEV */ + parambase[3] = 0x0; /* LOADER_TYPE */ + parambase[4] = 0x0; /* INITRD_START */ + parambase[5] = 0x0; /* INITRD_SIZE */ + parambase[6] = 0; + + strcpy((char *) ((int) parambase + 0x100), + "console=ttySC0,38400"); + } +#endif + + puts("Ok, booting the kernel.\n"); + + cache_control(CACHE_DISABLE); +} diff -puN /dev/null arch/sh64/boot/compressed/vmlinux.lds.S --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/boot/compressed/vmlinux.lds.S 2004-06-28 13:30:30.634146744 -0700 @@ -0,0 +1,65 @@ +/* + * ld script to make compressed SuperH/shmedia Linux kernel+decompression + * bootstrap + * Modified by Stuart Menefy from arch/sh/vmlinux.lds.S written by Niibe Yutaka + */ + +#include + +#ifdef CONFIG_LITTLE_ENDIAN +/* OUTPUT_FORMAT("elf32-sh64l-linux", "elf32-sh64l-linux", "elf32-sh64l-linux") */ +#define NOP 0x6ff0fff0 +#else +/* OUTPUT_FORMAT("elf32-sh64", "elf32-sh64", "elf32-sh64") */ +#define NOP 0xf0fff06f +#endif + +OUTPUT_FORMAT("elf32-sh64-linux") +OUTPUT_ARCH(sh) +ENTRY(_start) + +#define ALIGNED_GAP(section, align) (((ADDR(section)+SIZEOF(section)+(align)-1) & ~((align)-1))-ADDR(section)) +#define FOLLOWING(section, align) AT (LOADADDR(section) + ALIGNED_GAP(section,align)) + +SECTIONS +{ + _text = .; /* Text and read-only data */ + + .text : { + *(.text) + *(.text64) + *(.text..SHmedia32) + *(.fixup) + *(.gnu.warning) + } = NOP + . = ALIGN(4); + .rodata : { *(.rodata) } + + /* There is no 'real' reason for eight byte alignment, four would work + * as well, but gdb downloads much (*4) faster with this. + */ + . = ALIGN(8); + .image : { *(.image) } + . = ALIGN(4); + _etext = .; /* End of text section */ + + .data : /* Data */ + FOLLOWING(.image, 4) + { + _data = .; + *(.data) + } + _data_image = LOADADDR(.data);/* Address of data section in ROM */ + + _edata = .; /* End of data section */ + + .stack : { stack = .; _stack = .; } + + . = ALIGN(4); + __bss_start = .; /* BSS */ + .bss : { + *(.bss) + } + . = ALIGN(4); + _end = . ; +} diff -puN /dev/null arch/sh64/boot/Makefile --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/boot/Makefile 2004-06-28 13:30:30.634146744 -0700 @@ -0,0 +1,20 @@ +# +# arch/sh64/boot/Makefile +# +# 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) 2002 Stuart Menefy +# + +targets := zImage +subdir- := compressed + +$(obj)/zImage: $(obj)/compressed/vmlinux FORCE + $(call if_changed,objcopy) + @echo 'Kernel: $@ is ready' + +$(obj)/compressed/vmlinux: FORCE + $(Q)$(MAKE) $(build)=$(obj)/compressed $@ + diff -puN /dev/null arch/sh64/configs/cayman_defconfig --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/configs/cayman_defconfig 2004-06-28 13:30:30.636146440 -0700 @@ -0,0 +1,660 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_SUPERH=y +CONFIG_SUPERH64=y +CONFIG_MMU=y +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_LOG_BUF_SHIFT=14 + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_STANDALONE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_SWAP=y +# CONFIG_SYSVIPC is not set +CONFIG_POSIX_MQUEUE=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +# CONFIG_HOTPLUG is not set +# CONFIG_IKCONFIG is not set +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# System type +# +# CONFIG_SH_GENERIC is not set +# CONFIG_SH_SIMULATOR is not set +CONFIG_SH_CAYMAN=y +# CONFIG_SH_ROMRAM is not set +# CONFIG_SH_HARP is not set + +# +# Processor type and features +# +CONFIG_CPU_SH5=y +CONFIG_CPU_SUBTYPE_SH5_101=y +# CONFIG_CPU_SUBTYPE_SH5_103 is not set +CONFIG_LITTLE_ENDIAN=y +# CONFIG_BIG_ENDIAN is not set +# CONFIG_SH64_FPU_DENORM_FLUSH is not set +CONFIG_SH64_PGTABLE_2_LEVEL=y +# CONFIG_SH64_PGTABLE_3_LEVEL is not set +CONFIG_HUGETLB_PAGE_SIZE_64K=y +# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set +# CONFIG_HUGETLB_PAGE_SIZE_512MB is not set +CONFIG_SH64_USER_MISALIGNED_FIXUP=y + +# +# Memory options +# +CONFIG_CACHED_MEMORY_OFFSET=0x20000000 +CONFIG_MEMORY_START=0x80000000 +CONFIG_MEMORY_SIZE_IN_MB=128 + +# +# Cache options +# +# CONFIG_DCACHE_DISABLED is not set +CONFIG_DCACHE_WRITE_BACK=y +# CONFIG_DCACHE_WRITE_THROUGH is not set +# CONFIG_ICACHE_DISABLED is not set +CONFIG_PCIDEVICE_MEMORY_START=C0000000 +CONFIG_DEVICE_MEMORY_START=E0000000 +CONFIG_FLASH_MEMORY_START=0x00000000 +CONFIG_PCI_BLOCK_START=0x40000000 + +# +# CPU Subtype specific options +# +CONFIG_SH64_ID2815_WORKAROUND=y + +# +# Misc options +# +CONFIG_HEARTBEAT=y +CONFIG_HDSP253_LED=y +CONFIG_SH_DMA=y +CONFIG_PREEMPT=y + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +CONFIG_PCI=y +CONFIG_SH_PCIDMA_NONCOHERENT=y +CONFIG_PCI_LEGACY_PROC=y +CONFIG_PCI_NAMES=y + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_FLAT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_CARMEL is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_LBD is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_MII is not set +# CONFIG_STNIC is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set + +# +# Tulip family network device support +# +CONFIG_NET_TULIP=y +# CONFIG_DE2104X is not set +CONFIG_TULIP=y +# CONFIG_TULIP_MWI is not set +# CONFIG_TULIP_MMIO is not set +# CONFIG_TULIP_NAPI is not set +# CONFIG_DE4X5 is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_DM9102 is not set +# CONFIG_HP100 is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_B44 is not set +# CONFIG_FORCEDETH is not set +# CONFIG_DGRS is not set +# CONFIG_EEPRO100 is not set +# CONFIG_E100 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set + +# +# Ethernet (10000 Mbit) +# +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PCIPS2 is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_SH_SCI=y +CONFIG_SERIAL_SH_SCI_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_SH_WDT is not set + +# +# PCI-based Watchdog Cards +# +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_WDTPCI is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +CONFIG_FB=y +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_E1355 is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON_OLD is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +CONFIG_FB_KYRO=y +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +# CONFIG_MDA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_PCI_CONSOLE=y +CONFIG_FONTS=y +# CONFIG_FONT_8x8 is not set +CONFIG_FONT_8x16=y +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set +# CONFIG_FONT_MINI_4x6 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set + +# +# Logo configuration +# +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +# CONFIG_LOGO_LINUX_CLUT224 is not set +# CONFIG_LOGO_SUPERH_MONO is not set +# CONFIG_LOGO_SUPERH_VGA16 is not set +CONFIG_LOGO_SUPERH_CLUT224=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +CONFIG_MINIX_FS=y +CONFIG_ROMFS_FS=y +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_FAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVPTS_FS_XATTR is not set +CONFIG_TMPFS=y +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_EXPORTFS is not set +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Kernel hacking +# +CONFIG_MAGIC_SYSRQ=y +# CONFIG_EARLY_PRINTK is not set +# CONFIG_DEBUG_KERNEL_WITH_GDB_STUB is not set +# CONFIG_SH64_PROC_TLB is not set +# CONFIG_SH64_PROC_ASIDS is not set +CONFIG_SH64_SR_WATCH=y +# CONFIG_SH_ALPHANUMERIC is not set +# CONFIG_SH_NO_BSS_INIT is not set +CONFIG_FRAME_POINTER=y + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set diff -puN /dev/null arch/sh64/defconfig --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/defconfig 2004-06-28 13:30:30.638146136 -0700 @@ -0,0 +1,660 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_SUPERH=y +CONFIG_SUPERH64=y +CONFIG_MMU=y +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_LOG_BUF_SHIFT=14 + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_STANDALONE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_SWAP=y +# CONFIG_SYSVIPC is not set +CONFIG_POSIX_MQUEUE=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +# CONFIG_HOTPLUG is not set +# CONFIG_IKCONFIG is not set +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# System type +# +# CONFIG_SH_GENERIC is not set +# CONFIG_SH_SIMULATOR is not set +CONFIG_SH_CAYMAN=y +# CONFIG_SH_ROMRAM is not set +# CONFIG_SH_HARP is not set + +# +# Processor type and features +# +CONFIG_CPU_SH5=y +CONFIG_CPU_SUBTYPE_SH5_101=y +# CONFIG_CPU_SUBTYPE_SH5_103 is not set +CONFIG_LITTLE_ENDIAN=y +# CONFIG_BIG_ENDIAN is not set +# CONFIG_SH64_FPU_DENORM_FLUSH is not set +CONFIG_SH64_PGTABLE_2_LEVEL=y +# CONFIG_SH64_PGTABLE_3_LEVEL is not set +CONFIG_HUGETLB_PAGE_SIZE_64K=y +# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set +# CONFIG_HUGETLB_PAGE_SIZE_512MB is not set +CONFIG_SH64_USER_MISALIGNED_FIXUP=y + +# +# Memory options +# +CONFIG_CACHED_MEMORY_OFFSET=0x20000000 +CONFIG_MEMORY_START=0x80000000 +CONFIG_MEMORY_SIZE_IN_MB=128 + +# +# Cache options +# +# CONFIG_DCACHE_DISABLED is not set +CONFIG_DCACHE_WRITE_BACK=y +# CONFIG_DCACHE_WRITE_THROUGH is not set +# CONFIG_ICACHE_DISABLED is not set +CONFIG_PCIDEVICE_MEMORY_START=C0000000 +CONFIG_DEVICE_MEMORY_START=E0000000 +CONFIG_FLASH_MEMORY_START=0x00000000 +CONFIG_PCI_BLOCK_START=0x40000000 + +# +# CPU Subtype specific options +# +CONFIG_SH64_ID2815_WORKAROUND=y + +# +# Misc options +# +CONFIG_HEARTBEAT=y +CONFIG_HDSP253_LED=y +CONFIG_SH_DMA=y +CONFIG_PREEMPT=y + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +CONFIG_PCI=y +CONFIG_SH_PCIDMA_NONCOHERENT=y +CONFIG_PCI_LEGACY_PROC=y +CONFIG_PCI_NAMES=y + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_FLAT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_CARMEL is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_LBD is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_MII is not set +# CONFIG_STNIC is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set + +# +# Tulip family network device support +# +CONFIG_NET_TULIP=y +# CONFIG_DE2104X is not set +CONFIG_TULIP=y +# CONFIG_TULIP_MWI is not set +# CONFIG_TULIP_MMIO is not set +# CONFIG_TULIP_NAPI is not set +# CONFIG_DE4X5 is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_DM9102 is not set +# CONFIG_HP100 is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_B44 is not set +# CONFIG_FORCEDETH is not set +# CONFIG_DGRS is not set +# CONFIG_EEPRO100 is not set +# CONFIG_E100 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set + +# +# Ethernet (10000 Mbit) +# +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PCIPS2 is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_SH_SCI=y +CONFIG_SERIAL_SH_SCI_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_SH_WDT is not set + +# +# PCI-based Watchdog Cards +# +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_WDTPCI is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +CONFIG_FB=y +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_E1355 is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON_OLD is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +CONFIG_FB_KYRO=y +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +# CONFIG_MDA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_PCI_CONSOLE=y +CONFIG_FONTS=y +# CONFIG_FONT_8x8 is not set +CONFIG_FONT_8x16=y +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set +# CONFIG_FONT_MINI_4x6 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set + +# +# Logo configuration +# +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +# CONFIG_LOGO_LINUX_CLUT224 is not set +# CONFIG_LOGO_SUPERH_MONO is not set +# CONFIG_LOGO_SUPERH_VGA16 is not set +CONFIG_LOGO_SUPERH_CLUT224=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +CONFIG_MINIX_FS=y +CONFIG_ROMFS_FS=y +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_FAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVPTS_FS_XATTR is not set +CONFIG_TMPFS=y +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_EXPORTFS is not set +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Kernel hacking +# +CONFIG_MAGIC_SYSRQ=y +# CONFIG_EARLY_PRINTK is not set +# CONFIG_DEBUG_KERNEL_WITH_GDB_STUB is not set +# CONFIG_SH64_PROC_TLB is not set +# CONFIG_SH64_PROC_ASIDS is not set +CONFIG_SH64_SR_WATCH=y +# CONFIG_SH_ALPHANUMERIC is not set +# CONFIG_SH_NO_BSS_INIT is not set +CONFIG_FRAME_POINTER=y + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set diff -puN /dev/null arch/sh64/Kconfig --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/Kconfig 2004-06-28 13:30:30.640145832 -0700 @@ -0,0 +1,320 @@ +# +# For a description of the syntax of this configuration file, +# see Documentation/kbuild/config-language.txt. +# + +mainmenu "Linux/SH64 Kernel Configuration" + +config SUPERH + bool + default y + +config SUPERH64 + bool + default y + +config MMU + bool + default y + +config UID16 + bool + default y + +config RWSEM_GENERIC_SPINLOCK + bool + default y + +config LOG_BUF_SHIFT + int + default 14 + +config RWSEM_XCHGADD_ALGORITHM + bool + +config GENERIC_ISA_DMA + bool + +source init/Kconfig + +menu "System type" + +choice + prompt "SuperH system type" + default SH_SIMULATOR + +config SH_GENERIC + bool "Generic" + +config SH_SIMULATOR + bool "Simulator" + +config SH_CAYMAN + bool "Cayman" + +config SH_ROMRAM + bool "ROM/RAM" + +config SH_HARP + bool "ST50-Harp" + +endchoice + +choice + prompt "Processor family" + default CPU_SH5 + +config CPU_SH5 + bool "SH-5" + +endchoice + +choice + prompt "Processor type" + +config CPU_SUBTYPE_SH5_101 + bool "SH5-101" + depends on CPU_SH5 + +config CPU_SUBTYPE_SH5_103 + bool "SH5-103" + depends on CPU_SH5 + +endchoice + +choice + prompt "Endianness" + default LITTLE_ENDIAN + +config LITTLE_ENDIAN + bool "Little-Endian" + +config BIG_ENDIAN + bool "Big-Endian" + +endchoice + +config SH64_FPU_DENORM_FLUSH + bool "Flush floating point denorms to zero" + +choice + prompt "Page table levels" + default SH64_PGTABLE_2_LEVEL + +config SH64_PGTABLE_2_LEVEL + bool "2" + +config SH64_PGTABLE_3_LEVEL + bool "3" + +endchoice + +choice + prompt "HugeTLB page size" + depends on HUGETLB_PAGE && MMU + default HUGETLB_PAGE_SIZE_64K + +config HUGETLB_PAGE_SIZE_64K + bool "64K" + +config HUGETLB_PAGE_SIZE_1MB + bool "1MB" + +config HUGETLB_PAGE_SIZE_512MB + bool "512MB" + +endchoice + +config SH64_USER_MISALIGNED_FIXUP + bool "Fixup misaligned loads/stores occurring in user mode" + +comment "Memory options" + +config CACHED_MEMORY_OFFSET + hex "Cached Area Offset" + depends on SH_HARP || SH_CAYMAN || SH_SIMULATOR + default "20000000" + +config MEMORY_START + hex "Physical memory start address" + depends on SH_HARP || SH_CAYMAN || SH_SIMULATOR + default "80000000" + +config MEMORY_SIZE_IN_MB + int "Memory size (in MB)" if SH_HARP || SH_CAYMAN || SH_SIMULATOR + default "64" if SH_HARP || SH_CAYMAN + default "8" if SH_SIMULATOR + +comment "Cache options" + +config DCACHE_DISABLED + bool "DCache Disabling" + depends on SH_HARP || SH_CAYMAN || SH_SIMULATOR + +choice + prompt "DCache mode" + depends on !DCACHE_DISABLED && !SH_SIMULATOR + default DCACHE_WRITE_BACK + +config DCACHE_WRITE_BACK + bool "Write-back" + +config DCACHE_WRITE_THROUGH + bool "Write-through" + +endchoice + +config ICACHE_DISABLED + bool "ICache Disabling" + depends on SH_HARP || SH_CAYMAN || SH_SIMULATOR + +config PCIDEVICE_MEMORY_START + hex + depends on SH_HARP || SH_CAYMAN || SH_SIMULATOR + default "C0000000" + +config DEVICE_MEMORY_START + hex + depends on SH_HARP || SH_CAYMAN || SH_SIMULATOR + default "E0000000" + +config FLASH_MEMORY_START + hex "Flash memory/on-chip devices start address" + depends on SH_HARP || SH_CAYMAN || SH_SIMULATOR + default "00000000" + +config PCI_BLOCK_START + hex "PCI block start address" + depends on SH_HARP || SH_CAYMAN || SH_SIMULATOR + default "40000000" + +comment "CPU Subtype specific options" + +config SH64_ID2815_WORKAROUND + bool "Include workaround for SH5-101 cut2 silicon defect ID2815" + +comment "Misc options" +config HEARTBEAT + bool "Heartbeat LED" + +config HDSP253_LED + bool "Support for HDSP-253 LED" + depends on SH_CAYMAN + +config SH_DMA + tristate "DMA controller (DMAC) support" + +config PREEMPT + bool "Preemptible Kernel (EXPERIMENTAL)" + depends on EXPERIMENTAL + +endmenu + +menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)" + +config ISA + bool + +config SBUS + bool + +config PCI + bool "PCI support" + help + Find out whether you have a PCI motherboard. PCI is the name of a + bus system, i.e. the way the CPU talks to the other stuff inside + your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or + VESA. If you have PCI, say Y, otherwise N. + + The PCI-HOWTO, available from + , contains valuable + information about which PCI hardware does work under Linux and which + doesn't. + +config SH_PCIDMA_NONCOHERENT + bool "Cache and PCI noncoherent" + depends on PCI + default y + help + Enable this option if your platform does not have a CPU cache which + remains coherent with PCI DMA. It is safest to say 'Y', although you + will see better performance if you can say 'N', because the PCI DMA + code will not have to flush the CPU's caches. If you have a PCI host + bridge integrated with your SH CPU, refer carefully to the chip specs + to see if you can say 'N' here. Otherwise, leave it as 'Y'. + +source "drivers/pci/Kconfig" + +source "drivers/pcmcia/Kconfig" + +source "drivers/pci/hotplug/Kconfig" + +endmenu + +menu "Executable file formats" + +source "fs/Kconfig.binfmt" + +endmenu + +source "drivers/Kconfig" + +source "fs/Kconfig" + +source "arch/sh64/oprofile/Kconfig" + +menu "Kernel hacking" + +config MAGIC_SYSRQ + bool "Magic SysRq key" + help + If you say Y here, you will have some control over the system even + if the system crashes for example during kernel debugging (e.g., you + will be able to flush the buffer cache to disk, reboot the system + immediately or dump some status information). This is accomplished + by pressing various keys while holding SysRq (Alt+PrintScreen). It + also works on a serial console (on PC hardware at least), if you + send a BREAK and then within 5 seconds a command keypress. The + keys are documented in Documentation/sysrq.txt. Don't say Y unless + you really know what this hack does. + +config EARLY_PRINTK + bool "Early SCIF console support" + +config DEBUG_KERNEL_WITH_GDB_STUB + bool "GDB Stub kernel debug" + +config SH64_PROC_TLB + bool "Debug: report TLB fill/purge activity through /proc/tlb" + depends on PROC_FS + +config SH64_PROC_ASIDS + bool "Debug: report ASIDs through /proc/asids" + depends on PROC_FS + +config SH64_SR_WATCH + bool "Debug: set SR.WATCH to enable hardware watchpoints and trace" + +config SH_ALPHANUMERIC + bool "Enable debug outputs to on-board alphanumeric display" + +config SH_NO_BSS_INIT + bool "Avoid zeroing BSS (to speed-up startup on suitable platforms)" + +config FRAME_POINTER + bool "Compile the kernel with frame pointers" + default y if KGDB + help + If you say Y here the resulting kernel image will be slightly larger + and slower, but it will give very useful debugging information. + If you don't debug the kernel, you can say N, but we may not be able + to solve problems without frame pointers. + +endmenu + +source "security/Kconfig" + +source "crypto/Kconfig" + +source "lib/Kconfig" + diff -puN /dev/null arch/sh64/kernel/alphanum.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/kernel/alphanum.c 2004-06-28 13:30:30.640145832 -0700 @@ -0,0 +1,45 @@ +/* + * arch/sh64/kernel/alpanum.c + * + * Copyright (C) 2002 Stuart Menefy + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * Machine-independent functions for handling 8-digit alphanumeric display + * (e.g. Agilent HDSP-253x) + */ +#include +#include +#include + +void mach_alphanum(int pos, unsigned char val); +void mach_led(int pos, int val); + +void print_seg(char *file, int line) +{ + int i; + unsigned int nibble; + + for (i = 0; i < 5; i++) { + mach_alphanum(i, file[i]); + } + + for (i = 0; i < 3; i++) { + nibble = ((line >> (i * 4)) & 0xf); + mach_alphanum(7 - i, nibble + ((nibble > 9) ? 55 : 48)); + } +} + +void print_seg_num(unsigned num) +{ + int i; + unsigned int nibble; + + for (i = 0; i < 8; i++) { + nibble = ((num >> (i * 4)) & 0xf); + + mach_alphanum(7 - i, nibble + ((nibble > 9) ? 55 : 48)); + } +} + diff -puN /dev/null arch/sh64/kernel/asm-offsets.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/kernel/asm-offsets.c 2004-06-28 13:30:30.641145680 -0700 @@ -0,0 +1,33 @@ +/* + * This program is used to generate definitions needed by + * assembly language modules. + * + * We use the technique used in the OSF Mach kernel code: + * generate asm statements containing #defines, + * compile this file to assembler, and then extract the + * #defines from the assembly-language output. + */ + +#include +#include +#include +#include + +#define DEFINE(sym, val) \ + asm volatile("\n->" #sym " %0 " #val : : "i" (val)) + +#define BLANK() asm volatile("\n->" : : ) + +int main(void) +{ + /* offsets into the thread_info struct */ + DEFINE(TI_TASK, offsetof(struct thread_info, task)); + DEFINE(TI_EXEC_DOMAIN, offsetof(struct thread_info, exec_domain)); + DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); + DEFINE(TI_PRE_COUNT, offsetof(struct thread_info, preempt_count)); + DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); + DEFINE(TI_ADDR_LIMIT, offsetof(struct thread_info, addr_limit)); + DEFINE(TI_RESTART_BLOCK,offsetof(struct thread_info, restart_block)); + + return 0; +} diff -puN /dev/null arch/sh64/kernel/dma.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/kernel/dma.c 2004-06-28 13:30:30.642145528 -0700 @@ -0,0 +1,297 @@ +/* + * arch/sh64/kernel/dma.c + * + * DMA routines for the SH-5 DMAC. + * + * Copyright (C) 2003 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + unsigned long dev_addr; + unsigned long mem_addr; + + unsigned int mode; + unsigned int count; +} dma_info_t; + +static dma_info_t dma_info[MAX_DMA_CHANNELS]; +extern spinlock_t dma_spin_lock; + +/* arch/sh64/kernel/irq_intc.c */ +extern void make_intc_irq(unsigned int irq); + +/* DMAC Interrupts */ +#define DMA_IRQ_DMTE0 18 +#define DMA_IRQ_DERR 22 + +#define DMAC_COMMON_BASE (dmac_base + 0x08) +#define DMAC_SAR_BASE (dmac_base + 0x10) +#define DMAC_DAR_BASE (dmac_base + 0x18) +#define DMAC_COUNT_BASE (dmac_base + 0x20) +#define DMAC_CTRL_BASE (dmac_base + 0x28) +#define DMAC_STATUS_BASE (dmac_base + 0x30) + +#define DMAC_SAR(n) (DMAC_SAR_BASE + ((n) * 0x28)) +#define DMAC_DAR(n) (DMAC_DAR_BASE + ((n) * 0x28)) +#define DMAC_COUNT(n) (DMAC_COUNT_BASE + ((n) * 0x28)) +#define DMAC_CTRL(n) (DMAC_CTRL_BASE + ((n) * 0x28)) +#define DMAC_STATUS(n) (DMAC_STATUS_BASE + ((n) * 0x28)) + +/* DMAC.COMMON Bit Definitions */ +#define DMAC_COMMON_PR 0x00000001 /* Priority */ + /* Bits 1-2 Reserved */ +#define DMAC_COMMON_ME 0x00000008 /* Master Enable */ +#define DMAC_COMMON_NMI 0x00000010 /* NMI Flag */ + /* Bits 5-6 Reserved */ +#define DMAC_COMMON_ER 0x00000780 /* Error Response */ +#define DMAC_COMMON_AAE 0x00007800 /* Address Alignment Error */ + /* Bits 15-63 Reserved */ + +/* DMAC.SAR Bit Definitions */ +#define DMAC_SAR_ADDR 0xffffffff /* Source Address */ + +/* DMAC.DAR Bit Definitions */ +#define DMAC_DAR_ADDR 0xffffffff /* Destination Address */ + +/* DMAC.COUNT Bit Definitions */ +#define DMAC_COUNT_CNT 0xffffffff /* Transfer Count */ + +/* DMAC.CTRL Bit Definitions */ +#define DMAC_CTRL_TS 0x00000007 /* Transfer Size */ +#define DMAC_CTRL_SI 0x00000018 /* Source Increment */ +#define DMAC_CTRL_DI 0x00000060 /* Destination Increment */ +#define DMAC_CTRL_RS 0x00000780 /* Resource Select */ +#define DMAC_CTRL_IE 0x00000800 /* Interrupt Enable */ +#define DMAC_CTRL_TE 0x00001000 /* Transfer Enable */ + /* Bits 15-63 Reserved */ + +/* DMAC.STATUS Bit Definitions */ +#define DMAC_STATUS_TE 0x00000001 /* Transfer End */ +#define DMAC_STATUS_AAE 0x00000002 /* Address Alignment Error */ + /* Bits 2-63 Reserved */ + +static unsigned long dmac_base; + +void set_dma_count(unsigned int chan, unsigned int count); +void set_dma_addr(unsigned int chan, unsigned int addr); + +static irqreturn_t dma_mte(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned int chan = irq - DMA_IRQ_DMTE0; + dma_info_t *info = dma_info + chan; + u64 status; + + if (info->mode & DMA_MODE_WRITE) { + sh64_out64(info->mem_addr & DMAC_SAR_ADDR, DMAC_SAR(chan)); + } else { + sh64_out64(info->mem_addr & DMAC_DAR_ADDR, DMAC_DAR(chan)); + } + + set_dma_count(chan, info->count); + + /* Clear the TE bit */ + status = sh64_in64(DMAC_STATUS(chan)); + status &= ~DMAC_STATUS_TE; + sh64_out64(status, DMAC_STATUS(chan)); + + return IRQ_HANDLED; +} + +static struct irqaction irq_dmte = { + .handler = dma_mte, + .flags = SA_INTERRUPT, + .name = "DMA MTE", +}; + +static irqreturn_t dma_err(int irq, void *dev_id, struct pt_regs *regs) +{ + u64 tmp; + u8 chan; + + printk(KERN_NOTICE "DMAC: Got a DMA Error!\n"); + + tmp = sh64_in64(DMAC_COMMON_BASE); + + /* Check for the type of error */ + if ((chan = tmp & DMAC_COMMON_AAE)) { + /* It's an address alignment error.. */ + printk(KERN_NOTICE "DMAC: Alignment error on channel %d, ", chan); + + printk(KERN_NOTICE "SAR: 0x%08llx, DAR: 0x%08llx, COUNT: %lld\n", + (sh64_in64(DMAC_SAR(chan)) & DMAC_SAR_ADDR), + (sh64_in64(DMAC_DAR(chan)) & DMAC_DAR_ADDR), + (sh64_in64(DMAC_COUNT(chan)) & DMAC_COUNT_CNT)); + + } else if ((chan = tmp & DMAC_COMMON_ER)) { + /* Something else went wrong.. */ + printk(KERN_NOTICE "DMAC: Error on channel %d\n", chan); + } + + /* Reset the ME bit to clear the interrupt */ + tmp |= DMAC_COMMON_ME; + sh64_out64(tmp, DMAC_COMMON_BASE); + + return IRQ_HANDLED; +} + +static struct irqaction irq_derr = { + .handler = dma_err, + .flags = SA_INTERRUPT, + .name = "DMA Error", +}; + +static inline unsigned long calc_xmit_shift(unsigned int chan) +{ + return sh64_in64(DMAC_CTRL(chan)) & 0x03; +} + +void setup_dma(unsigned int chan, dma_info_t *info) +{ + unsigned int irq = DMA_IRQ_DMTE0 + chan; + dma_info_t *dma = dma_info + chan; + + make_intc_irq(irq); + setup_irq(irq, &irq_dmte); + dma = info; +} + +void enable_dma(unsigned int chan) +{ + u64 ctrl; + + ctrl = sh64_in64(DMAC_CTRL(chan)); + ctrl |= DMAC_CTRL_TE; + sh64_out64(ctrl, DMAC_CTRL(chan)); +} + +void disable_dma(unsigned int chan) +{ + u64 ctrl; + + ctrl = sh64_in64(DMAC_CTRL(chan)); + ctrl &= ~DMAC_CTRL_TE; + sh64_out64(ctrl, DMAC_CTRL(chan)); +} + +void set_dma_mode(unsigned int chan, char mode) +{ + dma_info_t *info = dma_info + chan; + + info->mode = mode; + + set_dma_addr(chan, info->mem_addr); + set_dma_count(chan, info->count); +} + +void set_dma_addr(unsigned int chan, unsigned int addr) +{ + dma_info_t *info = dma_info + chan; + unsigned long sar, dar; + + info->mem_addr = addr; + sar = (info->mode & DMA_MODE_WRITE) ? info->mem_addr : info->dev_addr; + dar = (info->mode & DMA_MODE_WRITE) ? info->dev_addr : info->mem_addr; + + sh64_out64(sar & DMAC_SAR_ADDR, DMAC_SAR(chan)); + sh64_out64(dar & DMAC_SAR_ADDR, DMAC_DAR(chan)); +} + +void set_dma_count(unsigned int chan, unsigned int count) +{ + dma_info_t *info = dma_info + chan; + u64 tmp; + + info->count = count; + + tmp = (info->count >> calc_xmit_shift(chan)) & DMAC_COUNT_CNT; + + sh64_out64(tmp, DMAC_COUNT(chan)); +} + +unsigned long claim_dma_lock(void) +{ + unsigned long flags; + + spin_lock_irqsave(&dma_spin_lock, flags); + + return flags; +} + +void release_dma_lock(unsigned long flags) +{ + spin_unlock_irqrestore(&dma_spin_lock, flags); +} + +int get_dma_residue(unsigned int chan) +{ + return sh64_in64(DMAC_COUNT(chan) << calc_xmit_shift(chan)); +} + +int __init init_dma(void) +{ + struct vcr_info vcr; + u64 tmp; + + /* Remap the DMAC */ + dmac_base = onchip_remap(PHYS_DMAC_BLOCK, 1024, "DMAC"); + if (!dmac_base) { + printk(KERN_ERR "Unable to remap DMAC\n"); + return -ENOMEM; + } + + /* Report DMAC.VCR Info */ + vcr = sh64_get_vcr_info(dmac_base); + printk("DMAC: Module ID: 0x%04x, Module version: 0x%04x\n", + vcr.mod_id, vcr.mod_vers); + + /* Set the ME bit */ + tmp = sh64_in64(DMAC_COMMON_BASE); + tmp |= DMAC_COMMON_ME; + sh64_out64(tmp, DMAC_COMMON_BASE); + + /* Enable the DMAC Error Interrupt */ + make_intc_irq(DMA_IRQ_DERR); + setup_irq(DMA_IRQ_DERR, &irq_derr); + + return 0; +} + +static void __exit exit_dma(void) +{ + onchip_unmap(dmac_base); + free_irq(DMA_IRQ_DERR, 0); +} + +module_init(init_dma); +module_exit(exit_dma); + +MODULE_AUTHOR("Paul Mundt"); +MODULE_DESCRIPTION("DMA API for SH-5 DMAC"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(setup_dma); +EXPORT_SYMBOL(claim_dma_lock); +EXPORT_SYMBOL(release_dma_lock); +EXPORT_SYMBOL(enable_dma); +EXPORT_SYMBOL(disable_dma); +EXPORT_SYMBOL(set_dma_mode); +EXPORT_SYMBOL(set_dma_addr); +EXPORT_SYMBOL(set_dma_count); +EXPORT_SYMBOL(get_dma_residue); + diff -puN /dev/null arch/sh64/kernel/early_printk.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/kernel/early_printk.c 2004-06-28 13:30:30.643145376 -0700 @@ -0,0 +1,107 @@ +/* + * arch/sh64/kernel/early_printk.c + * + * SH-5 Early SCIF console (cloned and hacked from sh implementation) + * + * Copyright (C) 2003, 2004 Paul Mundt + * Copyright (C) 2002 M. R. Brown + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include +#include +#include + +extern void cpu_relax(void); + +#define SCIF_BASE_ADDR 0x01030000 +#define SCIF_ADDR_SH5 PHYS_PERIPHERAL_BLOCK+SCIF_BASE_ADDR + +/* + * Fixed virtual address where SCIF is mapped (should already be done + * in arch/sh64/kernel/head.S!). + */ +#define SCIF_REG 0xfa030000 + +enum { + SCIF_SCSMR2 = SCIF_REG + 0x00, + SCIF_SCBRR2 = SCIF_REG + 0x04, + SCIF_SCSCR2 = SCIF_REG + 0x08, + SCIF_SCFTDR2 = SCIF_REG + 0x0c, + SCIF_SCFSR2 = SCIF_REG + 0x10, + SCIF_SCFRDR2 = SCIF_REG + 0x14, + SCIF_SCFCR2 = SCIF_REG + 0x18, + SCIF_SCFDR2 = SCIF_REG + 0x1c, + SCIF_SCSPTR2 = SCIF_REG + 0x20, + SCIF_SCLSR2 = SCIF_REG + 0x24, +}; + +static void sh_console_putc(int c) +{ + while (!(ctrl_inw(SCIF_SCFSR2) & 0x20)) + cpu_relax(); + + ctrl_outb(c, SCIF_SCFTDR2); + ctrl_outw((ctrl_inw(SCIF_SCFSR2) & 0x9f), SCIF_SCFSR2); + + if (c == '\n') + sh_console_putc('\r'); +} + +static void sh_console_flush(void) +{ + ctrl_outw((ctrl_inw(SCIF_SCFSR2) & 0xbf), SCIF_SCFSR2); + + while (!(ctrl_inw(SCIF_SCFSR2) & 0x40)) + cpu_relax(); + + ctrl_outw((ctrl_inw(SCIF_SCFSR2) & 0xbf), SCIF_SCFSR2); +} + +static void sh_console_write(struct console *con, const char *s, unsigned count) +{ + while (count-- > 0) + sh_console_putc(*s++); + + sh_console_flush(); +} + +static int __init sh_console_setup(struct console *con, char *options) +{ + con->cflag = CREAD | HUPCL | CLOCAL | B19200 | CS8; + + return 0; +} + +static struct console sh_console = { + .name = "scifcon", + .write = sh_console_write, + .setup = sh_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, +}; + +void __init enable_early_printk(void) +{ + ctrl_outb(0x2a, SCIF_SCBRR2); /* 19200bps */ + + ctrl_outw(0x04, SCIF_SCFCR2); /* Reset TFRST */ + ctrl_outw(0x10, SCIF_SCFCR2); /* TTRG0=1 */ + + ctrl_outw(0, SCIF_SCSPTR2); + ctrl_outw(0x60, SCIF_SCFSR2); + ctrl_outw(0, SCIF_SCLSR2); + ctrl_outw(0x30, SCIF_SCSCR2); + + register_console(&sh_console); +} + +void disable_early_printk(void) +{ + unregister_console(&sh_console); +} + diff -puN /dev/null arch/sh64/kernel/entry.S --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/kernel/entry.S 2004-06-28 13:30:30.651144160 -0700 @@ -0,0 +1,2101 @@ +/* + * 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. + * + * arch/sh64/kernel/entry.S + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2004 Paul Mundt + * Copyright (C) 2003, 2004 Richard Curnow + * + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * SR fields. + */ +#define SR_ASID_MASK 0x00ff0000 +#define SR_FD_MASK 0x00008000 +#define SR_SS 0x08000000 +#define SR_BL 0x10000000 +#define SR_MD 0x40000000 + +/* + * Event code. + */ +#define EVENT_INTERRUPT 0 +#define EVENT_FAULT_TLB 1 +#define EVENT_FAULT_NOT_TLB 2 +#define EVENT_DEBUG 3 + +/* EXPEVT values */ +#define RESET_CAUSE 0x20 +#define DEBUGSS_CAUSE 0x980 + +/* + * Frame layout. Quad index. + */ +#define FRAME_T(x) FRAME_TBASE+(x*8) +#define FRAME_R(x) FRAME_RBASE+(x*8) +#define FRAME_S(x) FRAME_SBASE+(x*8) +#define FSPC 0 +#define FSSR 1 +#define FSYSCALL_ID 2 + +/* Arrange the save frame to be a multiple of 32 bytes long */ +#define FRAME_SBASE 0 +#define FRAME_RBASE (FRAME_SBASE+(3*8)) /* SYSCALL_ID - SSR - SPC */ +#define FRAME_TBASE (FRAME_RBASE+(63*8)) /* r0 - r62 */ +#define FRAME_PBASE (FRAME_TBASE+(8*8)) /* tr0 -tr7 */ +#define FRAME_SIZE (FRAME_PBASE+(2*8)) /* pad0-pad1 */ + +#define FP_FRAME_SIZE FP_FRAME_BASE+(33*8) /* dr0 - dr31 + fpscr */ +#define FP_FRAME_BASE 0 + +#define SAVED_R2 0*8 +#define SAVED_R3 1*8 +#define SAVED_R4 2*8 +#define SAVED_R5 3*8 +#define SAVED_R18 4*8 +#define SAVED_R6 5*8 +#define SAVED_TR0 6*8 + +/* These are the registers saved in the TLB path that aren't saved in the first + level of the normal one. */ +#define TLB_SAVED_R25 7*8 +#define TLB_SAVED_TR1 8*8 +#define TLB_SAVED_TR2 9*8 +#define TLB_SAVED_TR3 10*8 +#define TLB_SAVED_TR4 11*8 +/* Save R0/R1 : PT-migrating compiler currently dishounours -ffixed-r0 and -ffixed-r1 causing + breakage otherwise. */ +#define TLB_SAVED_R0 12*8 +#define TLB_SAVED_R1 13*8 + +#define CLI() \ + getcon SR, r6; \ + ori r6, 0xf0, r6; \ + putcon r6, SR; + +#define STI() \ + getcon SR, r6; \ + andi r6, ~0xf0, r6; \ + putcon r6, SR; + +#ifdef CONFIG_PREEMPT +# define preempt_stop() CLI() +#else +# define preempt_stop() +# define resume_kernel restore_all +#endif + + .section .data, "aw" + +#define FAST_TLBMISS_STACK_CACHELINES 4 +#define FAST_TLBMISS_STACK_QUADWORDS (4*FAST_TLBMISS_STACK_CACHELINES) + +/* Register back-up area for all exceptions */ + .balign 32 + /* Allow for 16 quadwords to be pushed by fast tlbmiss handling + * register saves etc. */ + .fill FAST_TLBMISS_STACK_QUADWORDS, 8, 0x0 +/* This is 32 byte aligned by construction */ +/* Register back-up area for all exceptions */ +reg_save_area: + .quad 0 + .quad 0 + .quad 0 + .quad 0 + + .quad 0 + .quad 0 + .quad 0 + .quad 0 + + .quad 0 + .quad 0 + .quad 0 + .quad 0 + + .quad 0 + .quad 0 + +/* Save area for RESVEC exceptions. We cannot use reg_save_area because of + * reentrancy. Note this area may be accessed via physical address. + * Align so this fits a whole single cache line, for ease of purging. + */ + .balign 32,0,32 +resvec_save_area: + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .balign 32,0,32 + +/* Jump table of 3rd level handlers */ +trap_jtable: + .long do_exception_error /* 0x000 */ + .long do_exception_error /* 0x020 */ + .long tlb_miss_load /* 0x040 */ + .long tlb_miss_store /* 0x060 */ + ! ARTIFICIAL pseudo-EXPEVT setting + .long do_debug_interrupt /* 0x080 */ + .long tlb_miss_load /* 0x0A0 */ + .long tlb_miss_store /* 0x0C0 */ + .long do_address_error_load /* 0x0E0 */ + .long do_address_error_store /* 0x100 */ +#ifndef CONFIG_NOFPU_SUPPORT + .long do_fpu_error /* 0x120 */ +#else + .long do_exception_error /* 0x120 */ +#endif + .long do_exception_error /* 0x140 */ + .long system_call /* 0x160 */ + .long do_reserved_inst /* 0x180 */ + .long do_illegal_slot_inst /* 0x1A0 */ + .long do_NMI /* 0x1C0 */ + .long do_exception_error /* 0x1E0 */ + .rept 15 + .long do_IRQ /* 0x200 - 0x3C0 */ + .endr + .long do_exception_error /* 0x3E0 */ + .rept 32 + .long do_IRQ /* 0x400 - 0x7E0 */ + .endr + .long fpu_error_or_IRQA /* 0x800 */ + .long fpu_error_or_IRQB /* 0x820 */ + .long do_IRQ /* 0x840 */ + .long do_IRQ /* 0x860 */ + .rept 6 + .long do_exception_error /* 0x880 - 0x920 */ + .endr + .long do_software_break_point /* 0x940 */ + .long do_exception_error /* 0x960 */ + .long do_single_step /* 0x980 */ + + .rept 3 + .long do_exception_error /* 0x9A0 - 0x9E0 */ + .endr + .long do_IRQ /* 0xA00 */ + .long do_IRQ /* 0xA20 */ + .long itlb_miss_or_IRQ /* 0xA40 */ + .long do_IRQ /* 0xA60 */ + .long do_IRQ /* 0xA80 */ + .long itlb_miss_or_IRQ /* 0xAA0 */ + .long do_exception_error /* 0xAC0 */ + .long do_address_error_exec /* 0xAE0 */ + .rept 8 + .long do_exception_error /* 0xB00 - 0xBE0 */ + .endr + .rept 18 + .long do_IRQ /* 0xC00 - 0xE20 */ + .endr + + .section .text64, "ax" + +/* + * --- Exception/Interrupt/Event Handling Section + */ + +/* + * VBR and RESVEC blocks. + * + * First level handler for VBR-based exceptions. + * + * To avoid waste of space, align to the maximum text block size. + * This is assumed to be at most 128 bytes or 32 instructions. + * DO NOT EXCEED 32 instructions on the first level handlers ! + * + * Also note that RESVEC is contained within the VBR block + * where the room left (1KB - TEXT_SIZE) allows placing + * the RESVEC block (at most 512B + TEXT_SIZE). + * + * So first (and only) level handler for RESVEC-based exceptions. + * + * Where the fault/interrupt is handled (not_a_tlb_miss, tlb_miss + * and interrupt) we are a lot tight with register space until + * saving onto the stack frame, which is done in handle_exception(). + * + */ + +#define TEXT_SIZE 128 +#define BLOCK_SIZE 1664 /* Dynamic check, 13*128 */ + + .balign TEXT_SIZE +LVBR_block: + .space 256, 0 /* Power-on class handler, */ + /* not required here */ +not_a_tlb_miss: + /* Save original stack pointer into KCR1 */ + putcon SP, KCR1 + + /* Save other original registers into reg_save_area */ + movi reg_save_area, SP + st.q SP, SAVED_R2, r2 + st.q SP, SAVED_R3, r3 + st.q SP, SAVED_R4, r4 + st.q SP, SAVED_R5, r5 + st.q SP, SAVED_R6, r6 + st.q SP, SAVED_R18, r18 + gettr tr0, r3 + st.q SP, SAVED_TR0, r3 + + /* Set args for Non-debug, Not a TLB miss class handler */ + getcon EXPEVT, r2 + movi ret_from_exception, r3 + ori r3, 1, r3 + movi EVENT_FAULT_NOT_TLB, r4 + or SP, ZERO, r5 + getcon KCR1, SP + pta handle_exception, tr0 + blink tr0, ZERO + + .balign 256 + ! VBR+0x200 + nop + .balign 256 + ! VBR+0x300 + nop + .balign 256 + /* + * Instead of the natural .balign 1024 place RESVEC here + * respecting the final 1KB alignment. + */ + .balign TEXT_SIZE + /* + * Instead of '.space 1024-TEXT_SIZE' place the RESVEC + * block making sure the final alignment is correct. + */ +tlb_miss: + putcon SP, KCR1 + movi reg_save_area, SP + /* SP is guaranteed 32-byte aligned. */ + st.q SP, TLB_SAVED_R0 , r0 + st.q SP, TLB_SAVED_R1 , r1 + st.q SP, SAVED_R2 , r2 + st.q SP, SAVED_R3 , r3 + st.q SP, SAVED_R4 , r4 + st.q SP, SAVED_R5 , r5 + st.q SP, SAVED_R6 , r6 + st.q SP, SAVED_R18, r18 + + /* Save R25 for safety; as/ld may want to use it to achieve the call to + * the code in mm/tlbmiss.c */ + st.q SP, TLB_SAVED_R25, r25 + gettr tr0, r2 + gettr tr1, r3 + gettr tr2, r4 + gettr tr3, r5 + gettr tr4, r18 + st.q SP, SAVED_TR0 , r2 + st.q SP, TLB_SAVED_TR1 , r3 + st.q SP, TLB_SAVED_TR2 , r4 + st.q SP, TLB_SAVED_TR3 , r5 + st.q SP, TLB_SAVED_TR4 , r18 + + pt do_fast_page_fault, tr0 + getcon SSR, r2 + getcon EXPEVT, r3 + getcon TEA, r4 + shlri r2, 30, r2 + andi r2, 1, r2 /* r2 = SSR.MD */ + blink tr0, LINK + + pt fixup_to_invoke_general_handler, tr1 + + /* If the fast path handler fixed the fault, just drop through quickly + to the restore code right away to return to the excepting context. + */ + beqi/u r2, 0, tr1 + +fast_tlb_miss_restore: + ld.q SP, SAVED_TR0, r2 + ld.q SP, TLB_SAVED_TR1, r3 + ld.q SP, TLB_SAVED_TR2, r4 + + ld.q SP, TLB_SAVED_TR3, r5 + ld.q SP, TLB_SAVED_TR4, r18 + + ptabs r2, tr0 + ptabs r3, tr1 + ptabs r4, tr2 + ptabs r5, tr3 + ptabs r18, tr4 + + ld.q SP, TLB_SAVED_R0, r0 + ld.q SP, TLB_SAVED_R1, r1 + ld.q SP, SAVED_R2, r2 + ld.q SP, SAVED_R3, r3 + ld.q SP, SAVED_R4, r4 + ld.q SP, SAVED_R5, r5 + ld.q SP, SAVED_R6, r6 + ld.q SP, SAVED_R18, r18 + ld.q SP, TLB_SAVED_R25, r25 + + getcon KCR1, SP + rte + nop /* for safety, in case the code is run on sh5-101 cut1.x */ + +fixup_to_invoke_general_handler: + + /* OK, new method. Restore stuff that's not expected to get saved into + the 'first-level' reg save area, then just fall through to setting + up the registers and calling the second-level handler. */ + + /* 2nd level expects r2,3,4,5,6,18,tr0 to be saved. So we must restore + r25,tr1-4 and save r6 to get into the right state. */ + + ld.q SP, TLB_SAVED_TR1, r3 + ld.q SP, TLB_SAVED_TR2, r4 + ld.q SP, TLB_SAVED_TR3, r5 + ld.q SP, TLB_SAVED_TR4, r18 + ld.q SP, TLB_SAVED_R25, r25 + + ld.q SP, TLB_SAVED_R0, r0 + ld.q SP, TLB_SAVED_R1, r1 + + ptabs/u r3, tr1 + ptabs/u r4, tr2 + ptabs/u r5, tr3 + ptabs/u r18, tr4 + + /* Set args for Non-debug, TLB miss class handler */ + getcon EXPEVT, r2 + movi ret_from_exception, r3 + ori r3, 1, r3 + movi EVENT_FAULT_TLB, r4 + or SP, ZERO, r5 + getcon KCR1, SP + pta handle_exception, tr0 + blink tr0, ZERO + +/* NB TAKE GREAT CARE HERE TO ENSURE THAT THE INTERRUPT CODE + DOES END UP AT VBR+0x600 */ + nop + nop + nop + nop + nop + nop + + .balign 256 + /* VBR + 0x600 */ + +interrupt: + /* Save original stack pointer into KCR1 */ + putcon SP, KCR1 + + /* Save other original registers into reg_save_area */ + movi reg_save_area, SP + st.q SP, SAVED_R2, r2 + st.q SP, SAVED_R3, r3 + st.q SP, SAVED_R4, r4 + st.q SP, SAVED_R5, r5 + st.q SP, SAVED_R6, r6 + st.q SP, SAVED_R18, r18 + gettr tr0, r3 + st.q SP, SAVED_TR0, r3 + + /* Set args for interrupt class handler */ + getcon INTEVT, r2 + movi ret_from_irq, r3 + ori r3, 1, r3 + movi EVENT_INTERRUPT, r4 + or SP, ZERO, r5 + getcon KCR1, SP + pta handle_exception, tr0 + blink tr0, ZERO + .balign TEXT_SIZE /* let's waste the bare minimum */ + +LVBR_block_end: /* Marker. Used for total checking */ + + .balign 256 +LRESVEC_block: + /* Panic handler. Called with MMU off. Possible causes/actions: + * - Reset: Jump to program start. + * - Single Step: Turn off Single Step & return. + * - Others: Call panic handler, passing PC as arg. + * (this may need to be extended...) + */ +reset_or_panic: + putcon SP, DCR + /* First save r0-1 and tr0, as we need to use these */ + movi resvec_save_area-CONFIG_CACHED_MEMORY_OFFSET, SP + st.q SP, 0, r0 + st.q SP, 8, r1 + gettr tr0, r0 + st.q SP, 32, r0 + + /* Check cause */ + getcon EXPEVT, r0 + movi RESET_CAUSE, r1 + sub r1, r0, r1 /* r1=0 if reset */ + movi _stext-CONFIG_CACHED_MEMORY_OFFSET, r0 + ori r0, 1, r0 + ptabs r0, tr0 + beqi r1, 0, tr0 /* Jump to start address if reset */ + + getcon EXPEVT, r0 + movi DEBUGSS_CAUSE, r1 + sub r1, r0, r1 /* r1=0 if single step */ + pta single_step_panic, tr0 + beqi r1, 0, tr0 /* jump if single step */ + + /* Now jump to where we save the registers. */ + movi panic_stash_regs-CONFIG_CACHED_MEMORY_OFFSET, r1 + ptabs r1, tr0 + blink tr0, r63 + +single_step_panic: + /* We are in a handler with Single Step set. We need to resume the + * handler, by turning on MMU & turning off Single Step. */ + getcon SSR, r0 + movi SR_MMU, r1 + or r0, r1, r0 + movi ~SR_SS, r1 + and r0, r1, r0 + putcon r0, SSR + /* Restore EXPEVT, as the rte won't do this */ + getcon PEXPEVT, r0 + putcon r0, EXPEVT + /* Restore regs */ + ld.q SP, 32, r0 + ptabs r0, tr0 + ld.q SP, 0, r0 + ld.q SP, 8, r1 + getcon DCR, SP + synco + rte + + + .balign 256 +debug_exception: + /* + * Single step/software_break_point first level handler. + * Called with MMU off, so the first thing we do is enable it + * by doing an rte with appropriate SSR. + */ + putcon SP, DCR + /* Save SSR & SPC, together with R0 & R1, as we need to use 2 regs. */ + movi resvec_save_area-CONFIG_CACHED_MEMORY_OFFSET, SP + + /* With the MMU off, we are bypassing the cache, so purge any + * data that will be made stale by the following stores. + */ + ocbp SP, 0 + synco + + st.q SP, 0, r0 + st.q SP, 8, r1 + getcon SPC, r0 + st.q SP, 16, r0 + getcon SSR, r0 + st.q SP, 24, r0 + + /* Enable MMU, block exceptions, set priv mode, disable single step */ + movi SR_MMU | SR_BL | SR_MD, r1 + or r0, r1, r0 + movi ~SR_SS, r1 + and r0, r1, r0 + putcon r0, SSR + /* Force control to debug_exception_2 when rte is executed */ + movi debug_exeception_2, r0 + ori r0, 1, r0 /* force SHmedia, just in case */ + putcon r0, SPC + getcon DCR, SP + synco + rte +debug_exeception_2: + /* Restore saved regs */ + putcon SP, KCR1 + movi resvec_save_area, SP + ld.q SP, 24, r0 + putcon r0, SSR + ld.q SP, 16, r0 + putcon r0, SPC + ld.q SP, 0, r0 + ld.q SP, 8, r1 + + /* Save other original registers into reg_save_area */ + movi reg_save_area, SP + st.q SP, SAVED_R2, r2 + st.q SP, SAVED_R3, r3 + st.q SP, SAVED_R4, r4 + st.q SP, SAVED_R5, r5 + st.q SP, SAVED_R6, r6 + st.q SP, SAVED_R18, r18 + gettr tr0, r3 + st.q SP, SAVED_TR0, r3 + + /* Set args for debug class handler */ + getcon EXPEVT, r2 + movi ret_from_exception, r3 + ori r3, 1, r3 + movi EVENT_DEBUG, r4 + or SP, ZERO, r5 + getcon KCR1, SP + pta handle_exception, tr0 + blink tr0, ZERO + + .balign 256 +debug_interrupt: + /* !!! WE COME HERE IN REAL MODE !!! */ + /* Hook-up debug interrupt to allow various debugging options to be + * hooked into its handler. */ + /* Save original stack pointer into KCR1 */ + synco + putcon SP, KCR1 + movi resvec_save_area-CONFIG_CACHED_MEMORY_OFFSET, SP + ocbp SP, 0 + ocbp SP, 32 + synco + + /* Save other original registers into reg_save_area thru real addresses */ + st.q SP, SAVED_R2, r2 + st.q SP, SAVED_R3, r3 + st.q SP, SAVED_R4, r4 + st.q SP, SAVED_R5, r5 + st.q SP, SAVED_R6, r6 + st.q SP, SAVED_R18, r18 + gettr tr0, r3 + st.q SP, SAVED_TR0, r3 + + /* move (spc,ssr)->(pspc,pssr). The rte will shift + them back again, so that they look like the originals + as far as the real handler code is concerned. */ + getcon spc, r6 + putcon r6, pspc + getcon ssr, r6 + putcon r6, pssr + + ! construct useful SR for handle_exception + movi 3, r6 + shlli r6, 30, r6 + getcon sr, r18 + or r18, r6, r6 + putcon r6, ssr + + ! SSR is now the current SR with the MD and MMU bits set + ! i.e. the rte will switch back to priv mode and put + ! the mmu back on + + ! construct spc + movi handle_exception, r18 + ori r18, 1, r18 ! for safety (do we need this?) + putcon r18, spc + + /* Set args for Non-debug, Not a TLB miss class handler */ + + ! EXPEVT==0x80 is unused, so 'steal' this value to put the + ! debug interrupt handler in the vectoring table + movi 0x80, r2 + movi ret_from_exception, r3 + ori r3, 1, r3 + movi EVENT_FAULT_NOT_TLB, r4 + + or SP, ZERO, r5 + movi CONFIG_CACHED_MEMORY_OFFSET, r6 + add r6, r5, r5 + getcon KCR1, SP + + synco ! for safety + rte ! -> handle_exception, switch back to priv mode again + +LRESVEC_block_end: /* Marker. Unused. */ + + .balign TEXT_SIZE + +/* + * Second level handler for VBR-based exceptions. Pre-handler. + * In common to all stack-frame sensitive handlers. + * + * Inputs: + * (KCR0) Current [current task union] + * (KCR1) Original SP + * (r2) INTEVT/EXPEVT + * (r3) appropriate return address + * (r4) Event (0 = interrupt, 1 = TLB miss fault, 2 = Not TLB miss fault, 3=debug) + * (r5) Pointer to reg_save_area + * (SP) Original SP + * + * Available registers: + * (r6) + * (r18) + * (tr0) + * + */ +handle_exception: + /* Common 2nd level handler. */ + + /* First thing we need an appropriate stack pointer */ + getcon SSR, r6 + shlri r6, 30, r6 + andi r6, 1, r6 + pta stack_ok, tr0 + bne r6, ZERO, tr0 /* Original stack pointer is fine */ + + /* Set stack pointer for user fault */ + getcon KCR0, SP + movi THREAD_SIZE, r6 /* Point to the end */ + add SP, r6, SP + +stack_ok: + +/* DEBUG : check for underflow/overflow of the kernel stack */ + pta no_underflow, tr0 + getcon KCR0, r6 + movi 1024, r18 + add r6, r18, r6 + bge SP, r6, tr0 ! ? below 1k from bottom of stack : danger zone + +/* Just panic to cause a crash. */ +bad_sp: + ld.b r63, 0, r6 + nop + +no_underflow: + pta bad_sp, tr0 + getcon kcr0, r6 + movi THREAD_SIZE, r18 + add r18, r6, r6 + bgt SP, r6, tr0 ! sp above the stack + + /* Make some room for the BASIC frame. */ + movi -(FRAME_SIZE), r6 + add SP, r6, SP + +/* Could do this with no stalling if we had another spare register, but the + code below will be OK. */ + ld.q r5, SAVED_R2, r6 + ld.q r5, SAVED_R3, r18 + st.q SP, FRAME_R(2), r6 + ld.q r5, SAVED_R4, r6 + st.q SP, FRAME_R(3), r18 + ld.q r5, SAVED_R5, r18 + st.q SP, FRAME_R(4), r6 + ld.q r5, SAVED_R6, r6 + st.q SP, FRAME_R(5), r18 + ld.q r5, SAVED_R18, r18 + st.q SP, FRAME_R(6), r6 + ld.q r5, SAVED_TR0, r6 + st.q SP, FRAME_R(18), r18 + st.q SP, FRAME_T(0), r6 + + /* Keep old SP around */ + getcon KCR1, r6 + + /* Save the rest of the general purpose registers */ + st.q SP, FRAME_R(0), r0 + st.q SP, FRAME_R(1), r1 + st.q SP, FRAME_R(7), r7 + st.q SP, FRAME_R(8), r8 + st.q SP, FRAME_R(9), r9 + st.q SP, FRAME_R(10), r10 + st.q SP, FRAME_R(11), r11 + st.q SP, FRAME_R(12), r12 + st.q SP, FRAME_R(13), r13 + st.q SP, FRAME_R(14), r14 + + /* SP is somewhere else */ + st.q SP, FRAME_R(15), r6 + + st.q SP, FRAME_R(16), r16 + st.q SP, FRAME_R(17), r17 + /* r18 is saved earlier. */ + st.q SP, FRAME_R(19), r19 + st.q SP, FRAME_R(20), r20 + st.q SP, FRAME_R(21), r21 + st.q SP, FRAME_R(22), r22 + st.q SP, FRAME_R(23), r23 + st.q SP, FRAME_R(24), r24 + st.q SP, FRAME_R(25), r25 + st.q SP, FRAME_R(26), r26 + st.q SP, FRAME_R(27), r27 + st.q SP, FRAME_R(28), r28 + st.q SP, FRAME_R(29), r29 + st.q SP, FRAME_R(30), r30 + st.q SP, FRAME_R(31), r31 + st.q SP, FRAME_R(32), r32 + st.q SP, FRAME_R(33), r33 + st.q SP, FRAME_R(34), r34 + st.q SP, FRAME_R(35), r35 + st.q SP, FRAME_R(36), r36 + st.q SP, FRAME_R(37), r37 + st.q SP, FRAME_R(38), r38 + st.q SP, FRAME_R(39), r39 + st.q SP, FRAME_R(40), r40 + st.q SP, FRAME_R(41), r41 + st.q SP, FRAME_R(42), r42 + st.q SP, FRAME_R(43), r43 + st.q SP, FRAME_R(44), r44 + st.q SP, FRAME_R(45), r45 + st.q SP, FRAME_R(46), r46 + st.q SP, FRAME_R(47), r47 + st.q SP, FRAME_R(48), r48 + st.q SP, FRAME_R(49), r49 + st.q SP, FRAME_R(50), r50 + st.q SP, FRAME_R(51), r51 + st.q SP, FRAME_R(52), r52 + st.q SP, FRAME_R(53), r53 + st.q SP, FRAME_R(54), r54 + st.q SP, FRAME_R(55), r55 + st.q SP, FRAME_R(56), r56 + st.q SP, FRAME_R(57), r57 + st.q SP, FRAME_R(58), r58 + st.q SP, FRAME_R(59), r59 + st.q SP, FRAME_R(60), r60 + st.q SP, FRAME_R(61), r61 + st.q SP, FRAME_R(62), r62 + + /* + * Save the S* registers. + */ + getcon SSR, r61 + st.q SP, FRAME_S(FSSR), r61 + getcon SPC, r62 + st.q SP, FRAME_S(FSPC), r62 + movi -1, r62 /* Reset syscall_nr */ + st.q SP, FRAME_S(FSYSCALL_ID), r62 + + /* Save the rest of the target registers */ + gettr tr1, r6 + st.q SP, FRAME_T(1), r6 + gettr tr2, r6 + st.q SP, FRAME_T(2), r6 + gettr tr3, r6 + st.q SP, FRAME_T(3), r6 + gettr tr4, r6 + st.q SP, FRAME_T(4), r6 + gettr tr5, r6 + st.q SP, FRAME_T(5), r6 + gettr tr6, r6 + st.q SP, FRAME_T(6), r6 + gettr tr7, r6 + st.q SP, FRAME_T(7), r6 + + ! setup FP so that unwinder can wind back through nested kernel mode + ! exceptions + add SP, ZERO, r14 + +#define POOR_MANS_STRACE 0 + +#if POOR_MANS_STRACE + /* We've pushed all the registers now, so only r2-r4 hold anything + * useful. Move them into callee save registers */ + or r2, ZERO, r28 + or r3, ZERO, r29 + or r4, ZERO, r30 + + /* Preserve r2 as the event code */ + movi evt_debug, r3 + ori r3, 1, r3 + ptabs r3, tr0 + + or SP, ZERO, r6 + getcon TRA, r5 + blink tr0, LINK + + or r28, ZERO, r2 + or r29, ZERO, r3 + or r30, ZERO, r4 +#endif + + + /* For syscall and debug race condition, get TRA now */ + getcon TRA, r5 + + /* We are in a safe position to turn SR.BL off, but set IMASK=0xf + * Also set FD, to catch FPU usage in the kernel. + * + * benedict.gaster@superh.com 29/07/2002 + * + * On all SH5-101 revisions it is unsafe to raise the IMASK and at the + * same time change BL from 1->0, as any pending interrupt of a level + * higher than he previous value of IMASK will leak through and be + * taken unexpectedly. + * + * To avoid this we raise the IMASK and then issue another PUTCON to + * enable interrupts. + */ + getcon SR, r6 + movi SR_IMASK | SR_FD, r7 + or r6, r7, r6 + putcon r6, SR + movi SR_UNBLOCK_EXC, r7 + and r6, r7, r6 + putcon r6, SR + + + /* Now call the appropriate 3rd level handler */ + or r3, ZERO, LINK + movi trap_jtable, r3 + shlri r2, 3, r2 + ldx.l r2, r3, r3 + shlri r2, 2, r2 + ptabs r3, tr0 + or SP, ZERO, r3 + blink tr0, ZERO + +/* + * Second level handler for VBR-based exceptions. Post-handlers. + * + * Post-handlers for interrupts (ret_from_irq), exceptions + * (ret_from_exception) and common reentrance doors (restore_all + * to get back to the original context, ret_from_syscall loop to + * check kernel exiting). + * + * ret_with_reschedule and work_notifysig are an inner lables of + * the ret_from_syscall loop. + * + * In common to all stack-frame sensitive handlers. + * + * Inputs: + * (SP) struct pt_regs *, original register's frame pointer (basic) + * + */ + .global ret_from_irq +ret_from_irq: +#if POOR_MANS_STRACE + pta evt_debug_ret_from_irq, tr0 + ori SP, 0, r2 + blink tr0, LINK +#endif + ld.q SP, FRAME_S(FSSR), r6 + shlri r6, 30, r6 + andi r6, 1, r6 + pta resume_kernel, tr0 + bne r6, ZERO, tr0 /* no further checks */ + STI() + pta ret_with_reschedule, tr0 + blink tr0, ZERO /* Do not check softirqs */ + + .global ret_from_exception +ret_from_exception: + preempt_stop() + +#if POOR_MANS_STRACE + pta evt_debug_ret_from_exc, tr0 + ori SP, 0, r2 + blink tr0, LINK +#endif + + ld.q SP, FRAME_S(FSSR), r6 + shlri r6, 30, r6 + andi r6, 1, r6 + pta resume_kernel, tr0 + bne r6, ZERO, tr0 /* no further checks */ + + /* Check softirqs */ + +#ifdef CONFIG_PREEMPT + pta ret_from_syscall, tr0 + blink tr0, ZERO + +resume_kernel: + pta restore_all, tr0 + + getcon KCR0, r6 + ld.l r6, TI_PRE_COUNT, r7 + beq/u r7, ZERO, tr0 + +need_resched: + ld.l r6, TI_FLAGS, r7 + movi (1 << TIF_NEED_RESCHED), r8 + and r8, r7, r8 + bne r8, ZERO, tr0 + + getcon SR, r7 + andi r7, 0xf0, r7 + bne r7, ZERO, tr0 + + movi ((PREEMPT_ACTIVE >> 16) & 65535), r8 + shori (PREEMPT_ACTIVE & 65535), r8 + st.l r6, TI_PRE_COUNT, r8 + + STI() + movi schedule, r7 + ori r7, 1, r7 + ptabs r7, tr1 + blink tr1, LINK + + st.l r6, TI_PRE_COUNT, ZERO + CLI() + + pta need_resched, tr1 + blink tr1, ZERO +#endif + + .global ret_from_syscall +ret_from_syscall: + +ret_with_reschedule: + getcon KCR0, r6 ! r6 contains current_thread_info + ld.l r6, TI_FLAGS, r7 ! r7 contains current_thread_info->flags + + ! FIXME:!!! + ! no handling of TIF_SYSCALL_TRACE yet!! + + movi (1 << TIF_NEED_RESCHED), r8 + and r8, r7, r8 + pta work_resched, tr0 + bne r8, ZERO, tr0 + + pta restore_all, tr1 + + movi (1 << TIF_SIGPENDING), r8 + and r8, r7, r8 + pta work_notifysig, tr0 + bne r8, ZERO, tr0 + + blink tr1, ZERO + +work_resched: + pta ret_from_syscall, tr0 + gettr tr0, LINK + movi schedule, r6 + ptabs r6, tr0 + blink tr0, ZERO /* Call schedule(), return on top */ + +work_notifysig: + gettr tr1, LINK + + movi do_signal, r6 + ptabs r6, tr0 + or SP, ZERO, r2 + or ZERO, ZERO, r3 + blink tr0, LINK /* Call do_signal(regs, 0), return here */ + +restore_all: + /* Do prefetches */ + + ld.q SP, FRAME_T(0), r6 + ld.q SP, FRAME_T(1), r7 + ld.q SP, FRAME_T(2), r8 + ld.q SP, FRAME_T(3), r9 + ptabs r6, tr0 + ptabs r7, tr1 + ptabs r8, tr2 + ptabs r9, tr3 + ld.q SP, FRAME_T(4), r6 + ld.q SP, FRAME_T(5), r7 + ld.q SP, FRAME_T(6), r8 + ld.q SP, FRAME_T(7), r9 + ptabs r6, tr4 + ptabs r7, tr5 + ptabs r8, tr6 + ptabs r9, tr7 + + ld.q SP, FRAME_R(0), r0 + ld.q SP, FRAME_R(1), r1 + ld.q SP, FRAME_R(2), r2 + ld.q SP, FRAME_R(3), r3 + ld.q SP, FRAME_R(4), r4 + ld.q SP, FRAME_R(5), r5 + ld.q SP, FRAME_R(6), r6 + ld.q SP, FRAME_R(7), r7 + ld.q SP, FRAME_R(8), r8 + ld.q SP, FRAME_R(9), r9 + ld.q SP, FRAME_R(10), r10 + ld.q SP, FRAME_R(11), r11 + ld.q SP, FRAME_R(12), r12 + ld.q SP, FRAME_R(13), r13 + ld.q SP, FRAME_R(14), r14 + + ld.q SP, FRAME_R(16), r16 + ld.q SP, FRAME_R(17), r17 + ld.q SP, FRAME_R(18), r18 + ld.q SP, FRAME_R(19), r19 + ld.q SP, FRAME_R(20), r20 + ld.q SP, FRAME_R(21), r21 + ld.q SP, FRAME_R(22), r22 + ld.q SP, FRAME_R(23), r23 + ld.q SP, FRAME_R(24), r24 + ld.q SP, FRAME_R(25), r25 + ld.q SP, FRAME_R(26), r26 + ld.q SP, FRAME_R(27), r27 + ld.q SP, FRAME_R(28), r28 + ld.q SP, FRAME_R(29), r29 + ld.q SP, FRAME_R(30), r30 + ld.q SP, FRAME_R(31), r31 + ld.q SP, FRAME_R(32), r32 + ld.q SP, FRAME_R(33), r33 + ld.q SP, FRAME_R(34), r34 + ld.q SP, FRAME_R(35), r35 + ld.q SP, FRAME_R(36), r36 + ld.q SP, FRAME_R(37), r37 + ld.q SP, FRAME_R(38), r38 + ld.q SP, FRAME_R(39), r39 + ld.q SP, FRAME_R(40), r40 + ld.q SP, FRAME_R(41), r41 + ld.q SP, FRAME_R(42), r42 + ld.q SP, FRAME_R(43), r43 + ld.q SP, FRAME_R(44), r44 + ld.q SP, FRAME_R(45), r45 + ld.q SP, FRAME_R(46), r46 + ld.q SP, FRAME_R(47), r47 + ld.q SP, FRAME_R(48), r48 + ld.q SP, FRAME_R(49), r49 + ld.q SP, FRAME_R(50), r50 + ld.q SP, FRAME_R(51), r51 + ld.q SP, FRAME_R(52), r52 + ld.q SP, FRAME_R(53), r53 + ld.q SP, FRAME_R(54), r54 + ld.q SP, FRAME_R(55), r55 + ld.q SP, FRAME_R(56), r56 + ld.q SP, FRAME_R(57), r57 + ld.q SP, FRAME_R(58), r58 + + getcon SR, r59 + movi SR_BLOCK_EXC, r60 + or r59, r60, r59 + putcon r59, SR /* SR.BL = 1, keep nesting out */ + ld.q SP, FRAME_S(FSSR), r61 + ld.q SP, FRAME_S(FSPC), r62 + movi SR_ASID_MASK, r60 + and r59, r60, r59 + andc r61, r60, r61 /* Clear out older ASID */ + or r59, r61, r61 /* Retain current ASID */ + putcon r61, SSR + putcon r62, SPC + + /* Ignore FSYSCALL_ID */ + + ld.q SP, FRAME_R(59), r59 + ld.q SP, FRAME_R(60), r60 + ld.q SP, FRAME_R(61), r61 + ld.q SP, FRAME_R(62), r62 + + /* Last touch */ + ld.q SP, FRAME_R(15), SP + rte + nop + +/* + * Third level handlers for VBR-based exceptions. Adapting args to + * and/or deflecting to fourth level handlers. + * + * Fourth level handlers interface. + * Most are C-coded handlers directly pointed by the trap_jtable. + * (Third = Fourth level) + * Inputs: + * (r2) fault/interrupt code, entry number (e.g. NMI = 14, + * IRL0-3 (0000) = 16, RTLBMISS = 2, SYSCALL = 11, etc ...) + * (r3) struct pt_regs *, original register's frame pointer + * (r4) Event (0 = interrupt, 1 = TLB miss fault, 2 = Not TLB miss fault) + * (r5) TRA control register (for syscall/debug benefit only) + * (LINK) return address + * (SP) = r3 + * + * Kernel TLB fault handlers will get a slightly different interface. + * (r2) struct pt_regs *, original register's frame pointer + * (r3) writeaccess, whether it's a store fault as opposed to load fault + * (r4) execaccess, whether it's a ITLB fault as opposed to DTLB fault + * (r5) Effective Address of fault + * (LINK) return address + * (SP) = r2 + * + * fpu_error_or_IRQ? is a helper to deflect to the right cause. + * + */ +tlb_miss_load: + or SP, ZERO, r2 + or ZERO, ZERO, r3 /* Read */ + or ZERO, ZERO, r4 /* Data */ + getcon TEA, r5 + pta call_do_page_fault, tr0 + beq ZERO, ZERO, tr0 + +tlb_miss_store: + or SP, ZERO, r2 + movi 1, r3 /* Write */ + or ZERO, ZERO, r4 /* Data */ + getcon TEA, r5 + pta call_do_page_fault, tr0 + beq ZERO, ZERO, tr0 + +itlb_miss_or_IRQ: + pta its_IRQ, tr0 + beqi/u r4, EVENT_INTERRUPT, tr0 + or SP, ZERO, r2 + or ZERO, ZERO, r3 /* Read */ + movi 1, r4 /* Text */ + getcon TEA, r5 + /* Fall through */ + +call_do_page_fault: + movi do_page_fault, r6 + ptabs r6, tr0 + blink tr0, ZERO + +fpu_error_or_IRQA: + pta its_IRQ, tr0 + beqi/l r4, EVENT_INTERRUPT, tr0 +#ifndef CONFIG_NOFPU_SUPPORT + movi do_fpu_state_restore, r6 +#else + movi do_exception_error, r6 +#endif + ptabs r6, tr0 + blink tr0, ZERO + +fpu_error_or_IRQB: + pta its_IRQ, tr0 + beqi/l r4, EVENT_INTERRUPT, tr0 +#ifndef CONFIG_NOFPU_SUPPORT + movi do_fpu_state_restore, r6 +#else + movi do_exception_error, r6 +#endif + ptabs r6, tr0 + blink tr0, ZERO + +its_IRQ: + movi do_IRQ, r6 + ptabs r6, tr0 + blink tr0, ZERO + +/* + * system_call/unknown_trap third level handler: + * + * Inputs: + * (r2) fault/interrupt code, entry number (TRAP = 11) + * (r3) struct pt_regs *, original register's frame pointer + * (r4) Not used. Event (0=interrupt, 1=TLB miss fault, 2=Not TLB miss fault) + * (r5) TRA Control Reg (0x00xyzzzz: x=1 SYSCALL, y = #args, z=nr) + * (SP) = r3 + * (LINK) return address: ret_from_exception + * (*r3) Syscall parms: SC#, arg0, arg1, ..., arg5 in order (Saved r2/r7) + * + * Outputs: + * (*r3) Syscall reply (Saved r2) + * (LINK) In case of syscall only it can be scrapped. + * Common second level post handler will be ret_from_syscall. + * Common (non-trace) exit point to that is syscall_ret (saving + * result to r2). Common bad exit point is syscall_bad (returning + * ENOSYS then saved to r2). + * + */ + +unknown_trap: + /* Unknown Trap or User Trace */ + movi do_unknown_trapa, r6 + ptabs r6, tr0 + ld.q r3, FRAME_R(9), r2 /* r2 = #arg << 16 | syscall # */ + andi r2, 0x1ff, r2 /* r2 = syscall # */ + blink tr0, LINK + + pta syscall_ret, tr0 + blink tr0, ZERO + + /* New syscall implementation*/ +system_call: + pta unknown_trap, tr0 + or r5, ZERO, r4 /* TRA (=r5) -> r4 */ + shlri r4, 20, r4 + bnei r4, 1, tr0 /* unknown_trap if not 0x1yzzzz */ + + /* It's a system call */ + st.q r3, FRAME_S(FSYSCALL_ID), r5 /* ID (0x1yzzzz) -> stack */ + andi r5, 0x1ff, r5 /* syscall # -> r5 */ + + STI() + + pta syscall_allowed, tr0 + movi NR_syscalls - 1, r4 /* Last valid */ + bgeu/l r4, r5, tr0 + +syscall_bad: + /* Return ENOSYS ! */ + movi -(ENOSYS), r2 /* Fall-through */ + + .global syscall_ret +syscall_ret: + st.q SP, FRAME_R(9), r2 /* Expecting SP back to BASIC frame */ + +#if POOR_MANS_STRACE + /* nothing useful in registers at this point */ + + movi evt_debug2, r5 + ori r5, 1, r5 + ptabs r5, tr0 + ld.q SP, FRAME_R(9), r2 + or SP, ZERO, r3 + blink tr0, LINK +#endif + + ld.q SP, FRAME_S(FSPC), r2 + addi r2, 4, r2 /* Move PC, being pre-execution event */ + st.q SP, FRAME_S(FSPC), r2 + pta ret_from_syscall, tr0 + blink tr0, ZERO + + +/* A different return path for ret_from_fork, because we now need + * to call schedule_tail with the later kernels. Because prev is + * loaded into r2 by switch_to() means we can just call it straight away + */ + +.global ret_from_fork +ret_from_fork: + + movi schedule_tail,r5 + ori r5, 1, r5 + ptabs r5, tr0 + blink tr0, LINK + +#if POOR_MANS_STRACE + /* nothing useful in registers at this point */ + + movi evt_debug2, r5 + ori r5, 1, r5 + ptabs r5, tr0 + ld.q SP, FRAME_R(9), r2 + or SP, ZERO, r3 + blink tr0, LINK +#endif + + ld.q SP, FRAME_S(FSPC), r2 + addi r2, 4, r2 /* Move PC, being pre-execution event */ + st.q SP, FRAME_S(FSPC), r2 + pta ret_from_syscall, tr0 + blink tr0, ZERO + + + +syscall_allowed: + /* Use LINK to deflect the exit point, default is syscall_ret */ + pta syscall_ret, tr0 + gettr tr0, LINK + pta syscall_notrace, tr0 + + getcon KCR0, r2 + ld.l r2, TI_FLAGS, r4 + movi (1 << TIF_SYSCALL_TRACE), r6 + and r6, r4, r6 + beq/l r6, ZERO, tr0 + + /* Trace it by calling syscall_trace before and after */ + movi syscall_trace, r4 + ptabs r4, tr0 + blink tr0, LINK + /* Reload syscall number as r5 is trashed by syscall_trace */ + ld.q SP, FRAME_S(FSYSCALL_ID), r5 + andi r5, 0x1ff, r5 + + pta syscall_ret_trace, tr0 + gettr tr0, LINK + +syscall_notrace: + /* Now point to the appropriate 4th level syscall handler */ + movi sys_call_table, r4 + shlli r5, 2, r5 + ldx.l r4, r5, r5 + ptabs r5, tr0 + + /* Prepare original args */ + ld.q SP, FRAME_R(2), r2 + ld.q SP, FRAME_R(3), r3 + ld.q SP, FRAME_R(4), r4 + ld.q SP, FRAME_R(5), r5 + ld.q SP, FRAME_R(6), r6 + ld.q SP, FRAME_R(7), r7 + + /* And now the trick for those syscalls requiring regs * ! */ + or SP, ZERO, r8 + + /* Call it */ + blink tr0, ZERO /* LINK is already properly set */ + +syscall_ret_trace: + /* We get back here only if under trace */ + st.q SP, FRAME_R(9), r2 /* Save return value */ + + movi syscall_trace, LINK + ptabs LINK, tr0 + blink tr0, LINK + + /* This needs to be done after any syscall tracing */ + ld.q SP, FRAME_S(FSPC), r2 + addi r2, 4, r2 /* Move PC, being pre-execution event */ + st.q SP, FRAME_S(FSPC), r2 + + pta ret_from_syscall, tr0 + blink tr0, ZERO /* Resume normal return sequence */ + +/* + * --- Switch to running under a particular ASID and return the previous ASID value + * --- The caller is assumed to have done a cli before calling this. + * + * Input r2 : new ASID + * Output r2 : old ASID + */ + + .global switch_and_save_asid +switch_and_save_asid: + getcon sr, r0 + movi 255, r4 + shlli r4, 16, r4 /* r4 = mask to select ASID */ + and r0, r4, r3 /* r3 = shifted old ASID */ + andi r2, 255, r2 /* mask down new ASID */ + shlli r2, 16, r2 /* align new ASID against SR.ASID */ + andc r0, r4, r0 /* efface old ASID from SR */ + or r0, r2, r0 /* insert the new ASID */ + putcon r0, ssr + movi 1f, r0 + putcon r0, spc + rte + nop +1: + ptabs LINK, tr0 + shlri r3, 16, r2 /* r2 = old ASID */ + blink tr0, r63 + + .global route_to_panic_handler +route_to_panic_handler: + /* Switch to real mode, goto panic_handler, don't return. Useful for + last-chance debugging, e.g. if no output wants to go to the console. + */ + + movi panic_handler - CONFIG_CACHED_MEMORY_OFFSET, r1 + ptabs r1, tr0 + pta 1f, tr1 + gettr tr1, r0 + putcon r0, spc + getcon sr, r0 + movi 1, r1 + shlli r1, 31, r1 + andc r0, r1, r0 + putcon r0, ssr + rte + nop +1: /* Now in real mode */ + blink tr0, r63 + nop + + .global peek_real_address_q +peek_real_address_q: + /* Two args: + r2 : real mode address to peek + r2(out) : result quadword + + This is provided as a cheapskate way of manipulating device + registers for debugging (to avoid the need to onchip_remap the debug + module, and to avoid the need to onchip_remap the watchpoint + controller in a way that identity maps sufficient bits to avoid the + SH5-101 cut2 silicon defect). + + This code is not performance critical + */ + + add.l r2, r63, r2 /* sign extend address */ + getcon sr, r0 /* r0 = saved original SR */ + movi 1, r1 + shlli r1, 28, r1 + or r0, r1, r1 /* r0 with block bit set */ + putcon r1, sr /* now in critical section */ + movi 1, r36 + shlli r36, 31, r36 + andc r1, r36, r1 /* turn sr.mmu off in real mode section */ + + putcon r1, ssr + movi .peek0 - CONFIG_CACHED_MEMORY_OFFSET, r36 /* real mode target address */ + movi 1f, r37 /* virtual mode return addr */ + putcon r36, spc + + synco + rte + nop + +.peek0: /* come here in real mode, don't touch caches!! + still in critical section (sr.bl==1) */ + putcon r0, ssr + putcon r37, spc + /* Here's the actual peek. If the address is bad, all bets are now off + * what will happen (handlers invoked in real-mode = bad news) */ + ld.q r2, 0, r2 + synco + rte /* Back to virtual mode */ + nop + +1: + ptabs LINK, tr0 + blink tr0, r63 + + .global poke_real_address_q +poke_real_address_q: + /* Two args: + r2 : real mode address to poke + r3 : quadword value to write. + + This is provided as a cheapskate way of manipulating device + registers for debugging (to avoid the need to onchip_remap the debug + module, and to avoid the need to onchip_remap the watchpoint + controller in a way that identity maps sufficient bits to avoid the + SH5-101 cut2 silicon defect). + + This code is not performance critical + */ + + add.l r2, r63, r2 /* sign extend address */ + getcon sr, r0 /* r0 = saved original SR */ + movi 1, r1 + shlli r1, 28, r1 + or r0, r1, r1 /* r0 with block bit set */ + putcon r1, sr /* now in critical section */ + movi 1, r36 + shlli r36, 31, r36 + andc r1, r36, r1 /* turn sr.mmu off in real mode section */ + + putcon r1, ssr + movi .poke0-CONFIG_CACHED_MEMORY_OFFSET, r36 /* real mode target address */ + movi 1f, r37 /* virtual mode return addr */ + putcon r36, spc + + synco + rte + nop + +.poke0: /* come here in real mode, don't touch caches!! + still in critical section (sr.bl==1) */ + putcon r0, ssr + putcon r37, spc + /* Here's the actual poke. If the address is bad, all bets are now off + * what will happen (handlers invoked in real-mode = bad news) */ + st.q r2, 0, r3 + synco + rte /* Back to virtual mode */ + nop + +1: + ptabs LINK, tr0 + blink tr0, r63 + +/* + * --- User Access Handling Section + */ + +/* + * User Access support. It all moved to non inlined Assembler + * functions in here. + * + * __kernel_size_t __copy_user(void *__to, const void *__from, + * __kernel_size_t __n) + * + * Inputs: + * (r2) target address + * (r3) source address + * (r4) size in bytes + * + * Ouputs: + * (*r2) target data + * (r2) non-copied bytes + * + * If a fault occurs on the user pointer, bail out early and return the + * number of bytes not copied in r2. + * Strategy : for large blocks, call a real memcpy function which can + * move >1 byte at a time using unaligned ld/st instructions, and can + * manipulate the cache using prefetch + alloco to improve the speed + * further. If a fault occurs in that function, just revert to the + * byte-by-byte approach used for small blocks; this is rare so the + * performance hit for that case does not matter. + * + * For small blocks it's not worth the overhead of setting up and calling + * the memcpy routine; do the copy a byte at a time. + * + */ + .global __copy_user +__copy_user: + pta __copy_user_byte_by_byte, tr1 + movi 16, r0 ! this value is a best guess, should tune it by benchmarking + bge/u r0, r4, tr1 + pta copy_user_memcpy, tr0 + addi SP, -32, SP + /* Save arguments in case we have to fix-up unhandled page fault */ + st.q SP, 0, r2 + st.q SP, 8, r3 + st.q SP, 16, r4 + st.q SP, 24, r35 ! r35 is callee-save + /* Save LINK in a register to reduce RTS time later (otherwise + ld SP,*,LINK;ptabs LINK;trn;blink trn,r63 becomes a critical path) */ + ori LINK, 0, r35 + blink tr0, LINK + + /* Copy completed normally if we get back here */ + ptabs r35, tr0 + ld.q SP, 24, r35 + /* don't restore r2-r4, pointless */ + /* set result=r2 to zero as the copy must have succeeded. */ + or r63, r63, r2 + addi SP, 32, SP + blink tr0, r63 ! RTS + + .global __copy_user_fixup +__copy_user_fixup: + /* Restore stack frame */ + ori r35, 0, LINK + ld.q SP, 24, r35 + ld.q SP, 16, r4 + ld.q SP, 8, r3 + ld.q SP, 0, r2 + addi SP, 32, SP + /* Fall through to original code, in the 'same' state we entered with */ + +/* The slow byte-by-byte method is used if the fast copy traps due to a bad + user address. In that rare case, the speed drop can be tolerated. */ +__copy_user_byte_by_byte: + pta ___copy_user_exit, tr1 + pta ___copy_user1, tr0 + beq/u r4, r63, tr1 /* early exit for zero length copy */ + sub r2, r3, r0 + addi r0, -1, r0 + +___copy_user1: + ld.b r3, 0, r5 /* Fault address 1 */ + + /* Could rewrite this to use just 1 add, but the second comes 'free' + due to load latency */ + addi r3, 1, r3 + addi r4, -1, r4 /* No real fixup required */ +___copy_user2: + stx.b r3, r0, r5 /* Fault address 2 */ + bne r4, ZERO, tr0 + +___copy_user_exit: + or r4, ZERO, r2 + ptabs LINK, tr0 + blink tr0, ZERO + +/* + * __kernel_size_t __clear_user(void *addr, __kernel_size_t size) + * + * Inputs: + * (r2) target address + * (r3) size in bytes + * + * Ouputs: + * (*r2) zero-ed target data + * (r2) non-zero-ed bytes + */ + .global __clear_user +__clear_user: + pta ___clear_user_exit, tr1 + pta ___clear_user1, tr0 + beq/u r3, r63, tr1 + +___clear_user1: + st.b r2, 0, ZERO /* Fault address */ + addi r2, 1, r2 + addi r3, -1, r3 /* No real fixup required */ + bne r3, ZERO, tr0 + +___clear_user_exit: + or r3, ZERO, r2 + ptabs LINK, tr0 + blink tr0, ZERO + + +/* + * int __strncpy_from_user(unsigned long __dest, unsigned long __src, + * int __count) + * + * Inputs: + * (r2) target address + * (r3) source address + * (r4) maximum size in bytes + * + * Ouputs: + * (*r2) copied data + * (r2) -EFAULT (in case of faulting) + * copied data (otherwise) + */ + .global __strncpy_from_user +__strncpy_from_user: + pta ___strncpy_from_user1, tr0 + pta ___strncpy_from_user_done, tr1 + or r4, ZERO, r5 /* r5 = original count */ + beq/u r4, r63, tr1 /* early exit if r4==0 */ + movi -(EFAULT), r6 /* r6 = reply, no real fixup */ + or ZERO, ZERO, r7 /* r7 = data, clear top byte of data */ + +___strncpy_from_user1: + ld.b r3, 0, r7 /* Fault address: only in reading */ + st.b r2, 0, r7 + addi r2, 1, r2 + addi r3, 1, r3 + beq/u ZERO, r7, tr1 + addi r4, -1, r4 /* return real number of copied bytes */ + bne/l ZERO, r4, tr0 + +___strncpy_from_user_done: + sub r5, r4, r6 /* If done, return copied */ + +___strncpy_from_user_exit: + or r6, ZERO, r2 + ptabs LINK, tr0 + blink tr0, ZERO + +/* + * extern long __strnlen_user(const char *__s, long __n) + * + * Inputs: + * (r2) source address + * (r3) source size in bytes + * + * Ouputs: + * (r2) -EFAULT (in case of faulting) + * string length (otherwise) + */ + .global __strnlen_user +__strnlen_user: + pta ___strnlen_user_set_reply, tr0 + pta ___strnlen_user1, tr1 + or ZERO, ZERO, r5 /* r5 = counter */ + movi -(EFAULT), r6 /* r6 = reply, no real fixup */ + or ZERO, ZERO, r7 /* r7 = data, clear top byte of data */ + beq r3, ZERO, tr0 + +___strnlen_user1: + ldx.b r2, r5, r7 /* Fault address: only in reading */ + addi r3, -1, r3 /* No real fixup */ + addi r5, 1, r5 + beq r3, ZERO, tr0 + bne r7, ZERO, tr1 +! The line below used to be active. This meant led to a junk byte lying between each pair +! of entries in the argv & envp structures in memory. Whilst the program saw the right data +! via the argv and envp arguments to main, it meant the 'flat' representation visible through +! /proc/$pid/cmdline was corrupt, causing trouble with ps, for example. +! addi r5, 1, r5 /* Include '\0' */ + +___strnlen_user_set_reply: + or r5, ZERO, r6 /* If done, return counter */ + +___strnlen_user_exit: + or r6, ZERO, r2 + ptabs LINK, tr0 + blink tr0, ZERO + +/* + * extern long __get_user_asm_?(void *val, long addr) + * + * Inputs: + * (r2) dest address + * (r3) source address (in User Space) + * + * Ouputs: + * (r2) -EFAULT (faulting) + * 0 (not faulting) + */ + .global __get_user_asm_b +__get_user_asm_b: + or r2, ZERO, r4 + movi -(EFAULT), r2 /* r2 = reply, no real fixup */ + +___get_user_asm_b1: + ld.b r3, 0, r5 /* r5 = data */ + st.b r4, 0, r5 + or ZERO, ZERO, r2 + +___get_user_asm_b_exit: + ptabs LINK, tr0 + blink tr0, ZERO + + + .global __get_user_asm_w +__get_user_asm_w: + or r2, ZERO, r4 + movi -(EFAULT), r2 /* r2 = reply, no real fixup */ + +___get_user_asm_w1: + ld.w r3, 0, r5 /* r5 = data */ + st.w r4, 0, r5 + or ZERO, ZERO, r2 + +___get_user_asm_w_exit: + ptabs LINK, tr0 + blink tr0, ZERO + + + .global __get_user_asm_l +__get_user_asm_l: + or r2, ZERO, r4 + movi -(EFAULT), r2 /* r2 = reply, no real fixup */ + +___get_user_asm_l1: + ld.l r3, 0, r5 /* r5 = data */ + st.l r4, 0, r5 + or ZERO, ZERO, r2 + +___get_user_asm_l_exit: + ptabs LINK, tr0 + blink tr0, ZERO + + + .global __get_user_asm_q +__get_user_asm_q: + or r2, ZERO, r4 + movi -(EFAULT), r2 /* r2 = reply, no real fixup */ + +___get_user_asm_q1: + ld.q r3, 0, r5 /* r5 = data */ + st.q r4, 0, r5 + or ZERO, ZERO, r2 + +___get_user_asm_q_exit: + ptabs LINK, tr0 + blink tr0, ZERO + +/* + * extern long __put_user_asm_?(void *pval, long addr) + * + * Inputs: + * (r2) kernel pointer to value + * (r3) dest address (in User Space) + * + * Ouputs: + * (r2) -EFAULT (faulting) + * 0 (not faulting) + */ + .global __put_user_asm_b +__put_user_asm_b: + ld.b r2, 0, r4 /* r4 = data */ + movi -(EFAULT), r2 /* r2 = reply, no real fixup */ + +___put_user_asm_b1: + st.b r3, 0, r4 + or ZERO, ZERO, r2 + +___put_user_asm_b_exit: + ptabs LINK, tr0 + blink tr0, ZERO + + + .global __put_user_asm_w +__put_user_asm_w: + ld.w r2, 0, r4 /* r4 = data */ + movi -(EFAULT), r2 /* r2 = reply, no real fixup */ + +___put_user_asm_w1: + st.w r3, 0, r4 + or ZERO, ZERO, r2 + +___put_user_asm_w_exit: + ptabs LINK, tr0 + blink tr0, ZERO + + + .global __put_user_asm_l +__put_user_asm_l: + ld.l r2, 0, r4 /* r4 = data */ + movi -(EFAULT), r2 /* r2 = reply, no real fixup */ + +___put_user_asm_l1: + st.l r3, 0, r4 + or ZERO, ZERO, r2 + +___put_user_asm_l_exit: + ptabs LINK, tr0 + blink tr0, ZERO + + + .global __put_user_asm_q +__put_user_asm_q: + ld.q r2, 0, r4 /* r4 = data */ + movi -(EFAULT), r2 /* r2 = reply, no real fixup */ + +___put_user_asm_q1: + st.q r3, 0, r4 + or ZERO, ZERO, r2 + +___put_user_asm_q_exit: + ptabs LINK, tr0 + blink tr0, ZERO + +panic_stash_regs: + /* The idea is : when we get an unhandled panic, we dump the registers + to a known memory location, the just sit in a tight loop. + This allows the human to look at the memory region through the GDB + session (assuming the debug module's SHwy initiator isn't locked up + or anything), to hopefully analyze the cause of the panic. */ + + /* On entry, former r15 (SP) is in DCR + former r0 is at resvec_saved_area + 0 + former r1 is at resvec_saved_area + 8 + former tr0 is at resvec_saved_area + 32 + DCR is the only register whose value is lost altogether. + */ + + movi 0xffffffff80000000, r0 ! phy of dump area + ld.q SP, 0x000, r1 ! former r0 + st.q r0, 0x000, r1 + ld.q SP, 0x008, r1 ! former r1 + st.q r0, 0x008, r1 + st.q r0, 0x010, r2 + st.q r0, 0x018, r3 + st.q r0, 0x020, r4 + st.q r0, 0x028, r5 + st.q r0, 0x030, r6 + st.q r0, 0x038, r7 + st.q r0, 0x040, r8 + st.q r0, 0x048, r9 + st.q r0, 0x050, r10 + st.q r0, 0x058, r11 + st.q r0, 0x060, r12 + st.q r0, 0x068, r13 + st.q r0, 0x070, r14 + getcon dcr, r14 + st.q r0, 0x078, r14 + st.q r0, 0x080, r16 + st.q r0, 0x088, r17 + st.q r0, 0x090, r18 + st.q r0, 0x098, r19 + st.q r0, 0x0a0, r20 + st.q r0, 0x0a8, r21 + st.q r0, 0x0b0, r22 + st.q r0, 0x0b8, r23 + st.q r0, 0x0c0, r24 + st.q r0, 0x0c8, r25 + st.q r0, 0x0d0, r26 + st.q r0, 0x0d8, r27 + st.q r0, 0x0e0, r28 + st.q r0, 0x0e8, r29 + st.q r0, 0x0f0, r30 + st.q r0, 0x0f8, r31 + st.q r0, 0x100, r32 + st.q r0, 0x108, r33 + st.q r0, 0x110, r34 + st.q r0, 0x118, r35 + st.q r0, 0x120, r36 + st.q r0, 0x128, r37 + st.q r0, 0x130, r38 + st.q r0, 0x138, r39 + st.q r0, 0x140, r40 + st.q r0, 0x148, r41 + st.q r0, 0x150, r42 + st.q r0, 0x158, r43 + st.q r0, 0x160, r44 + st.q r0, 0x168, r45 + st.q r0, 0x170, r46 + st.q r0, 0x178, r47 + st.q r0, 0x180, r48 + st.q r0, 0x188, r49 + st.q r0, 0x190, r50 + st.q r0, 0x198, r51 + st.q r0, 0x1a0, r52 + st.q r0, 0x1a8, r53 + st.q r0, 0x1b0, r54 + st.q r0, 0x1b8, r55 + st.q r0, 0x1c0, r56 + st.q r0, 0x1c8, r57 + st.q r0, 0x1d0, r58 + st.q r0, 0x1d8, r59 + st.q r0, 0x1e0, r60 + st.q r0, 0x1e8, r61 + st.q r0, 0x1f0, r62 + st.q r0, 0x1f8, r63 ! bogus, but for consistency's sake... + + ld.q SP, 0x020, r1 ! former tr0 + st.q r0, 0x200, r1 + gettr tr1, r1 + st.q r0, 0x208, r1 + gettr tr2, r1 + st.q r0, 0x210, r1 + gettr tr3, r1 + st.q r0, 0x218, r1 + gettr tr4, r1 + st.q r0, 0x220, r1 + gettr tr5, r1 + st.q r0, 0x228, r1 + gettr tr6, r1 + st.q r0, 0x230, r1 + gettr tr7, r1 + st.q r0, 0x238, r1 + + getcon sr, r1 + getcon ssr, r2 + getcon pssr, r3 + getcon spc, r4 + getcon pspc, r5 + getcon intevt, r6 + getcon expevt, r7 + getcon pexpevt, r8 + getcon tra, r9 + getcon tea, r10 + getcon kcr0, r11 + getcon kcr1, r12 + getcon vbr, r13 + getcon resvec, r14 + + st.q r0, 0x240, r1 + st.q r0, 0x248, r2 + st.q r0, 0x250, r3 + st.q r0, 0x258, r4 + st.q r0, 0x260, r5 + st.q r0, 0x268, r6 + st.q r0, 0x270, r7 + st.q r0, 0x278, r8 + st.q r0, 0x280, r9 + st.q r0, 0x288, r10 + st.q r0, 0x290, r11 + st.q r0, 0x298, r12 + st.q r0, 0x2a0, r13 + st.q r0, 0x2a8, r14 + + getcon SPC,r2 + getcon SSR,r3 + getcon EXPEVT,r4 + /* Prepare to jump to C - physical address */ + movi panic_handler-CONFIG_CACHED_MEMORY_OFFSET, r1 + ori r1, 1, r1 + ptabs r1, tr0 + getcon DCR, SP + blink tr0, ZERO + nop + nop + nop + nop + + + + +/* + * --- Signal Handling Section + */ + +/* + * extern long long _sa_default_rt_restorer + * extern long long _sa_default_restorer + * + * or, better, + * + * extern void _sa_default_rt_restorer(void) + * extern void _sa_default_restorer(void) + * + * Code prototypes to do a sys_rt_sigreturn() or sys_sysreturn() + * from user space. Copied into user space by signal management. + * Both must be quad aligned and 2 quad long (4 instructions). + * + */ + .balign 8 + .global sa_default_rt_restorer +sa_default_rt_restorer: + movi 0x10, r9 + shori __NR_rt_sigreturn, r9 + trapa r9 + nop + + .balign 8 + .global sa_default_restorer +sa_default_restorer: + movi 0x10, r9 + shori __NR_sigreturn, r9 + trapa r9 + nop + +/* + * --- __ex_table Section + */ + +/* + * User Access Exception Table. + */ + .section __ex_table, "a" + + .global asm_uaccess_start /* Just a marker */ +asm_uaccess_start: + + .long ___copy_user1, ___copy_user_exit + .long ___copy_user2, ___copy_user_exit + .long ___clear_user1, ___clear_user_exit + .long ___strncpy_from_user1, ___strncpy_from_user_exit + .long ___strnlen_user1, ___strnlen_user_exit + .long ___get_user_asm_b1, ___get_user_asm_b_exit + .long ___get_user_asm_w1, ___get_user_asm_w_exit + .long ___get_user_asm_l1, ___get_user_asm_l_exit + .long ___get_user_asm_q1, ___get_user_asm_q_exit + .long ___put_user_asm_b1, ___put_user_asm_b_exit + .long ___put_user_asm_w1, ___put_user_asm_w_exit + .long ___put_user_asm_l1, ___put_user_asm_l_exit + .long ___put_user_asm_q1, ___put_user_asm_q_exit + + .global asm_uaccess_end /* Just a marker */ +asm_uaccess_end: + + + + +/* + * --- .text.init Section + */ + + .section .text.init, "ax" + +/* + * void trap_init (void) + * + */ + .global trap_init +trap_init: + addi SP, -24, SP /* Room to save r28/r29/r30 */ + st.q SP, 0, r28 + st.q SP, 8, r29 + st.q SP, 16, r30 + + /* Set VBR and RESVEC */ + movi LVBR_block, r19 + andi r19, -4, r19 /* reset MMUOFF + reserved */ + /* For RESVEC exceptions we force the MMU off, which means we need the + physical address. */ + movi LRESVEC_block-CONFIG_CACHED_MEMORY_OFFSET, r20 + andi r20, -4, r20 /* reset reserved */ + ori r20, 1, r20 /* set MMUOFF */ + putcon r19, VBR + putcon r20, RESVEC + + /* Sanity check */ + movi LVBR_block_end, r21 + andi r21, -4, r21 + movi BLOCK_SIZE, r29 /* r29 = expected size */ + or r19, ZERO, r30 + add r19, r29, r19 + + /* + * Ugly, but better loop forever now than crash afterwards. + * We should print a message, but if we touch LVBR or + * LRESVEC blocks we should not be surprised if we get stuck + * in trap_init(). + */ + pta trap_init_loop, tr1 + gettr tr1, r28 /* r28 = trap_init_loop */ + sub r21, r30, r30 /* r30 = actual size */ + + /* + * VBR/RESVEC handlers overlap by being bigger than + * allowed. Very bad. Just loop forever. + * (r28) panic/loop address + * (r29) expected size + * (r30) actual size + */ +trap_init_loop: + bne r19, r21, tr1 + + /* Now that exception vectors are set up reset SR.BL */ + getcon SR, r22 + movi SR_UNBLOCK_EXC, r23 + and r22, r23, r22 + putcon r22, SR + + addi SP, 24, SP + ptabs LINK, tr0 + blink tr0, ZERO + diff -puN /dev/null arch/sh64/kernel/fpu.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/kernel/fpu.c 2004-06-28 13:30:30.652144008 -0700 @@ -0,0 +1,170 @@ +/* + * 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. + * + * arch/sh64/kernel/fpu.c + * + * Copyright (C) 2001 Manuela Cirronis, Paolo Alberelli + * Copyright (C) 2002 STMicroelectronics Limited + * Author : Stuart Menefy + * + * Started from SH4 version: + * Copyright (C) 1999, 2000 Kaz Kojima & Niibe Yutaka + * + */ + +#include +#include +#include +#include +#include + +/* + * Initially load the FPU with signalling NANS. This bit pattern + * has the property that no matter whether considered as single or as + * double precision, it still represents a signalling NAN. + */ +#define sNAN64 0xFFFFFFFFFFFFFFFFULL +#define sNAN32 0xFFFFFFFFUL + +static union sh_fpu_union init_fpuregs = { + .hard = { + .fp_regs = { [0 ... 63] = sNAN32 }, + .fpscr = FPSCR_INIT + } +}; + +inline void fpsave(struct sh_fpu_hard_struct *fpregs) +{ + asm volatile("fst.p %0, (0*8), fp0\n\t" + "fst.p %0, (1*8), fp2\n\t" + "fst.p %0, (2*8), fp4\n\t" + "fst.p %0, (3*8), fp6\n\t" + "fst.p %0, (4*8), fp8\n\t" + "fst.p %0, (5*8), fp10\n\t" + "fst.p %0, (6*8), fp12\n\t" + "fst.p %0, (7*8), fp14\n\t" + "fst.p %0, (8*8), fp16\n\t" + "fst.p %0, (9*8), fp18\n\t" + "fst.p %0, (10*8), fp20\n\t" + "fst.p %0, (11*8), fp22\n\t" + "fst.p %0, (12*8), fp24\n\t" + "fst.p %0, (13*8), fp26\n\t" + "fst.p %0, (14*8), fp28\n\t" + "fst.p %0, (15*8), fp30\n\t" + "fst.p %0, (16*8), fp32\n\t" + "fst.p %0, (17*8), fp34\n\t" + "fst.p %0, (18*8), fp36\n\t" + "fst.p %0, (19*8), fp38\n\t" + "fst.p %0, (20*8), fp40\n\t" + "fst.p %0, (21*8), fp42\n\t" + "fst.p %0, (22*8), fp44\n\t" + "fst.p %0, (23*8), fp46\n\t" + "fst.p %0, (24*8), fp48\n\t" + "fst.p %0, (25*8), fp50\n\t" + "fst.p %0, (26*8), fp52\n\t" + "fst.p %0, (27*8), fp54\n\t" + "fst.p %0, (28*8), fp56\n\t" + "fst.p %0, (29*8), fp58\n\t" + "fst.p %0, (30*8), fp60\n\t" + "fst.p %0, (31*8), fp62\n\t" + + "fgetscr fr63\n\t" + "fst.s %0, (32*8), fr63\n\t" + : /* no output */ + : "r" (fpregs) + : "memory"); +} + + +static inline void +fpload(struct sh_fpu_hard_struct *fpregs) +{ + asm volatile("fld.p %0, (0*8), fp0\n\t" + "fld.p %0, (1*8), fp2\n\t" + "fld.p %0, (2*8), fp4\n\t" + "fld.p %0, (3*8), fp6\n\t" + "fld.p %0, (4*8), fp8\n\t" + "fld.p %0, (5*8), fp10\n\t" + "fld.p %0, (6*8), fp12\n\t" + "fld.p %0, (7*8), fp14\n\t" + "fld.p %0, (8*8), fp16\n\t" + "fld.p %0, (9*8), fp18\n\t" + "fld.p %0, (10*8), fp20\n\t" + "fld.p %0, (11*8), fp22\n\t" + "fld.p %0, (12*8), fp24\n\t" + "fld.p %0, (13*8), fp26\n\t" + "fld.p %0, (14*8), fp28\n\t" + "fld.p %0, (15*8), fp30\n\t" + "fld.p %0, (16*8), fp32\n\t" + "fld.p %0, (17*8), fp34\n\t" + "fld.p %0, (18*8), fp36\n\t" + "fld.p %0, (19*8), fp38\n\t" + "fld.p %0, (20*8), fp40\n\t" + "fld.p %0, (21*8), fp42\n\t" + "fld.p %0, (22*8), fp44\n\t" + "fld.p %0, (23*8), fp46\n\t" + "fld.p %0, (24*8), fp48\n\t" + "fld.p %0, (25*8), fp50\n\t" + "fld.p %0, (26*8), fp52\n\t" + "fld.p %0, (27*8), fp54\n\t" + "fld.p %0, (28*8), fp56\n\t" + "fld.p %0, (29*8), fp58\n\t" + "fld.p %0, (30*8), fp60\n\t" + + "fld.s %0, (32*8), fr63\n\t" + "fputscr fr63\n\t" + + "fld.p %0, (31*8), fp62\n\t" + : /* no output */ + : "r" (fpregs) ); +} + +void fpinit(struct sh_fpu_hard_struct *fpregs) +{ + *fpregs = init_fpuregs.hard; +} + +asmlinkage void +do_fpu_error(unsigned long ex, struct pt_regs *regs) +{ + struct task_struct *tsk = current; + + regs->pc += 4; + + tsk->thread.trap_no = 11; + tsk->thread.error_code = 0; + force_sig(SIGFPE, tsk); +} + + +asmlinkage void +do_fpu_state_restore(unsigned long ex, struct pt_regs *regs) +{ + void die(const char *str, struct pt_regs *regs, long err); + + if (! user_mode(regs)) + die("FPU used in kernel", regs, ex); + + regs->sr &= ~SR_FD; + + if (last_task_used_math == current) + return; + + grab_fpu(); + if (last_task_used_math != NULL) { + /* Other processes fpu state, save away */ + fpsave(&last_task_used_math->thread.fpu.hard); + } + last_task_used_math = current; + if (current->used_math) { + fpload(¤t->thread.fpu.hard); + } else { + /* First time FPU user. */ + fpload(&init_fpuregs.hard); + current->used_math = 1; + } + release_fpu(); +} + diff -puN /dev/null arch/sh64/kernel/head.S --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/kernel/head.S 2004-06-28 13:30:30.654143704 -0700 @@ -0,0 +1,373 @@ +/* + * 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. + * + * arch/sh64/kernel/head.S + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003, 2004 Paul Mundt + * + * + * benedict.gaster@superh.com: 2nd May 2002 + * Moved definition of empty_zero_page to its own section allowing + * it to be placed at an absolute address known at load time. + * + * lethal@linux-sh.org: 9th May 2003 + * Kill off GLOBAL_NAME() usage. + * + * lethal@linux-sh.org: 8th May 2004 + * Add early SCIF console DTLB mapping. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +/* + * MMU defines: TLB boundaries. + */ + +#define MMUIR_FIRST ITLB_FIXED +#define MMUIR_END ITLB_LAST_VAR_UNRESTRICTED+TLB_STEP +#define MMUIR_STEP TLB_STEP + +#define MMUDR_FIRST DTLB_FIXED +#define MMUDR_END DTLB_LAST_VAR_UNRESTRICTED+TLB_STEP +#define MMUDR_STEP TLB_STEP + +/* Safety check : CONFIG_CACHED_MEMORY_OFFSET has to be a multiple of 512Mb */ +#if (CONFIG_CACHED_MEMORY_OFFSET & ((1UL<<29)-1)) +#error "CONFIG_CACHED_MEMORY_OFFSET must be a multiple of 512Mb" +#endif + +/* + * MMU defines: Fixed TLBs. + */ +/* Deal safely with the case where the base of RAM is not 512Mb aligned */ + +#define ALIGN_512M_MASK (0xffffffffe0000000) +#define ALIGNED_EFFECTIVE ((CONFIG_CACHED_MEMORY_OFFSET + CONFIG_MEMORY_START) & ALIGN_512M_MASK) +#define ALIGNED_PHYSICAL (CONFIG_MEMORY_START & ALIGN_512M_MASK) + +#define MMUIR_TEXT_H (0x0000000000000003 | ALIGNED_EFFECTIVE) + /* Enabled, Shared, ASID 0, Eff. Add. 0xA0000000 */ + +#define MMUIR_TEXT_L (0x000000000000009a | ALIGNED_PHYSICAL) + /* 512 Mb, Cacheable, Write-back, execute, Not User, Ph. Add. */ + +#define MMUDR_CACHED_H 0x0000000000000003 | ALIGNED_EFFECTIVE + /* Enabled, Shared, ASID 0, Eff. Add. 0xA0000000 */ +#define MMUDR_CACHED_L 0x000000000000015a | ALIGNED_PHYSICAL + /* 512 Mb, Cacheable, Write-back, read/write, Not User, Ph. Add. */ + +#ifdef CONFIG_ICACHE_DISABLED +#define ICCR0_INIT_VAL ICCR0_OFF /* ICACHE off */ +#else +#define ICCR0_INIT_VAL ICCR0_ON | ICCR0_ICI /* ICE + ICI */ +#endif +#define ICCR1_INIT_VAL ICCR1_NOLOCK /* No locking */ + +#if defined (CONFIG_DCACHE_DISABLED) +#define OCCR0_INIT_VAL OCCR0_OFF /* D-cache: off */ +#elif defined (CONFIG_DCACHE_WRITE_THROUGH) +#define OCCR0_INIT_VAL OCCR0_ON | OCCR0_OCI | OCCR0_WT /* D-cache: on, */ + /* WT, invalidate */ +#elif defined (CONFIG_DCACHE_WRITE_BACK) +#define OCCR0_INIT_VAL OCCR0_ON | OCCR0_OCI | OCCR0_WB /* D-cache: on, */ + /* WB, invalidate */ +#else +#error preprocessor flag CONFIG_DCACHE_... not recognized! +#endif + +#define OCCR1_INIT_VAL OCCR1_NOLOCK /* No locking */ + + .section .empty_zero_page, "aw" + .global empty_zero_page + +empty_zero_page: + .long 1 /* MOUNT_ROOT_RDONLY */ + .long 0 /* RAMDISK_FLAGS */ + .long 0x0200 /* ORIG_ROOT_DEV */ + .long 1 /* LOADER_TYPE */ + .long 0x00360000 /* INITRD_START */ + .long 0x000a0000 /* INITRD_SIZE */ + .long 0 + + .text + .balign 4096,0,4096 + + .section .data, "aw" + .balign PAGE_SIZE + + .section .data, "aw" + .balign PAGE_SIZE + + .global swapper_pg_dir +swapper_pg_dir: + .space PAGE_SIZE, 0 + + .global empty_bad_page +empty_bad_page: + .space PAGE_SIZE, 0 + + .global empty_bad_pte_table +empty_bad_pte_table: + .space PAGE_SIZE, 0 + + .global fpu_in_use +fpu_in_use: .quad 0 + + + .section .text, "ax" + .balign L1_CACHE_BYTES +/* + * Condition at the entry of __stext: + * . Reset state: + * . SR.FD = 1 (FPU disabled) + * . SR.BL = 1 (Exceptions disabled) + * . SR.MD = 1 (Privileged Mode) + * . SR.MMU = 0 (MMU Disabled) + * . SR.CD = 0 (CTC User Visible) + * . SR.IMASK = Undefined (Interrupt Mask) + * + * Operations supposed to be performed by __stext: + * . prevent speculative fetch onto device memory while MMU is off + * . reflect as much as possible SH5 ABI (r15, r26, r27, r18) + * . first, save CPU state and set it to something harmless + * . any CPU detection and/or endianness settings (?) + * . initialize EMI/LMI (but not TMU/RTC/INTC/SCIF): TBD + * . set initial TLB entries for cached and uncached regions + * (no fine granularity paging) + * . set initial cache state + * . enable MMU and caches + * . set CPU to a consistent state + * . registers (including stack pointer and current/KCR0) + * . NOT expecting to set Exception handling nor VBR/RESVEC/DCR + * at this stage. This is all to later Linux initialization steps. + * . initialize FPU + * . clear BSS + * . jump into start_kernel() + * . be prepared to hopeless start_kernel() returns. + * + */ + .global _stext +_stext: + /* + * Prevent speculative fetch on device memory due to + * uninitialized target registers. + */ + ptabs/u ZERO, tr0 + ptabs/u ZERO, tr1 + ptabs/u ZERO, tr2 + ptabs/u ZERO, tr3 + ptabs/u ZERO, tr4 + ptabs/u ZERO, tr5 + ptabs/u ZERO, tr6 + ptabs/u ZERO, tr7 + synci + + /* + * Read/Set CPU state. After this block: + * r29 = Initial SR + */ + getcon SR, r29 + movi SR_HARMLESS, r20 + putcon r20, SR + + /* + * Initialize EMI/LMI. To Be Done. + */ + + /* + * CPU detection and/or endianness settings (?). To Be Done. + * Pure PIC code here, please ! Just save state into r30. + * After this block: + * r30 = CPU type/Platform Endianness + */ + + /* + * Set initial TLB entries for cached and uncached regions. + * Note: PTA/BLINK is PIC code, PTABS/BLINK isn't ! + */ + /* Clear ITLBs */ + pta clear_ITLB, tr1 + movi MMUIR_FIRST, r21 + movi MMUIR_END, r22 +clear_ITLB: + putcfg r21, 0, ZERO /* Clear MMUIR[n].PTEH.V */ + addi r21, MMUIR_STEP, r21 + bne r21, r22, tr1 + + /* Clear DTLBs */ + pta clear_DTLB, tr1 + movi MMUDR_FIRST, r21 + movi MMUDR_END, r22 +clear_DTLB: + putcfg r21, 0, ZERO /* Clear MMUDR[n].PTEH.V */ + addi r21, MMUDR_STEP, r21 + bne r21, r22, tr1 + + /* Map one big (512Mb) page for ITLB */ + movi MMUIR_FIRST, r21 + movi MMUIR_TEXT_L, r22 /* PTEL first */ + add.l r22, r63, r22 /* Sign extend */ + putcfg r21, 1, r22 /* Set MMUIR[0].PTEL */ + movi MMUIR_TEXT_H, r22 /* PTEH last */ + add.l r22, r63, r22 /* Sign extend */ + putcfg r21, 0, r22 /* Set MMUIR[0].PTEH */ + + /* Map one big CACHED (512Mb) page for DTLB */ + movi MMUDR_FIRST, r21 + movi MMUDR_CACHED_L, r22 /* PTEL first */ + add.l r22, r63, r22 /* Sign extend */ + putcfg r21, 1, r22 /* Set MMUDR[0].PTEL */ + movi MMUDR_CACHED_H, r22 /* PTEH last */ + add.l r22, r63, r22 /* Sign extend */ + putcfg r21, 0, r22 /* Set MMUDR[0].PTEH */ + +#ifdef CONFIG_EARLY_PRINTK + /* + * Setup a DTLB translation for SCIF phys. + */ + addi r21, MMUDR_STEP, r21 + movi 0x0a03, r22 /* SCIF phys */ + shori 0x0148, r22 + putcfg r21, 1, r22 /* PTEL first */ + movi 0xfa03, r22 /* 0xfa030000, fixed SCIF virt */ + shori 0x0003, r22 + putcfg r21, 0, r22 /* PTEH last */ +#endif + + /* + * Set cache behaviours. + */ + /* ICache */ + movi ICCR_BASE, r21 + movi ICCR0_INIT_VAL, r22 + movi ICCR1_INIT_VAL, r23 + putcfg r21, ICCR_REG0, r22 + putcfg r21, ICCR_REG1, r23 + + /* OCache */ + movi OCCR_BASE, r21 + movi OCCR0_INIT_VAL, r22 + movi OCCR1_INIT_VAL, r23 + putcfg r21, OCCR_REG0, r22 + putcfg r21, OCCR_REG1, r23 + + + /* + * Enable Caches and MMU. Do the first non-PIC jump. + * Now head.S global variables, constants and externs + * can be used. + */ + getcon SR, r21 + movi SR_ENABLE_MMU, r22 + or r21, r22, r21 + putcon r21, SSR + movi hyperspace, r22 + ori r22, 1, r22 /* Make it SHmedia, not required but..*/ + putcon r22, SPC + synco + rte /* And now go into the hyperspace ... */ +hyperspace: /* ... that's the next instruction ! */ + + /* + * Set CPU to a consistent state. + * r31 = FPU support flag + * tr0/tr7 in use. Others give a chance to loop somewhere safe + */ + movi start_kernel, r32 + ori r32, 1, r32 + + ptabs r32, tr0 /* r32 = _start_kernel address */ + pta/u hopeless, tr1 + pta/u hopeless, tr2 + pta/u hopeless, tr3 + pta/u hopeless, tr4 + pta/u hopeless, tr5 + pta/u hopeless, tr6 + pta/u hopeless, tr7 + gettr tr1, r28 /* r28 = hopeless address */ + + /* Set initial stack pointer */ + movi init_thread_union, SP + putcon SP, KCR0 /* Set current to init_task */ + movi THREAD_SIZE, r22 /* Point to the end */ + add SP, r22, SP + + /* + * Initialize FPU. + * Keep FPU flag in r31. After this block: + * r31 = FPU flag + */ + movi fpu_in_use, r31 /* Temporary */ + +#ifndef CONFIG_NOFPU_SUPPORT + getcon SR, r21 + movi SR_ENABLE_FPU, r22 + and r21, r22, r22 + putcon r22, SR /* Try to enable */ + getcon SR, r22 + xor r21, r22, r21 + shlri r21, 15, r21 /* Supposedly 0/1 */ + st.q r31, 0 , r21 /* Set fpu_in_use */ +#else + movi 0, r21 + st.q r31, 0 , r21 /* Set fpu_in_use */ +#endif + or r21, ZERO, r31 /* Set FPU flag at last */ + +#ifndef CONFIG_SH_NO_BSS_INIT +/* Don't clear BSS if running on slow platforms such as an RTL simulation, + remote memory via SHdebug link, etc. For these the memory can be guaranteed + to be all zero on boot anyway. */ + /* + * Clear bss + */ + pta clear_quad, tr1 + movi __bss_start, r22 + movi _end, r23 +clear_quad: + st.q r22, 0, ZERO + addi r22, 8, r22 + bne r22, r23, tr1 /* Both quad aligned, see vmlinux.lds.S */ +#endif + pta/u hopeless, tr1 + + /* Say bye to head.S but be prepared to wrongly get back ... */ + blink tr0, LINK + + /* If we ever get back here through LINK/tr1-tr7 */ + pta/u hopeless, tr7 + +hopeless: + /* + * Something's badly wrong here. Loop endlessly, + * there's nothing more we can do about it. + * + * Note on hopeless: it can be jumped into invariably + * before or after jumping into hyperspace. The only + * requirement is to be PIC called (PTA) before and + * any way (PTA/PTABS) after. According to Virtual + * to Physical mapping a simulator/emulator can easily + * tell where we came here from just looking at hopeless + * (PC) address. + * + * For debugging purposes: + * (r28) hopeless/loop address + * (r29) Original SR + * (r30) CPU type/Platform endianness + * (r31) FPU Support + * (r32) _start_kernel address + */ + blink tr7, ZERO + + diff -puN /dev/null arch/sh64/kernel/init_task.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/kernel/init_task.c 2004-06-28 13:30:30.654143704 -0700 @@ -0,0 +1,45 @@ +/* + * 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. + * + * arch/sh64/kernel/init_task.c + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003 Paul Mundt + * + */ +#include +#include +#include +#include + +#include +#include + +static struct fs_struct init_fs = INIT_FS; +static struct files_struct init_files = INIT_FILES; +static struct signal_struct init_signals = INIT_SIGNALS(init_signals); +static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); +struct mm_struct init_mm = INIT_MM(init_mm); + +struct pt_regs fake_swapper_regs; + +/* + * Initial thread structure. + * + * We need to make sure that this is THREAD_SIZE-byte aligned due + * to the way process stacks are handled. This is done by having a + * special "init_task" linker map entry.. + */ +union thread_union init_thread_union + __attribute__((__section__(".data.init_task"))) = + { INIT_THREAD_INFO(init_task) }; + +/* + * Initial task structure. + * + * All other task structs will be allocated on slabs in fork.c + */ +struct task_struct init_task = INIT_TASK(init_task); + diff -puN /dev/null arch/sh64/kernel/irq.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/kernel/irq.c 2004-06-28 13:30:30.658143096 -0700 @@ -0,0 +1,720 @@ +/* + * 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. + * + * arch/sh64/kernel/irq.c + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003 Paul Mundt + * + */ + +/* + * IRQs are in fact implemented a bit like signal handlers for the kernel. + * Naturally it's not a 1:1 relation, but there are similarities. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Controller mappings for all interrupt sources: + */ +irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = { + [0 ... NR_IRQS-1] = { + .handler = &no_irq_type, + .lock = SPIN_LOCK_UNLOCKED + } +}; + + +/* + * Special irq handlers. + */ + +irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs) +{ + return IRQ_NONE; +} + +/* + * Generic no controller code + */ + +static void enable_none(unsigned int irq) { } +static unsigned int startup_none(unsigned int irq) { return 0; } +static void disable_none(unsigned int irq) { } +static void ack_none(unsigned int irq) +{ +/* + * 'what should we do if we get a hw irq event on an illegal vector'. + * each architecture has to answer this themselves, it doesnt deserve + * a generic callback i think. + */ + printk("unexpected IRQ trap at irq %02x\n", irq); +} + +/* startup is the same as "enable", shutdown is same as "disable" */ +#define shutdown_none disable_none +#define end_none enable_none + +struct hw_interrupt_type no_irq_type = { + "none", + startup_none, + shutdown_none, + enable_none, + disable_none, + ack_none, + end_none +}; + +#if defined(CONFIG_PROC_FS) +int show_interrupts(struct seq_file *p, void *v) +{ + int i = *(loff_t *) v, j; + struct irqaction * action; + unsigned long flags; + + if (i == 0) { + seq_puts(p, " "); + for (j=0; jtypename); + seq_printf(p, " %s", action->name); + + for (action=action->next; action; action = action->next) + seq_printf(p, ", %s", action->name); + seq_putc(p, '\n'); +unlock: + spin_unlock_irqrestore(&irq_desc[i].lock, flags); + } + return 0; +} +#endif + +/* + * do_NMI handles all Non-Maskable Interrupts. + */ +asmlinkage void do_NMI(unsigned long vector_num, struct pt_regs * regs) +{ + if (regs->sr & 0x40000000) + printk("unexpected NMI trap in system mode\n"); + else + printk("unexpected NMI trap in user mode\n"); + + /* No statistics */ +} + +/* + * This should really return information about whether + * we should do bottom half handling etc. Right now we + * end up _always_ checking the bottom half, which is a + * waste of time and is not what some drivers would + * prefer. + */ +int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action) +{ + int status; + + status = 1; /* Force the "do bottom halves" bit */ + + if (!(action->flags & SA_INTERRUPT)) + local_irq_enable(); + + do { + status |= action->flags; + action->handler(irq, action->dev_id, regs); + action = action->next; + } while (action); + if (status & SA_SAMPLE_RANDOM) + add_interrupt_randomness(irq); + + local_irq_disable(); + + return status; +} + +/* + * Generic enable/disable code: this just calls + * down into the PIC-specific version for the actual + * hardware disable after having gotten the irq + * controller lock. + */ + +/** + * disable_irq_nosync - disable an irq without waiting + * @irq: Interrupt to disable + * + * Disable the selected interrupt line. Disables of an interrupt + * stack. Unlike disable_irq(), this function does not ensure existing + * instances of the IRQ handler have completed before returning. + * + * This function may be called from IRQ context. + */ +void disable_irq_nosync(unsigned int irq) +{ + irq_desc_t *desc = irq_desc + irq; + unsigned long flags; + + spin_lock_irqsave(&desc->lock, flags); + if (!desc->depth++) { + desc->status |= IRQ_DISABLED; + desc->handler->disable(irq); + } + spin_unlock_irqrestore(&desc->lock, flags); +} + +/** + * disable_irq - disable an irq and wait for completion + * @irq: Interrupt to disable + * + * Disable the selected interrupt line. Disables of an interrupt + * stack. That is for two disables you need two enables. This + * function waits for any pending IRQ handlers for this interrupt + * to complete before returning. If you use this function while + * holding a resource the IRQ handler may need you will deadlock. + * + * This function may be called - with care - from IRQ context. + */ +void disable_irq(unsigned int irq) +{ + disable_irq_nosync(irq); + synchronize_irq(irq); +} + +/** + * enable_irq - enable interrupt handling on an irq + * @irq: Interrupt to enable + * + * Re-enables the processing of interrupts on this IRQ line + * providing no disable_irq calls are now in effect. + * + * This function may be called from IRQ context. + */ +void enable_irq(unsigned int irq) +{ + irq_desc_t *desc = irq_desc + irq; + unsigned long flags; + + spin_lock_irqsave(&desc->lock, flags); + switch (desc->depth) { + case 1: { + unsigned int status = desc->status & ~IRQ_DISABLED; + desc->status = status; + if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { + desc->status = status | IRQ_REPLAY; + hw_resend_irq(desc->handler,irq); + } + desc->handler->enable(irq); + /* fall-through */ + } + default: + desc->depth--; + break; + case 0: + printk("enable_irq() unbalanced from %p\n", + __builtin_return_address(0)); + } + spin_unlock_irqrestore(&desc->lock, flags); +} + +/* + * do_IRQ handles all normal device IRQ's. + */ +asmlinkage int do_IRQ(unsigned long vector_num, struct pt_regs * regs) +{ + /* + * We ack quickly, we don't want the irq controller + * thinking we're snobs just because some other CPU has + * disabled global interrupts (we have already done the + * INT_ACK cycles, it's too late to try to pretend to the + * controller that we aren't taking the interrupt). + * + * 0 return value means that this irq is already being + * handled by some other CPU. (or is disabled) + */ + int irq; + int cpu = smp_processor_id(); + irq_desc_t *desc = NULL; + struct irqaction * action; + unsigned int status; + + irq_enter(); + +#ifdef CONFIG_PREEMPT + /* + * At this point we're now about to actually call handlers, + * and interrupts might get reenabled during them... bump + * preempt_count to prevent any preemption while the handler + * called here is pending... + */ + preempt_disable(); +#endif + + irq = irq_demux(vector_num); + + /* + * Should never happen, if it does check + * vectorN_to_IRQ[] against trap_jtable[]. + */ + if (irq == -1) { + printk("unexpected IRQ trap at vector %03lx\n", vector_num); + goto out; + } + + desc = irq_desc + irq; + + kstat_cpu(cpu).irqs[irq]++; + spin_lock(&desc->lock); + desc->handler->ack(irq); + /* + REPLAY is when Linux resends an IRQ that was dropped earlier + WAITING is used by probe to mark irqs that are being tested + */ + status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING | IRQ_INPROGRESS); + status |= IRQ_PENDING; /* we _want_ to handle it */ + + /* + * If the IRQ is disabled for whatever reason, we cannot + * use the action we have. + */ + action = NULL; + if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { + action = desc->action; + status &= ~IRQ_PENDING; /* we commit to handling */ + status |= IRQ_INPROGRESS; /* we are handling it */ + } + desc->status = status; + + /* + * If there is no IRQ handler or it was disabled, exit early. + Since we set PENDING, if another processor is handling + a different instance of this same irq, the other processor + will take care of it. + */ + if (!action) + goto out; + + /* + * Edge triggered interrupts need to remember + * pending events. + * This applies to any hw interrupts that allow a second + * instance of the same irq to arrive while we are in do_IRQ + * or in the handler. But the code here only handles the _second_ + * instance of the irq, not the third or fourth. So it is mostly + * useful for irq hardware that does not mask cleanly in an + * SMP environment. + */ + for (;;) { + spin_unlock(&desc->lock); + handle_IRQ_event(irq, regs, action); + spin_lock(&desc->lock); + + if (!(desc->status & IRQ_PENDING)) + break; + desc->status &= ~IRQ_PENDING; + } + desc->status &= ~IRQ_INPROGRESS; +out: + /* + * The ->end() handler has to deal with interrupts which got + * disabled while the handler was running. + */ + if (desc) { + desc->handler->end(irq); + spin_unlock(&desc->lock); + } + + irq_exit(); + +#ifdef CONFIG_PREEMPT + /* + * We're done with the handlers, interrupts should be + * currently disabled; decrement preempt_count now so + * as we return preemption may be allowed... + */ + preempt_enable_no_resched(); +#endif + + return 1; +} + +/** + * request_irq - allocate an interrupt line + * @irq: Interrupt line to allocate + * @handler: Function to be called when the IRQ occurs + * @irqflags: Interrupt type flags + * @devname: An ascii name for the claiming device + * @dev_id: A cookie passed back to the handler function + * + * This call allocates interrupt resources and enables the + * interrupt line and IRQ handling. From the point this + * call is made your handler function may be invoked. Since + * your handler function must clear any interrupt the board + * raises, you must take care both to initialise your hardware + * and to set up the interrupt handler in the right order. + * + * Dev_id must be globally unique. Normally the address of the + * device data structure is used as the cookie. Since the handler + * receives this value it makes sense to use it. + * + * If your interrupt is shared you must pass a non NULL dev_id + * as this is required when freeing the interrupt. + * + * Flags: + * + * SA_SHIRQ Interrupt is shared + * + * SA_INTERRUPT Disable local interrupts while processing + * + * SA_SAMPLE_RANDOM The interrupt can be used for entropy + * + */ +int request_irq(unsigned int irq, + irqreturn_t (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, + const char * devname, + void *dev_id) +{ + int retval; + struct irqaction * action; + +#if 1 + /* + * Sanity-check: shared interrupts should REALLY pass in + * a real dev-ID, otherwise we'll have trouble later trying + * to figure out which interrupt is which (messes up the + * interrupt freeing logic etc). + */ + if (irqflags & SA_SHIRQ) { + if (!dev_id) + printk("Bad boy: %s (at 0x%x) called us without a dev_id!\n", devname, (&irq)[-1]); + } +#endif + + if (irq >= NR_IRQS) + return -EINVAL; + if (!handler) + return -EINVAL; + + action = (struct irqaction *) + kmalloc(sizeof(struct irqaction), GFP_KERNEL); + if (!action) + return -ENOMEM; + + action->handler = handler; + action->flags = irqflags; + action->mask = 0; + action->name = devname; + action->next = NULL; + action->dev_id = dev_id; + + retval = setup_irq(irq, action); + if (retval) + kfree(action); + return retval; +} + +/** + * free_irq - free an interrupt + * @irq: Interrupt line to free + * @dev_id: Device identity to free + * + * Remove an interrupt handler. The handler is removed and if the + * interrupt line is no longer in use by any driver it is disabled. + * On a shared IRQ the caller must ensure the interrupt is disabled + * on the card it drives before calling this function. The function + * does not return until any executing interrupts for this IRQ + * have completed. + * + * This function may be called from interrupt context. + * + * Bugs: Attempting to free an irq in a handler for the same irq hangs + * the machine. + */ +void free_irq(unsigned int irq, void *dev_id) +{ + irq_desc_t *desc; + struct irqaction **p; + unsigned long flags; + + if (irq >= NR_IRQS) + return; + + desc = irq_desc + irq; + spin_lock_irqsave(&desc->lock,flags); + p = &desc->action; + for (;;) { + struct irqaction * action = *p; + if (action) { + struct irqaction **pp = p; + p = &action->next; + if (action->dev_id != dev_id) + continue; + + /* Found it - now remove it from the list of entries */ + *pp = action->next; + if (!desc->action) { + desc->status |= IRQ_DISABLED; + desc->handler->shutdown(irq); + } + spin_unlock_irqrestore(&desc->lock,flags); + kfree(action); + return; + } + printk("Trying to free free IRQ%d\n",irq); + spin_unlock_irqrestore(&desc->lock,flags); + return; + } +} + +/* + * IRQ autodetection code.. + * + * This depends on the fact that any interrupt that + * comes in on to an unassigned handler will get stuck + * with "IRQ_WAITING" cleared and the interrupt + * disabled. + */ + +/** + * probe_irq_on - begin an interrupt autodetect + * + * Commence probing for an interrupt. The interrupts are scanned + * and a mask of potential interrupt lines is returned. + * + */ +unsigned long probe_irq_on(void) +{ + unsigned int i; + irq_desc_t *desc; + unsigned long val; + unsigned long delay; + + /* + * something may have generated an irq long ago and we want to + * flush such a longstanding irq before considering it as spurious. + */ + for (i = NR_IRQS-1; i >= 0; i--) { + desc = irq_desc + i; + + spin_lock_irq(&desc->lock); + if (!irq_desc[i].action) { + irq_desc[i].handler->startup(i); + } + spin_unlock_irq(&desc->lock); + } + + /* Wait for longstanding interrupts to trigger. */ + for (delay = jiffies + HZ/50; time_after(delay, jiffies); ) + /* about 20ms delay */ synchronize_irq(); + + /* + * enable any unassigned irqs + * (we must startup again here because if a longstanding irq + * happened in the previous stage, it may have masked itself) + */ + for (i = NR_IRQS-1; i >= 0; i--) { + desc = irq_desc + 1; + + spin_lock_irq(&desc->lock); + if (!desc->action) { + desc->status |= IRQ_AUTODETECT | IRQ_WAITING; + if (desc->handler->startup(i)) + desc->status |= IRQ_PENDING; + } + spin_unlock_irq(&desc->lock); + } + + /* + * Wait for spurious interrupts to trigger + */ + for (delay = jiffies + HZ/10; time_after(delay, jiffies); ) + /* about 100ms delay */ synchronize_irq(); + + /* + * Now filter out any obviously spurious interrupts + */ + val = 0; + for (i = 0; i < NR_IRQS; i++) { + irq_desc_t *desc = irq_desc + i; + unsigned int status; + + spin_lock_irq(&desc->lock); + status = desc->status; + + if (status & IRQ_AUTODETECT) { + /* It triggered already - consider it spurious. */ + if (!(status & IRQ_WAITING)) { + desc->status = status & ~IRQ_AUTODETECT; + desc->handler->shutdown(i); + } else + if (i < 32) + val |= 1 << i; + } + spin_unlock_irq(&desc->lock); + } + + return val; +} + +/* + * Return the one interrupt that triggered (this can + * handle any interrupt source). + */ + +/** + * probe_irq_off - end an interrupt autodetect + * @val: mask of potential interrupts (unused) + * + * Scans the unused interrupt lines and returns the line which + * appears to have triggered the interrupt. If no interrupt was + * found then zero is returned. If more than one interrupt is + * found then minus the first candidate is returned to indicate + * their is doubt. + * + * The interrupt probe logic state is returned to its previous + * value. + * + * BUGS: When used in a module (which arguably shouldnt happen) + * nothing prevents two IRQ probe callers from overlapping. The + * results of this are non-optimal. + */ +int probe_irq_off(unsigned long val) +{ + int i, irq_found, nr_irqs; + + nr_irqs = 0; + irq_found = 0; + for (i=0; ilock); + status = desc->status; + if (!(status & IRQ_AUTODETECT)) + continue; + + if (status & IRQ_AUTODETECT) { + if (!(status & IRQ_WAITING)) { + if (!nr_irqs) + irq_found = i; + nr_irqs++; + } + + desc->status = status & ~IRQ_AUTODETECT; + desc->handler->shutdown(i); + } + spin_unlock_irq(&desc->lock); + } + + if (nr_irqs > 1) + irq_found = -irq_found; + return irq_found; +} + +int setup_irq(unsigned int irq, struct irqaction * new) +{ + int shared = 0; + unsigned long flags; + struct irqaction *old, **p; + irq_desc_t *desc = irq_desc + irq; + + /* + * Some drivers like serial.c use request_irq() heavily, + * so we have to be careful not to interfere with a + * running system. + */ + if (new->flags & SA_SAMPLE_RANDOM) { + /* + * This function might sleep, we want to call it first, + * outside of the atomic block. + * Yes, this might clear the entropy pool if the wrong + * driver is attempted to be loaded, without actually + * installing a new handler, but is this really a problem, + * only the sysadmin is able to do this. + */ + rand_initialize_irq(irq); + } + + /* + * The following block of code has to be executed atomically + */ + spin_lock_irqsave(&desc->lock,flags); + p = &desc->action; + if ((old = *p) != NULL) { + /* Can't share interrupts unless both agree to */ + if (!(old->flags & new->flags & SA_SHIRQ)) { + spin_unlock_irqrestore(&desc->lock,flags); + return -EBUSY; + } + + /* add new interrupt at end of irq queue */ + do { + p = &old->next; + old = *p; + } while (old); + shared = 1; + } + + *p = new; + + if (!shared) { + desc->depth = 0; + desc->status &= ~IRQ_DISABLED; + desc->handler->startup(irq); + } + spin_unlock_irqrestore(&desc->lock,flags); + + /* + * No PROC FS support for interrupts. + * For improvements in this area please check + * the i386 branch. + */ + return 0; +} + +#if defined(CONFIG_PROC_FS) && defined(CONFIG_SYSCTL) + +void init_irq_proc(void) +{ + /* + * No PROC FS support for interrupts. + * For improvements in this area please check + * the i386 branch. + */ +} +#endif diff -puN /dev/null arch/sh64/kernel/irq_intc.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/kernel/irq_intc.c 2004-06-28 13:30:30.659142944 -0700 @@ -0,0 +1,272 @@ +/* + * 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. + * + * arch/sh64/kernel/irq_intc.c + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003 Paul Mundt + * + * Interrupt Controller support for SH5 INTC. + * Per-interrupt selective. IRLM=0 (Fixed priority) is not + * supported being useless without a cascaded interrupt + * controller. + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include /* this includes also +#include +#include + +/* + * Maybe the generic Peripheral block could move to a more + * generic include file. INTC Block will be defined here + * and only here to make INTC self-contained in a single + * file. + */ +#define INTC_BLOCK_OFFSET 0x01000000 + +/* Base */ +#define INTC_BASE PHYS_PERIPHERAL_BLOCK + \ + INTC_BLOCK_OFFSET + +/* Address */ +#define INTC_ICR_SET (intc_virt + 0x0) +#define INTC_ICR_CLEAR (intc_virt + 0x8) +#define INTC_INTPRI_0 (intc_virt + 0x10) +#define INTC_INTSRC_0 (intc_virt + 0x50) +#define INTC_INTSRC_1 (intc_virt + 0x58) +#define INTC_INTREQ_0 (intc_virt + 0x60) +#define INTC_INTREQ_1 (intc_virt + 0x68) +#define INTC_INTENB_0 (intc_virt + 0x70) +#define INTC_INTENB_1 (intc_virt + 0x78) +#define INTC_INTDSB_0 (intc_virt + 0x80) +#define INTC_INTDSB_1 (intc_virt + 0x88) + +#define INTC_ICR_IRLM 0x1 +#define INTC_INTPRI_PREGS 8 /* 8 Priority Registers */ +#define INTC_INTPRI_PPREG 8 /* 8 Priorities per Register */ + + +/* + * Mapper between the vector ordinal and the IRQ number + * passed to kernel/device drivers. + */ +int intc_evt_to_irq[(0xE20/0x20)+1] = { + -1, -1, -1, -1, -1, -1, -1, -1, /* 0x000 - 0x0E0 */ + -1, -1, -1, -1, -1, -1, -1, -1, /* 0x100 - 0x1E0 */ + 0, 0, 0, 0, 0, 1, 0, 0, /* 0x200 - 0x2E0 */ + 2, 0, 0, 3, 0, 0, 0, -1, /* 0x300 - 0x3E0 */ + 32, 33, 34, 35, 36, 37, 38, -1, /* 0x400 - 0x4E0 */ + -1, -1, -1, 63, -1, -1, -1, -1, /* 0x500 - 0x5E0 */ + -1, -1, 18, 19, 20, 21, 22, -1, /* 0x600 - 0x6E0 */ + 39, 40, 41, 42, -1, -1, -1, -1, /* 0x700 - 0x7E0 */ + 4, 5, 6, 7, -1, -1, -1, -1, /* 0x800 - 0x8E0 */ + -1, -1, -1, -1, -1, -1, -1, -1, /* 0x900 - 0x9E0 */ + 12, 13, 14, 15, 16, 17, -1, -1, /* 0xA00 - 0xAE0 */ + -1, -1, -1, -1, -1, -1, -1, -1, /* 0xB00 - 0xBE0 */ + -1, -1, -1, -1, -1, -1, -1, -1, /* 0xC00 - 0xCE0 */ + -1, -1, -1, -1, -1, -1, -1, -1, /* 0xD00 - 0xDE0 */ + -1, -1 /* 0xE00 - 0xE20 */ +}; + +/* + * Opposite mapper. + */ +static int IRQ_to_vectorN[NR_INTC_IRQS] = { + 0x12, 0x15, 0x18, 0x1B, 0x40, 0x41, 0x42, 0x43, /* 0- 7 */ + -1, -1, -1, -1, 0x50, 0x51, 0x52, 0x53, /* 8-15 */ + 0x54, 0x55, 0x32, 0x33, 0x34, 0x35, 0x36, -1, /* 16-23 */ + -1, -1, -1, -1, -1, -1, -1, -1, /* 24-31 */ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x38, /* 32-39 */ + 0x39, 0x3A, 0x3B, -1, -1, -1, -1, -1, /* 40-47 */ + -1, -1, -1, -1, -1, -1, -1, -1, /* 48-55 */ + -1, -1, -1, -1, -1, -1, -1, 0x2B, /* 56-63 */ + +}; + +static unsigned long intc_virt; + +static unsigned int startup_intc_irq(unsigned int irq); +static void shutdown_intc_irq(unsigned int irq); +static void enable_intc_irq(unsigned int irq); +static void disable_intc_irq(unsigned int irq); +static void mask_and_ack_intc(unsigned int); +static void end_intc_irq(unsigned int irq); + +static struct hw_interrupt_type intc_irq_type = { + "INTC", + startup_intc_irq, + shutdown_intc_irq, + enable_intc_irq, + disable_intc_irq, + mask_and_ack_intc, + end_intc_irq +}; + +static int irlm; /* IRL mode */ + +static unsigned int startup_intc_irq(unsigned int irq) +{ + enable_intc_irq(irq); + return 0; /* never anything pending */ +} + +static void shutdown_intc_irq(unsigned int irq) +{ + disable_intc_irq(irq); +} + +static void enable_intc_irq(unsigned int irq) +{ + unsigned long reg; + unsigned long bitmask; + + if ((irq <= IRQ_IRL3) && (irlm == NO_PRIORITY)) + printk("Trying to use straight IRL0-3 with an encoding platform.\n"); + + if (irq < 32) { + reg = INTC_INTENB_0; + bitmask = 1 << irq; + } else { + reg = INTC_INTENB_1; + bitmask = 1 << (irq - 32); + } + + ctrl_outl(bitmask, reg); +} + +static void disable_intc_irq(unsigned int irq) +{ + unsigned long reg; + unsigned long bitmask; + + if (irq < 32) { + reg = INTC_INTDSB_0; + bitmask = 1 << irq; + } else { + reg = INTC_INTDSB_1; + bitmask = 1 << (irq - 32); + } + + ctrl_outl(bitmask, reg); +} + +static void mask_and_ack_intc(unsigned int irq) +{ + disable_intc_irq(irq); +} + +static void end_intc_irq(unsigned int irq) +{ + enable_intc_irq(irq); +} + +/* For future use, if we ever support IRLM=0) */ +void make_intc_irq(unsigned int irq) +{ + disable_irq_nosync(irq); + irq_desc[irq].handler = &intc_irq_type; + disable_intc_irq(irq); +} + +#if defined(CONFIG_PROC_FS) && defined(CONFIG_SYSCTL) +int intc_irq_describe(char* p, int irq) +{ + if (irq < NR_INTC_IRQS) + return sprintf(p, "(0x%3x)", IRQ_to_vectorN[irq]*0x20); + else + return 0; +} +#endif + +void __init init_IRQ(void) +{ + unsigned long long __dummy0, __dummy1=~0x00000000100000f0; + unsigned long reg; + unsigned long data; + int i; + + intc_virt = onchip_remap(INTC_BASE, 1024, "INTC"); + if (!intc_virt) { + panic("Unable to remap INTC\n"); + } + + + /* Set default: per-line enable/disable, priority driven ack/eoi */ + for (i = 0; i < NR_INTC_IRQS; i++) { + if (platform_int_priority[i] != NO_PRIORITY) { + irq_desc[i].handler = &intc_irq_type; + } + } + + + /* Disable all interrupts and set all priorities to 0 to avoid trouble */ + ctrl_outl(-1, INTC_INTDSB_0); + ctrl_outl(-1, INTC_INTDSB_1); + + for (reg = INTC_INTPRI_0, i = 0; i < INTC_INTPRI_PREGS; i++, reg += 8) + ctrl_outl( NO_PRIORITY, reg); + + + /* Set IRLM */ + /* If all the priorities are set to 'no priority', then + * assume we are using encoded mode. + */ + irlm = platform_int_priority[IRQ_IRL0] + platform_int_priority[IRQ_IRL1] + \ + platform_int_priority[IRQ_IRL2] + platform_int_priority[IRQ_IRL3]; + + if (irlm == NO_PRIORITY) { + /* IRLM = 0 */ + reg = INTC_ICR_CLEAR; + i = IRQ_INTA; + printk("Trying to use encoded IRL0-3. IRLs unsupported.\n"); + } else { + /* IRLM = 1 */ + reg = INTC_ICR_SET; + i = IRQ_IRL0; + } + ctrl_outl(INTC_ICR_IRLM, reg); + + /* Set interrupt priorities according to platform description */ + for (data = 0, reg = INTC_INTPRI_0; i < NR_INTC_IRQS; i++) { + data |= platform_int_priority[i] << ((i % INTC_INTPRI_PPREG) * 4); + if ((i % INTC_INTPRI_PPREG) == (INTC_INTPRI_PPREG - 1)) { + /* Upon the 7th, set Priority Register */ + ctrl_outl(data, reg); + data = 0; + reg += 8; + } + } + +#ifdef CONFIG_SH_CAYMAN + { + extern void init_cayman_irq(void); + + init_cayman_irq(); + } +#endif + + /* + * And now let interrupts come in. + * sti() is not enough, we need to + * lower priority, too. + */ + __asm__ __volatile__("getcon " __SR ", %0\n\t" + "and %0, %1, %0\n\t" + "putcon %0, " __SR "\n\t" + : "=&r" (__dummy0) + : "r" (__dummy1)); +} diff -puN /dev/null arch/sh64/kernel/led.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/kernel/led.c 2004-06-28 13:30:30.659142944 -0700 @@ -0,0 +1,41 @@ +/* + * arch/sh64/kernel/led.c + * + * Copyright (C) 2002 Stuart Menefy + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * Flash the LEDs + */ +#include +#include +#include + +void mach_led(int pos, int val); + +/* acts like an actual heart beat -- ie thump-thump-pause... */ +void heartbeat(void) +{ + static unsigned int cnt = 0, period = 0, dist = 0; + + if (cnt == 0 || cnt == dist) { + mach_led(-1, 1); + } else if (cnt == 7 || cnt == dist + 7) { + mach_led(-1, 0); + } + + if (++cnt > period) { + cnt = 0; + + /* + * The hyperbolic function below modifies the heartbeat period + * length in dependency of the current (5min) load. It goes + * through the points f(0)=126, f(1)=86, f(5)=51, f(inf)->30. + */ + period = ((672 << FSHIFT) / (5 * avenrun[0] + + (7 << FSHIFT))) + 30; + dist = period / 4; + } +} + diff -puN /dev/null arch/sh64/kernel/Makefile --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/kernel/Makefile 2004-06-28 13:30:30.660142792 -0700 @@ -0,0 +1,38 @@ +# +# 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) 2000, 2001 Paolo Alberelli +# Copyright (C) 2003 Paul Mundt +# +# Makefile for the Linux sh64 kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +extra-y := head.o init_task.o vmlinux.lds.s + +obj-y := process.o signal.o entry.o traps.o irq.o irq_intc.o \ + ptrace.o setup.o time.o sys_sh64.o semaphore.o sh_ksyms.o \ + switchto.o syscalls.o + +obj-$(CONFIG_HEARTBEAT) += led.o +obj-$(CONFIG_SH_ALPHANUMERIC) += alphanum.o +obj-$(CONFIG_SH_DMA) += dma.o +obj-$(CONFIG_EARLY_PRINTK) += early_printk.o +obj-$(CONFIG_KALLSYMS) += unwind.o +obj-$(CONFIG_PCI) += pci-dma.o pcibios.o + +ifeq ($(CONFIG_PCI),y) +obj-$(CONFIG_CPU_SH5) += pci_sh5.o +endif + +ifndef CONFIG_NOFPU_SUPPORT +obj-y += fpu.o +endif + +USE_STANDARD_AS_RULE := true + diff -puN /dev/null arch/sh64/kernel/pcibios.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/kernel/pcibios.c 2004-06-28 13:30:30.661142640 -0700 @@ -0,0 +1,168 @@ +/* + * $Id: pcibios.c,v 1.1 2001/08/24 12:38:19 dwmw2 Exp $ + * + * arch/sh/kernel/pcibios.c + * + * Copyright (C) 2002 STMicroelectronics Limited + * Author : David J. McKay + * + * Copyright (C) 2004 Richard Curnow, SuperH UK Limited + * + * 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. + * This is GPL'd. + * + * Provided here are generic versions of: + * pcibios_update_resource() + * pcibios_align_resource() + * pcibios_enable_device() + * pcibios_set_master() + * pcibios_update_irq() + * + * These functions are collected here to reduce duplication of common + * code amongst the many platform-specific PCI support code files. + * + * Platform-specific files are expected to provide: + * pcibios_fixup_bus() + * pcibios_init() + * pcibios_setup() + * pcibios_fixup_pbus_ranges() + */ + +#include +#include +#include + +void +pcibios_update_resource(struct pci_dev *dev, struct resource *root, + struct resource *res, int resource) +{ + u32 new, check; + int reg; + + new = res->start | (res->flags & PCI_REGION_FLAG_MASK); + if (resource < 6) { + reg = PCI_BASE_ADDRESS_0 + 4*resource; + } else if (resource == PCI_ROM_RESOURCE) { + res->flags |= PCI_ROM_ADDRESS_ENABLE; + new |= PCI_ROM_ADDRESS_ENABLE; + reg = dev->rom_base_reg; + } else { + /* Somebody might have asked allocation of a non-standard resource */ + return; + } + + pci_write_config_dword(dev, reg, new); + pci_read_config_dword(dev, reg, &check); + if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) { + printk(KERN_ERR "PCI: Error while updating region " + "%s/%d (%08x != %08x)\n", dev->slot_name, resource, + new, check); + } +} + +/* + * We need to avoid collisions with `mirrored' VGA ports + * and other strange ISA hardware, so we always want the + * addresses to be allocated in the 0x000-0x0ff region + * modulo 0x400. + */ +void pcibios_align_resource(void *data, struct resource *res, + unsigned long size, unsigned long align) +{ + if (res->flags & IORESOURCE_IO) { + unsigned long start = res->start; + + if (start & 0x300) { + start = (start + 0x3ff) & ~0x3ff; + res->start = start; + } + } +} + +static void pcibios_enable_bridge(struct pci_dev *dev) +{ + struct pci_bus *bus = dev->subordinate; + u16 cmd, old_cmd; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + old_cmd = cmd; + + if (bus->resource[0]->flags & IORESOURCE_IO) { + cmd |= PCI_COMMAND_IO; + } + if ((bus->resource[1]->flags & IORESOURCE_MEM) || + (bus->resource[2]->flags & IORESOURCE_PREFETCH)) { + cmd |= PCI_COMMAND_MEMORY; + } + + if (cmd != old_cmd) { + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + + printk("PCI bridge %s, command register -> %04x\n", + pci_name(dev), cmd); + +} + + + +int pcibios_enable_device(struct pci_dev *dev, int mask) +{ + u16 cmd, old_cmd; + int idx; + struct resource *r; + + if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { + pcibios_enable_bridge(dev); + } + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + old_cmd = cmd; + for(idx=0; idx<6; idx++) { + if (!(mask & (1 << idx))) + continue; + r = &dev->resource[idx]; + if (!r->start && r->end) { + printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name); + return -EINVAL; + } + if (r->flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + if (r->flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + } + if (dev->resource[PCI_ROM_RESOURCE].start) + cmd |= PCI_COMMAND_MEMORY; + if (cmd != old_cmd) { + printk(KERN_INFO "PCI: Enabling device %s (%04x -> %04x)\n", pci_name(dev), old_cmd, cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + return 0; +} + +/* + * If we set up a device for bus mastering, we need to check and set + * the latency timer as it may not be properly set. + */ +unsigned int pcibios_max_latency = 255; + +void pcibios_set_master(struct pci_dev *dev) +{ + u8 lat; + pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); + if (lat < 16) + lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency; + else if (lat > pcibios_max_latency) + lat = pcibios_max_latency; + else + return; + printk(KERN_INFO "PCI: Setting latency timer of device %s to %d\n", pci_name(dev), lat); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); +} + +void __init pcibios_update_irq(struct pci_dev *dev, int irq) +{ + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); +} diff -puN /dev/null arch/sh64/kernel/pci-dma.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/kernel/pci-dma.c 2004-06-28 13:30:30.661142640 -0700 @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2001 David J. Mckay (david.mckay@st.com) + * Copyright (C) 2003 Paul Mundt (lethal@linux-sh.org) + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * Dynamic DMA mapping support. + */ +#include +#include +#include +#include +#include + +void *consistent_alloc(struct pci_dev *hwdev, size_t size, + dma_addr_t *dma_handle) +{ + void *ret; + int gfp = GFP_ATOMIC; + void *vp; + + if (hwdev == NULL || hwdev->dma_mask != 0xffffffff) + gfp |= GFP_DMA; + + ret = (void *)__get_free_pages(gfp, get_order(size)); + + /* now call our friend ioremap_nocache to give us an uncached area */ + vp = ioremap_nocache(virt_to_phys(ret), size); + + if (vp != NULL) { + memset(vp, 0, size); + *dma_handle = virt_to_bus(ret); + dma_cache_wback_inv((unsigned long)ret, size); + } + + return vp; +} + +void consistent_free(struct pci_dev *hwdev, size_t size, + void *vaddr, dma_addr_t dma_handle) +{ + void *alloc; + + alloc = bus_to_virt((unsigned long)dma_handle); + free_pages((unsigned long)alloc, get_order(size)); + + iounmap(vaddr); +} + diff -puN /dev/null arch/sh64/kernel/pci_sh5.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/kernel/pci_sh5.c 2004-06-28 13:30:30.664142184 -0700 @@ -0,0 +1,546 @@ +/* + * Copyright (C) 2001 David J. Mckay (david.mckay@st.com) + * Copyright (C) 2003, 2004 Paul Mundt + * Copyright (C) 2004 Richard Curnow + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * Support functions for the SH5 PCI hardware. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "pci_sh5.h" + +static unsigned long pcicr_virt; +unsigned long pciio_virt; + +static void __init pci_fixup_ide_bases(struct pci_dev *d) +{ + int i; + + /* + * PCI IDE controllers use non-standard I/O port decoding, respect it. + */ + if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE) + return; + printk("PCI: IDE base address fixup for %s\n", d->slot_name); + for(i=0; i<4; i++) { + struct resource *r = &d->resource[i]; + if ((r->start & ~0x80) == 0x374) { + r->start |= 2; + r->end = r->start; + } + } +} + +/* Add future fixups here... */ +struct pci_fixup pcibios_fixups[] = { + { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases }, + { 0 } +}; + +char * __init pcibios_setup(char *str) +{ + return str; +} + +/* Rounds a number UP to the nearest power of two. Used for + * sizing the PCI window. + */ +static u32 __init r2p2(u32 num) +{ + int i = 31; + u32 tmp = num; + + if (num == 0) + return 0; + + do { + if (tmp & (1 << 31)) + break; + i--; + tmp <<= 1; + } while (i >= 0); + + tmp = 1 << i; + /* If the original number isn't a power of 2, round it up */ + if (tmp != num) + tmp <<= 1; + + return tmp; +} + +extern unsigned long long memory_start, memory_end; + +int __init sh5pci_init(unsigned memStart, unsigned memSize) +{ + u32 lsr0; + u32 uval; + + pcicr_virt = onchip_remap(SH5PCI_ICR_BASE, 1024, "PCICR"); + if (!pcicr_virt) { + panic("Unable to remap PCICR\n"); + } + + pciio_virt = onchip_remap(SH5PCI_IO_BASE, 0x10000, "PCIIO"); + if (!pciio_virt) { + panic("Unable to remap PCIIO\n"); + } + + pr_debug("Register base addres is 0x%08lx\n", pcicr_virt); + + /* Clear snoop registers */ + SH5PCI_WRITE(CSCR0, 0); + SH5PCI_WRITE(CSCR1, 0); + + pr_debug("Wrote to reg\n"); + + /* Switch off interrupts */ + SH5PCI_WRITE(INTM, 0); + SH5PCI_WRITE(AINTM, 0); + SH5PCI_WRITE(PINTM, 0); + + /* Set bus active, take it out of reset */ + uval = SH5PCI_READ(CR); + + /* Set command Register */ + SH5PCI_WRITE(CR, uval | CR_LOCK_MASK | CR_CFINT| CR_FTO | CR_PFE | CR_PFCS | CR_BMAM); + + uval=SH5PCI_READ(CR); + pr_debug("CR is actually 0x%08x\n",uval); + + /* Allow it to be a master */ + /* NB - WE DISABLE I/O ACCESS to stop overlap */ + /* set WAIT bit to enable stepping, an attempt to improve stability */ + SH5PCI_WRITE_SHORT(CSR_CMD, + PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_WAIT); + + /* + ** Set translation mapping memory in order to convert the address + ** used for the main bus, to the PCI internal address. + */ + SH5PCI_WRITE(MBR,0x40000000); + + /* Always set the max size 512M */ + SH5PCI_WRITE(MBMR, PCISH5_MEM_SIZCONV(512*1024*1024)); + + /* + ** I/O addresses are mapped at internal PCI specific address + ** as is described into the configuration bridge table. + ** These are changed to 0, to allow cards that have legacy + ** io such as vga to function correctly. We set the SH5 IOBAR to + ** 256K, which is a bit big as we can only have 64K of address space + */ + + SH5PCI_WRITE(IOBR,0x0); + + pr_debug("PCI:Writing 0x%08x to IOBR\n",0); + + /* Set up a 256K window. Totally pointless waste of address space */ + SH5PCI_WRITE(IOBMR,0); + pr_debug("PCI:Writing 0x%08x to IOBMR\n",0); + + /* The SH5 has a HUGE 256K I/O region, which breaks the PCI spec. Ideally, + * we would want to map the I/O region somewhere, but it is so big this is not + * that easy! + */ + SH5PCI_WRITE(CSR_IBAR0,~0); + /* Set memory size value */ + memSize = memory_end - memory_start; + + /* Now we set up the mbars so the PCI bus can see the memory of the machine */ + if (memSize < (1024 * 1024)) { + printk(KERN_ERR "PCISH5: Ridiculous memory size of 0x%x?\n", memSize); + return -EINVAL; + } + + /* Set LSR 0 */ + lsr0 = (memSize > (512 * 1024 * 1024)) ? 0x1ff00001 : ((r2p2(memSize) - 0x100000) | 0x1); + SH5PCI_WRITE(LSR0, lsr0); + + pr_debug("PCI:Writing 0x%08x to LSR0\n",lsr0); + + /* Set MBAR 0 */ + SH5PCI_WRITE(CSR_MBAR0, memory_start); + SH5PCI_WRITE(LAR0, memory_start); + + SH5PCI_WRITE(CSR_MBAR1,0); + SH5PCI_WRITE(LAR1,0); + SH5PCI_WRITE(LSR1,0); + + pr_debug("PCI:Writing 0x%08llx to CSR_MBAR0\n",memory_start); + pr_debug("PCI:Writing 0x%08llx to LAR0\n",memory_start); + + /* Enable the PCI interrupts on the device */ + SH5PCI_WRITE(INTM, ~0); + SH5PCI_WRITE(AINTM, ~0); + SH5PCI_WRITE(PINTM, ~0); + + pr_debug("Switching on all error interrupts\n"); + + return(0); +} + +static int sh5pci_read(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 *val) +{ + SH5PCI_WRITE(PAR, CONFIG_CMD(bus, devfn, where)); + + switch (size) { + case 1: + *val = (u8)SH5PCI_READ_BYTE(PDR + (where & 3)); + break; + case 2: + *val = (u16)SH5PCI_READ_SHORT(PDR + (where & 2)); + break; + case 4: + *val = SH5PCI_READ(PDR); + break; + } + + return PCIBIOS_SUCCESSFUL; +} + +static int sh5pci_write(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 val) +{ + SH5PCI_WRITE(PAR, CONFIG_CMD(bus, devfn, where)); + + switch (size) { + case 1: + SH5PCI_WRITE_BYTE(PDR + (where & 3), (u8)val); + break; + case 2: + SH5PCI_WRITE_SHORT(PDR + (where & 2), (u16)val); + break; + case 4: + SH5PCI_WRITE(PDR, val); + break; + } + + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops pci_config_ops = { + .read = sh5pci_read, + .write = sh5pci_write, +}; + +/* Everything hangs off this */ +static struct pci_bus *pci_root_bus; + + +static u8 __init no_swizzle(struct pci_dev *dev, u8 * pin) +{ + pr_debug("swizzle for dev %d on bus %d slot %d pin is %d\n", + dev->devfn,dev->bus->number, PCI_SLOT(dev->devfn),*pin); + return PCI_SLOT(dev->devfn); +} + +static inline u8 bridge_swizzle(u8 pin, u8 slot) +{ + return (((pin-1) + slot) % 4) + 1; +} + +u8 __init common_swizzle(struct pci_dev *dev, u8 *pinp) +{ + if (dev->bus->number != 0) { + u8 pin = *pinp; + do { + pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); + /* Move up the chain of bridges. */ + dev = dev->bus->self; + } while (dev->bus->self); + *pinp = pin; + + /* The slot is the slot of the last bridge. */ + } + + return PCI_SLOT(dev->devfn); +} + +/* This needs to be shunted out of here into the board specific bit */ + +static int __init map_cayman_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + int result = -1; + + /* The complication here is that the PCI IRQ lines from the Cayman's 2 + 5V slots get into the CPU via a different path from the IRQ lines + from the 3 3.3V slots. Thus, we have to detect whether the card's + interrupts go via the 5V or 3.3V path, i.e. the 'bridge swizzling' + at the point where we cross from 5V to 3.3V is not the normal case. + + The added complication is that we don't know that the 5V slots are + always bus 2, because a card containing a PCI-PCI bridge may be + plugged into a 3.3V slot, and this changes the bus numbering. + + Also, the Cayman has an intermediate PCI bus that goes a custom + expansion board header (and to the secondary bridge). This bus has + never been used in practice. + + The 1ary onboard PCI-PCI bridge is device 3 on bus 0 + The 2ary onboard PCI-PCI bridge is device 0 on the 2ary bus of the 1ary bridge. + */ + + struct slot_pin { + int slot; + int pin; + } path[4]; + int i=0; + + while (dev->bus->number > 0) { + + slot = path[i].slot = PCI_SLOT(dev->devfn); + pin = path[i].pin = bridge_swizzle(pin, slot); + dev = dev->bus->self; + i++; + if (i > 3) panic("PCI path to root bus too long!\n"); + } + + slot = PCI_SLOT(dev->devfn); + /* This is the slot on bus 0 through which the device is eventually + reachable. */ + + /* Now work back up. */ + if ((slot < 3) || (i == 0)) { + /* Bus 0 (incl. PCI-PCI bridge itself) : perform the final + swizzle now. */ + result = IRQ_INTA + bridge_swizzle(pin, slot) - 1; + } else { + i--; + slot = path[i].slot; + pin = path[i].pin; + if (slot > 0) { + panic("PCI expansion bus device found - not handled!\n"); + } else { + if (i > 0) { + /* 5V slots */ + i--; + slot = path[i].slot; + pin = path[i].pin; + /* 'pin' was swizzled earlier wrt slot, don't do it again. */ + result = IRQ_P2INTA + (pin - 1); + } else { + /* IRQ for 2ary PCI-PCI bridge : unused */ + result = -1; + } + } + } + + return result; +} + +irqreturn_t pcish5_err_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned pci_int, pci_air, pci_cir, pci_aint; + + pci_int = SH5PCI_READ(INT); + pci_cir = SH5PCI_READ(CIR); + pci_air = SH5PCI_READ(AIR); + + if (pci_int) { + printk("PCI INTERRUPT (at %08llx)!\n", regs->pc); + printk("PCI INT -> 0x%x\n", pci_int & 0xffff); + printk("PCI AIR -> 0x%x\n", pci_air); + printk("PCI CIR -> 0x%x\n", pci_cir); + SH5PCI_WRITE(INT, ~0); + } + + pci_aint = SH5PCI_READ(AINT); + if (pci_aint) { + printk("PCI ARB INTERRUPT!\n"); + printk("PCI AINT -> 0x%x\n", pci_aint); + printk("PCI AIR -> 0x%x\n", pci_air); + printk("PCI CIR -> 0x%x\n", pci_cir); + SH5PCI_WRITE(AINT, ~0); + } + + return IRQ_HANDLED; +} + +irqreturn_t pcish5_serr_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + printk("SERR IRQ\n"); + + return IRQ_NONE; +} + +#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1)) + +static void __init +pcibios_size_bridge(struct pci_bus *bus, struct resource *ior, + struct resource *memr) +{ + struct resource io_res, mem_res; + struct pci_dev *dev; + struct pci_dev *bridge = bus->self; + struct list_head *ln; + + if (!bridge) + return; /* host bridge, nothing to do */ + + /* set reasonable default locations for pcibios_align_resource */ + io_res.start = PCIBIOS_MIN_IO; + mem_res.start = PCIBIOS_MIN_MEM; + + io_res.end = io_res.start; + mem_res.end = mem_res.start; + + /* Collect information about how our direct children are layed out. */ + for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) { + int i; + dev = pci_dev_b(ln); + + /* Skip bridges for now */ + if (dev->class >> 8 == PCI_CLASS_BRIDGE_PCI) + continue; + + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + struct resource res; + unsigned long size; + + memcpy(&res, &dev->resource[i], sizeof(res)); + size = res.end - res.start + 1; + + if (res.flags & IORESOURCE_IO) { + res.start = io_res.end; + pcibios_align_resource(dev, &res, size, 0); + io_res.end = res.start + size; + } else if (res.flags & IORESOURCE_MEM) { + res.start = mem_res.end; + pcibios_align_resource(dev, &res, size, 0); + mem_res.end = res.start + size; + } + } + } + + /* And for all of the subordinate busses. */ + for (ln=bus->children.next; ln != &bus->children; ln=ln->next) + pcibios_size_bridge(pci_bus_b(ln), &io_res, &mem_res); + + /* turn the ending locations into sizes (subtract start) */ + io_res.end -= io_res.start; + mem_res.end -= mem_res.start; + + /* Align the sizes up by bridge rules */ + io_res.end = ROUND_UP(io_res.end, 4*1024) - 1; + mem_res.end = ROUND_UP(mem_res.end, 1*1024*1024) - 1; + + /* Adjust the bridge's allocation requirements */ + bridge->resource[0].end = bridge->resource[0].start + io_res.end; + bridge->resource[1].end = bridge->resource[1].start + mem_res.end; + + bridge->resource[PCI_BRIDGE_RESOURCES].end = + bridge->resource[PCI_BRIDGE_RESOURCES].start + io_res.end; + bridge->resource[PCI_BRIDGE_RESOURCES+1].end = + bridge->resource[PCI_BRIDGE_RESOURCES+1].start + mem_res.end; + + /* adjust parent's resource requirements */ + if (ior) { + ior->end = ROUND_UP(ior->end, 4*1024); + ior->end += io_res.end; + } + + if (memr) { + memr->end = ROUND_UP(memr->end, 1*1024*1024); + memr->end += mem_res.end; + } +} + +#undef ROUND_UP + +static void __init pcibios_size_bridges(void) +{ + struct resource io_res, mem_res; + + memset(&io_res, 0, sizeof(io_res)); + memset(&mem_res, 0, sizeof(mem_res)); + + pcibios_size_bridge(pci_root_bus, &io_res, &mem_res); +} + +static int __init pcibios_init(void) +{ + if (request_irq(IRQ_ERR, pcish5_err_irq, + SA_INTERRUPT, "PCI Error",NULL) < 0) { + printk(KERN_ERR "PCISH5: Cannot hook PCI_PERR interrupt\n"); + return -EINVAL; + } + + if (request_irq(IRQ_SERR, pcish5_serr_irq, + SA_INTERRUPT, "PCI SERR interrupt", NULL) < 0) { + printk(KERN_ERR "PCISH5: Cannot hook PCI_SERR interrupt\n"); + return -EINVAL; + } + + /* The pci subsytem needs to know where memory is and how much + * of it there is. I've simply made these globals. A better mechanism + * is probably needed. + */ + sh5pci_init(__pa(memory_start), + __pa(memory_end) - __pa(memory_start)); + + pci_root_bus = pci_scan_bus(0, &pci_config_ops, NULL); + pcibios_size_bridges(); + pci_assign_unassigned_resources(); + pci_fixup_irqs(no_swizzle, map_cayman_irq); + + return 0; +} + +subsys_initcall(pcibios_init); + +void __init pcibios_fixup_bus(struct pci_bus *bus) +{ + struct pci_dev *dev = bus->self; + int i; + +#if 1 + if(dev) { + for(i=0; i<3; i++) { + bus->resource[i] = + &dev->resource[PCI_BRIDGE_RESOURCES+i]; + bus->resource[i]->name = bus->name; + } + bus->resource[0]->flags |= IORESOURCE_IO; + bus->resource[1]->flags |= IORESOURCE_MEM; + + /* For now, propogate host limits to the bus; + * we'll adjust them later. */ + +#if 1 + bus->resource[0]->end = 64*1024 - 1 ; + bus->resource[1]->end = PCIBIOS_MIN_MEM+(256*1024*1024)-1; + bus->resource[0]->start = PCIBIOS_MIN_IO; + bus->resource[1]->start = PCIBIOS_MIN_MEM; +#else + bus->resource[0]->end = 0 + bus->resource[1]->end = 0 + bus->resource[0]->start =0 + bus->resource[1]->start = 0; +#endif + /* Turn off downstream PF memory address range by default */ + bus->resource[2]->start = 1024*1024; + bus->resource[2]->end = bus->resource[2]->start - 1; + } +#endif + +} + diff -puN /dev/null arch/sh64/kernel/pci_sh5.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/kernel/pci_sh5.h 2004-06-28 13:30:30.665142032 -0700 @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2001 David J. Mckay (david.mckay@st.com) + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * Defintions for the SH5 PCI hardware. + */ + +/* Product ID */ +#define PCISH5_PID 0x350d + +/* vendor ID */ +#define PCISH5_VID 0x1054 + +/* Configuration types */ +#define ST_TYPE0 0x00 /* Configuration cycle type 0 */ +#define ST_TYPE1 0x01 /* Configuration cycle type 1 */ + +/* VCR data */ +#define PCISH5_VCR_STATUS 0x00 +#define PCISH5_VCR_VERSION 0x08 + +/* +** ICR register offsets and bits +*/ +#define PCISH5_ICR_CR 0x100 /* PCI control register values */ +#define CR_PBAM (1<<12) +#define CR_PFCS (1<<11) +#define CR_FTO (1<<10) +#define CR_PFE (1<<9) +#define CR_TBS (1<<8) +#define CR_SPUE (1<<7) +#define CR_BMAM (1<<6) +#define CR_HOST (1<<5) +#define CR_CLKEN (1<<4) +#define CR_SOCS (1<<3) +#define CR_IOCS (1<<2) +#define CR_RSTCTL (1<<1) +#define CR_CFINT (1<<0) +#define CR_LOCK_MASK 0xa5000000 + +#define PCISH5_ICR_INT 0x114 /* Interrupt registert values */ +#define INT_MADIM (1<<2) + +#define PCISH5_ICR_LSR0 0X104 /* Local space register values */ +#define PCISH5_ICR_LSR1 0X108 /* Local space register values */ +#define PCISH5_ICR_LAR0 0x10c /* Local address register values */ +#define PCISH5_ICR_LAR1 0x110 /* Local address register values */ +#define PCISH5_ICR_INTM 0x118 /* Interrupt mask register values */ +#define PCISH5_ICR_AIR 0x11c /* Interrupt error address information register values */ +#define PCISH5_ICR_CIR 0x120 /* Interrupt error command information register values */ +#define PCISH5_ICR_AINT 0x130 /* Interrupt error arbiter interrupt register values */ +#define PCISH5_ICR_AINTM 0x134 /* Interrupt error arbiter interrupt mask register values */ +#define PCISH5_ICR_BMIR 0x138 /* Interrupt error info register of bus master values */ +#define PCISH5_ICR_PAR 0x1c0 /* Pio address register values */ +#define PCISH5_ICR_MBR 0x1c4 /* Memory space bank register values */ +#define PCISH5_ICR_IOBR 0x1c8 /* I/O space bank register values */ +#define PCISH5_ICR_PINT 0x1cc /* power management interrupt register values */ +#define PCISH5_ICR_PINTM 0x1d0 /* power management interrupt mask register values */ +#define PCISH5_ICR_MBMR 0x1d8 /* memory space bank mask register values */ +#define PCISH5_ICR_IOBMR 0x1dc /* I/O space bank mask register values */ +#define PCISH5_ICR_CSCR0 0x210 /* PCI cache snoop control register 0 */ +#define PCISH5_ICR_CSCR1 0x214 /* PCI cache snoop control register 1 */ +#define PCISH5_ICR_PDR 0x220 /* Pio data register values */ + +/* These are configs space registers */ +#define PCISH5_ICR_CSR_VID 0x000 /* Vendor id */ +#define PCISH5_ICR_CSR_DID 0x002 /* Device id */ +#define PCISH5_ICR_CSR_CMD 0x004 /* Command register */ +#define PCISH5_ICR_CSR_STATUS 0x006 /* Stautus */ +#define PCISH5_ICR_CSR_IBAR0 0x010 /* I/O base address register */ +#define PCISH5_ICR_CSR_MBAR0 0x014 /* First Memory base address register */ +#define PCISH5_ICR_CSR_MBAR1 0x018 /* Second Memory base address register */ + + + +/* Base address of registers */ +#define SH5PCI_ICR_BASE (PHYS_PCI_BLOCK + 0x00040000) +#define SH5PCI_IO_BASE (PHYS_PCI_BLOCK + 0x00800000) +/* #define SH5PCI_VCR_BASE (P2SEG_PCICB_BLOCK + P2SEG) */ + +/* Register selection macro */ +#define PCISH5_ICR_REG(x) ( pcicr_virt + (PCISH5_ICR_##x)) +/* #define PCISH5_VCR_REG(x) ( SH5PCI_VCR_BASE (PCISH5_VCR_##x)) */ + +/* Write I/O functions */ +#define SH5PCI_WRITE(reg,val) ctrl_outl((u32)(val),PCISH5_ICR_REG(reg)) +#define SH5PCI_WRITE_SHORT(reg,val) ctrl_outw((u16)(val),PCISH5_ICR_REG(reg)) +#define SH5PCI_WRITE_BYTE(reg,val) ctrl_outb((u8)(val),PCISH5_ICR_REG(reg)) + +/* Read I/O functions */ +#define SH5PCI_READ(reg) ctrl_inl(PCISH5_ICR_REG(reg)) +#define SH5PCI_READ_SHORT(reg) ctrl_inw(PCISH5_ICR_REG(reg)) +#define SH5PCI_READ_BYTE(reg) ctrl_inb(PCISH5_ICR_REG(reg)) + +/* Set PCI config bits */ +#define SET_CONFIG_BITS(bus,devfn,where) ((((bus) << 16) | ((devfn) << 8) | ((where) & ~3)) | 0x80000000) + +/* Set PCI command register */ +#define CONFIG_CMD(bus, devfn, where) SET_CONFIG_BITS(bus->number,devfn,where) + +/* Size converters */ +#define PCISH5_MEM_SIZCONV(x) (((x / 0x40000) - 1) << 18) +#define PCISH5_IO_SIZCONV(x) (((x / 0x40000) - 1) << 18) + + diff -puN /dev/null arch/sh64/kernel/process.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/kernel/process.c 2004-06-28 13:30:30.669141424 -0700 @@ -0,0 +1,963 @@ +/* + * 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. + * + * arch/sh64/kernel/process.c + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003 Paul Mundt + * Copyright (C) 2003, 2004 Richard Curnow + * + * Started from SH3/4 version: + * Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima + * + * In turn started from i386 version: + * Copyright (C) 1995 Linus Torvalds + * + */ + +/* + * This file handles the architecture-dependent parts of process handling.. + */ + +/* Temporary flags/tests. All to be removed/undefined. BEGIN */ +#define IDLE_TRACE +#define VM_SHOW_TABLES +#define VM_TEST_FAULT +#define VM_TEST_RTLBMISS +#define VM_TEST_WTLBMISS + +#undef VM_SHOW_TABLES +#undef IDLE_TRACE +/* Temporary flags/tests. All to be removed/undefined. END */ + +#define __KERNEL_SYSCALLS__ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include /* includes also */ +#include +#include +#include + +#include + +struct task_struct *last_task_used_math = NULL; + +#ifdef IDLE_TRACE +#ifdef VM_SHOW_TABLES +/* For testing */ +static void print_PTE(long base) +{ + int i, skip=0; + long long x, y, *p = (long long *) base; + + for (i=0; i< 512; i++, p++){ + if (*p == 0) { + if (!skip) { + skip++; + printk("(0s) "); + } + } else { + skip=0; + x = (*p) >> 32; + y = (*p) & 0xffffffff; + printk("%08Lx%08Lx ", x, y); + if (!((i+1)&0x3)) printk("\n"); + } + } +} + +/* For testing */ +static void print_DIR(long base) +{ + int i, skip=0; + long *p = (long *) base; + + for (i=0; i< 512; i++, p++){ + if (*p == 0) { + if (!skip) { + skip++; + printk("(0s) "); + } + } else { + skip=0; + printk("%08lx ", *p); + if (!((i+1)&0x7)) printk("\n"); + } + } +} + +/* For testing */ +static void print_vmalloc_first_tables(void) +{ + +#define PRESENT 0x800 /* Bit 11 */ + + /* + * Do it really dirty by looking at raw addresses, + * raw offsets, no types. If we used pgtable/pgalloc + * macros/definitions we could hide potential bugs. + * + * Note that pointers are 32-bit for CDC. + */ + long pgdt, pmdt, ptet; + + pgdt = (long) &swapper_pg_dir; + printk("-->PGD (0x%08lx):\n", pgdt); + print_DIR(pgdt); + printk("\n"); + + /* VMALLOC pool is mapped at 0xc0000000, second (pointer) entry in PGD */ + pgdt += 4; + pmdt = (long) (* (long *) pgdt); + if (!(pmdt & PRESENT)) { + printk("No PMD\n"); + return; + } else pmdt &= 0xfffff000; + + printk("-->PMD (0x%08lx):\n", pmdt); + print_DIR(pmdt); + printk("\n"); + + /* Get the pmdt displacement for 0xc0000000 */ + pmdt += 2048; + + /* just look at first two address ranges ... */ + /* ... 0xc0000000 ... */ + ptet = (long) (* (long *) pmdt); + if (!(ptet & PRESENT)) { + printk("No PTE0\n"); + return; + } else ptet &= 0xfffff000; + + printk("-->PTE0 (0x%08lx):\n", ptet); + print_PTE(ptet); + printk("\n"); + + /* ... 0xc0001000 ... */ + ptet += 4; + if (!(ptet & PRESENT)) { + printk("No PTE1\n"); + return; + } else ptet &= 0xfffff000; + printk("-->PTE1 (0x%08lx):\n", ptet); + print_PTE(ptet); + printk("\n"); +} +#else +#define print_vmalloc_first_tables() +#endif /* VM_SHOW_TABLES */ + +static void test_VM(void) +{ + void *a, *b, *c; + +#ifdef VM_SHOW_TABLES + printk("Initial PGD/PMD/PTE\n"); +#endif + print_vmalloc_first_tables(); + + printk("Allocating 2 bytes\n"); + a = vmalloc(2); + print_vmalloc_first_tables(); + + printk("Allocating 4100 bytes\n"); + b = vmalloc(4100); + print_vmalloc_first_tables(); + + printk("Allocating 20234 bytes\n"); + c = vmalloc(20234); + print_vmalloc_first_tables(); + +#ifdef VM_TEST_FAULT + /* Here you may want to fault ! */ + +#ifdef VM_TEST_RTLBMISS + printk("Ready to fault upon read.\n"); + if (* (char *) a) { + printk("RTLBMISSed on area a !\n"); + } + printk("RTLBMISSed on area a !\n"); +#endif + +#ifdef VM_TEST_WTLBMISS + printk("Ready to fault upon write.\n"); + *((char *) b) = 'L'; + printk("WTLBMISSed on area b !\n"); +#endif + +#endif /* VM_TEST_FAULT */ + + printk("Deallocating the 4100 byte chunk\n"); + vfree(b); + print_vmalloc_first_tables(); + + printk("Deallocating the 2 byte chunk\n"); + vfree(a); + print_vmalloc_first_tables(); + + printk("Deallocating the last chunk\n"); + vfree(c); + print_vmalloc_first_tables(); +} + +extern unsigned long volatile jiffies; +int once = 0; +unsigned long old_jiffies; +int pid = -1, pgid = -1; + +void idle_trace(void) +{ + + _syscall0(int, getpid) + _syscall1(int, getpgid, int, pid) + + if (!once) { + /* VM allocation/deallocation simple test */ + test_VM(); + pid = getpid(); + + printk("Got all through to Idle !!\n"); + printk("I'm now going to loop forever ...\n"); + printk("Any ! below is a timer tick.\n"); + printk("Any . below is a getpgid system call from pid = %d.\n", pid); + + + old_jiffies = jiffies; + once++; + } + + if (old_jiffies != jiffies) { + old_jiffies = jiffies - old_jiffies; + switch (old_jiffies) { + case 1: + printk("!"); + break; + case 2: + printk("!!"); + break; + case 3: + printk("!!!"); + break; + case 4: + printk("!!!!"); + break; + default: + printk("(%d!)", (int) old_jiffies); + } + old_jiffies = jiffies; + } + pgid = getpgid(pid); + printk("."); +} +#else +#define idle_trace() do { } while (0) +#endif /* IDLE_TRACE */ + +static int hlt_counter = 1; + +#define HARD_IDLE_TIMEOUT (HZ / 3) + +void disable_hlt(void) +{ + hlt_counter++; +} + +void enable_hlt(void) +{ + hlt_counter--; +} + +static int __init nohlt_setup(char *__unused) +{ + hlt_counter = 1; + return 1; +} + +static int __init hlt_setup(char *__unused) +{ + hlt_counter = 0; + return 1; +} + +__setup("nohlt", nohlt_setup); +__setup("hlt", hlt_setup); + +static inline void hlt(void) +{ + if (hlt_counter) + return; + + __asm__ __volatile__ ("sleep" : : : "memory"); +} + +/* + * The idle loop on a uniprocessor SH.. + */ +void default_idle(void) +{ + /* endless idle loop with no priority at all */ + while (1) { + if (hlt_counter) { + while (1) + if (need_resched()) + break; + } else { + local_irq_disable(); + while (!need_resched()) { + local_irq_enable(); + idle_trace(); + hlt(); + local_irq_disable(); + } + local_irq_enable(); + } + schedule(); + } +} + +void cpu_idle(void *unused) +{ + default_idle(); +} + +void machine_restart(char * __unused) +{ + extern void phys_stext(void); + + phys_stext(); +} + +void machine_halt(void) +{ + for (;;); +} + +void machine_power_off(void) +{ + extern void enter_deep_standby(void); + + enter_deep_standby(); +} + +void show_regs(struct pt_regs * regs) +{ + unsigned long long ah, al, bh, bl, ch, cl; + + printk("\n"); + + ah = (regs->pc) >> 32; + al = (regs->pc) & 0xffffffff; + bh = (regs->regs[18]) >> 32; + bl = (regs->regs[18]) & 0xffffffff; + ch = (regs->regs[15]) >> 32; + cl = (regs->regs[15]) & 0xffffffff; + printk("PC : %08Lx%08Lx LINK: %08Lx%08Lx SP : %08Lx%08Lx\n", + ah, al, bh, bl, ch, cl); + + ah = (regs->sr) >> 32; + al = (regs->sr) & 0xffffffff; + asm volatile ("getcon " __TEA ", %0" : "=r" (bh)); + asm volatile ("getcon " __TEA ", %0" : "=r" (bl)); + bh = (bh) >> 32; + bl = (bl) & 0xffffffff; + asm volatile ("getcon " __KCR0 ", %0" : "=r" (ch)); + asm volatile ("getcon " __KCR0 ", %0" : "=r" (cl)); + ch = (ch) >> 32; + cl = (cl) & 0xffffffff; + printk("SR : %08Lx%08Lx TEA : %08Lx%08Lx KCR0: %08Lx%08Lx\n", + ah, al, bh, bl, ch, cl); + + ah = (regs->regs[0]) >> 32; + al = (regs->regs[0]) & 0xffffffff; + bh = (regs->regs[1]) >> 32; + bl = (regs->regs[1]) & 0xffffffff; + ch = (regs->regs[2]) >> 32; + cl = (regs->regs[2]) & 0xffffffff; + printk("R0 : %08Lx%08Lx R1 : %08Lx%08Lx R2 : %08Lx%08Lx\n", + ah, al, bh, bl, ch, cl); + + ah = (regs->regs[3]) >> 32; + al = (regs->regs[3]) & 0xffffffff; + bh = (regs->regs[4]) >> 32; + bl = (regs->regs[4]) & 0xffffffff; + ch = (regs->regs[5]) >> 32; + cl = (regs->regs[5]) & 0xffffffff; + printk("R3 : %08Lx%08Lx R4 : %08Lx%08Lx R5 : %08Lx%08Lx\n", + ah, al, bh, bl, ch, cl); + + ah = (regs->regs[6]) >> 32; + al = (regs->regs[6]) & 0xffffffff; + bh = (regs->regs[7]) >> 32; + bl = (regs->regs[7]) & 0xffffffff; + ch = (regs->regs[8]) >> 32; + cl = (regs->regs[8]) & 0xffffffff; + printk("R6 : %08Lx%08Lx R7 : %08Lx%08Lx R8 : %08Lx%08Lx\n", + ah, al, bh, bl, ch, cl); + + ah = (regs->regs[9]) >> 32; + al = (regs->regs[9]) & 0xffffffff; + bh = (regs->regs[10]) >> 32; + bl = (regs->regs[10]) & 0xffffffff; + ch = (regs->regs[11]) >> 32; + cl = (regs->regs[11]) & 0xffffffff; + printk("R9 : %08Lx%08Lx R10 : %08Lx%08Lx R11 : %08Lx%08Lx\n", + ah, al, bh, bl, ch, cl); + + ah = (regs->regs[12]) >> 32; + al = (regs->regs[12]) & 0xffffffff; + bh = (regs->regs[13]) >> 32; + bl = (regs->regs[13]) & 0xffffffff; + ch = (regs->regs[14]) >> 32; + cl = (regs->regs[14]) & 0xffffffff; + printk("R12 : %08Lx%08Lx R13 : %08Lx%08Lx R14 : %08Lx%08Lx\n", + ah, al, bh, bl, ch, cl); + + ah = (regs->regs[16]) >> 32; + al = (regs->regs[16]) & 0xffffffff; + bh = (regs->regs[17]) >> 32; + bl = (regs->regs[17]) & 0xffffffff; + ch = (regs->regs[19]) >> 32; + cl = (regs->regs[19]) & 0xffffffff; + printk("R16 : %08Lx%08Lx R17 : %08Lx%08Lx R19 : %08Lx%08Lx\n", + ah, al, bh, bl, ch, cl); + + ah = (regs->regs[20]) >> 32; + al = (regs->regs[20]) & 0xffffffff; + bh = (regs->regs[21]) >> 32; + bl = (regs->regs[21]) & 0xffffffff; + ch = (regs->regs[22]) >> 32; + cl = (regs->regs[22]) & 0xffffffff; + printk("R20 : %08Lx%08Lx R21 : %08Lx%08Lx R22 : %08Lx%08Lx\n", + ah, al, bh, bl, ch, cl); + + ah = (regs->regs[23]) >> 32; + al = (regs->regs[23]) & 0xffffffff; + bh = (regs->regs[24]) >> 32; + bl = (regs->regs[24]) & 0xffffffff; + ch = (regs->regs[25]) >> 32; + cl = (regs->regs[25]) & 0xffffffff; + printk("R23 : %08Lx%08Lx R24 : %08Lx%08Lx R25 : %08Lx%08Lx\n", + ah, al, bh, bl, ch, cl); + + ah = (regs->regs[26]) >> 32; + al = (regs->regs[26]) & 0xffffffff; + bh = (regs->regs[27]) >> 32; + bl = (regs->regs[27]) & 0xffffffff; + ch = (regs->regs[28]) >> 32; + cl = (regs->regs[28]) & 0xffffffff; + printk("R26 : %08Lx%08Lx R27 : %08Lx%08Lx R28 : %08Lx%08Lx\n", + ah, al, bh, bl, ch, cl); + + ah = (regs->regs[29]) >> 32; + al = (regs->regs[29]) & 0xffffffff; + bh = (regs->regs[30]) >> 32; + bl = (regs->regs[30]) & 0xffffffff; + ch = (regs->regs[31]) >> 32; + cl = (regs->regs[31]) & 0xffffffff; + printk("R29 : %08Lx%08Lx R30 : %08Lx%08Lx R31 : %08Lx%08Lx\n", + ah, al, bh, bl, ch, cl); + + ah = (regs->regs[32]) >> 32; + al = (regs->regs[32]) & 0xffffffff; + bh = (regs->regs[33]) >> 32; + bl = (regs->regs[33]) & 0xffffffff; + ch = (regs->regs[34]) >> 32; + cl = (regs->regs[34]) & 0xffffffff; + printk("R32 : %08Lx%08Lx R33 : %08Lx%08Lx R34 : %08Lx%08Lx\n", + ah, al, bh, bl, ch, cl); + + ah = (regs->regs[35]) >> 32; + al = (regs->regs[35]) & 0xffffffff; + bh = (regs->regs[36]) >> 32; + bl = (regs->regs[36]) & 0xffffffff; + ch = (regs->regs[37]) >> 32; + cl = (regs->regs[37]) & 0xffffffff; + printk("R35 : %08Lx%08Lx R36 : %08Lx%08Lx R37 : %08Lx%08Lx\n", + ah, al, bh, bl, ch, cl); + + ah = (regs->regs[38]) >> 32; + al = (regs->regs[38]) & 0xffffffff; + bh = (regs->regs[39]) >> 32; + bl = (regs->regs[39]) & 0xffffffff; + ch = (regs->regs[40]) >> 32; + cl = (regs->regs[40]) & 0xffffffff; + printk("R38 : %08Lx%08Lx R39 : %08Lx%08Lx R40 : %08Lx%08Lx\n", + ah, al, bh, bl, ch, cl); + + ah = (regs->regs[41]) >> 32; + al = (regs->regs[41]) & 0xffffffff; + bh = (regs->regs[42]) >> 32; + bl = (regs->regs[42]) & 0xffffffff; + ch = (regs->regs[43]) >> 32; + cl = (regs->regs[43]) & 0xffffffff; + printk("R41 : %08Lx%08Lx R42 : %08Lx%08Lx R43 : %08Lx%08Lx\n", + ah, al, bh, bl, ch, cl); + + ah = (regs->regs[44]) >> 32; + al = (regs->regs[44]) & 0xffffffff; + bh = (regs->regs[45]) >> 32; + bl = (regs->regs[45]) & 0xffffffff; + ch = (regs->regs[46]) >> 32; + cl = (regs->regs[46]) & 0xffffffff; + printk("R44 : %08Lx%08Lx R45 : %08Lx%08Lx R46 : %08Lx%08Lx\n", + ah, al, bh, bl, ch, cl); + + ah = (regs->regs[47]) >> 32; + al = (regs->regs[47]) & 0xffffffff; + bh = (regs->regs[48]) >> 32; + bl = (regs->regs[48]) & 0xffffffff; + ch = (regs->regs[49]) >> 32; + cl = (regs->regs[49]) & 0xffffffff; + printk("R47 : %08Lx%08Lx R48 : %08Lx%08Lx R49 : %08Lx%08Lx\n", + ah, al, bh, bl, ch, cl); + + ah = (regs->regs[50]) >> 32; + al = (regs->regs[50]) & 0xffffffff; + bh = (regs->regs[51]) >> 32; + bl = (regs->regs[51]) & 0xffffffff; + ch = (regs->regs[52]) >> 32; + cl = (regs->regs[52]) & 0xffffffff; + printk("R50 : %08Lx%08Lx R51 : %08Lx%08Lx R52 : %08Lx%08Lx\n", + ah, al, bh, bl, ch, cl); + + ah = (regs->regs[53]) >> 32; + al = (regs->regs[53]) & 0xffffffff; + bh = (regs->regs[54]) >> 32; + bl = (regs->regs[54]) & 0xffffffff; + ch = (regs->regs[55]) >> 32; + cl = (regs->regs[55]) & 0xffffffff; + printk("R53 : %08Lx%08Lx R54 : %08Lx%08Lx R55 : %08Lx%08Lx\n", + ah, al, bh, bl, ch, cl); + + ah = (regs->regs[56]) >> 32; + al = (regs->regs[56]) & 0xffffffff; + bh = (regs->regs[57]) >> 32; + bl = (regs->regs[57]) & 0xffffffff; + ch = (regs->regs[58]) >> 32; + cl = (regs->regs[58]) & 0xffffffff; + printk("R56 : %08Lx%08Lx R57 : %08Lx%08Lx R58 : %08Lx%08Lx\n", + ah, al, bh, bl, ch, cl); + + ah = (regs->regs[59]) >> 32; + al = (regs->regs[59]) & 0xffffffff; + bh = (regs->regs[60]) >> 32; + bl = (regs->regs[60]) & 0xffffffff; + ch = (regs->regs[61]) >> 32; + cl = (regs->regs[61]) & 0xffffffff; + printk("R59 : %08Lx%08Lx R60 : %08Lx%08Lx R61 : %08Lx%08Lx\n", + ah, al, bh, bl, ch, cl); + + ah = (regs->regs[62]) >> 32; + al = (regs->regs[62]) & 0xffffffff; + bh = (regs->tregs[0]) >> 32; + bl = (regs->tregs[0]) & 0xffffffff; + ch = (regs->tregs[1]) >> 32; + cl = (regs->tregs[1]) & 0xffffffff; + printk("R62 : %08Lx%08Lx T0 : %08Lx%08Lx T1 : %08Lx%08Lx\n", + ah, al, bh, bl, ch, cl); + + ah = (regs->tregs[2]) >> 32; + al = (regs->tregs[2]) & 0xffffffff; + bh = (regs->tregs[3]) >> 32; + bl = (regs->tregs[3]) & 0xffffffff; + ch = (regs->tregs[4]) >> 32; + cl = (regs->tregs[4]) & 0xffffffff; + printk("T2 : %08Lx%08Lx T3 : %08Lx%08Lx T4 : %08Lx%08Lx\n", + ah, al, bh, bl, ch, cl); + + ah = (regs->tregs[5]) >> 32; + al = (regs->tregs[5]) & 0xffffffff; + bh = (regs->tregs[6]) >> 32; + bl = (regs->tregs[6]) & 0xffffffff; + ch = (regs->tregs[7]) >> 32; + cl = (regs->tregs[7]) & 0xffffffff; + printk("T5 : %08Lx%08Lx T6 : %08Lx%08Lx T7 : %08Lx%08Lx\n", + ah, al, bh, bl, ch, cl); + + /* + * If we're in kernel mode, dump the stack too.. + */ + if (!user_mode(regs)) { + void show_stack(struct task_struct *tsk, unsigned long *sp); + unsigned long sp = regs->regs[15] & 0xffffffff; + struct task_struct *tsk = get_current(); + + tsk->thread.kregs = regs; + + show_stack(tsk, (unsigned long *)sp); + } +} + +struct task_struct * alloc_task_struct(void) +{ + /* Get task descriptor pages */ + return (struct task_struct *) + __get_free_pages(GFP_KERNEL, get_order(THREAD_SIZE)); +} + +void free_task_struct(struct task_struct *p) +{ + free_pages((unsigned long) p, get_order(THREAD_SIZE)); +} + +/* + * Create a kernel thread + */ + +/* + * This is the mechanism for creating a new kernel thread. + * + * NOTE! Only a kernel-only process(ie the swapper or direct descendants + * who haven't done an "execve()") should use this: it will work within + * a system call from a "real" process, but the process memory space will + * not be free'd until both the parent and the child have exited. + */ +int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +{ + /* A bit less processor dependent than older sh ... */ + + unsigned int reply; + +static __inline__ _syscall2(int,clone,unsigned long,flags,unsigned long,newsp) +static __inline__ _syscall1(int,exit,int,ret) + + reply = clone(flags | CLONE_VM, 0); + if (!reply) { + /* Child */ + reply = exit(fn(arg)); + } + + return reply; +} + +/* + * Free current thread data structures etc.. + */ +void exit_thread(void) +{ + /* See arch/sparc/kernel/process.c for the precedent for doing this -- RPC. + + The SH-5 FPU save/restore approach relies on last_task_used_math + pointing to a live task_struct. When another task tries to use the + FPU for the 1st time, the FPUDIS trap handling (see + arch/sh64/kernel/fpu.c) will save the existing FPU state to the + FP regs field within last_task_used_math before re-loading the new + task's FPU state (or initialising it if the FPU has been used + before). So if last_task_used_math is stale, and its page has already been + re-allocated for another use, the consequences are rather grim. Unless we + null it here, there is no other path through which it would get safely + nulled. */ + +#ifndef CONFIG_NOFPU_SUPPORT + if (last_task_used_math == current) { + last_task_used_math = NULL; + } +#endif +} + +void flush_thread(void) +{ + + /* Called by fs/exec.c (flush_old_exec) to remove traces of a + * previously running executable. */ +#ifndef CONFIG_NOFPU_SUPPORT + if (last_task_used_math == current) { + last_task_used_math = NULL; + } + /* Force FPU state to be reinitialised after exec */ + current->used_math = 0; +#endif + + /* if we are a kernel thread, about to change to user thread, + * update kreg + */ + if(current->thread.kregs==&fake_swapper_regs) { + current->thread.kregs = + ((struct pt_regs *)(THREAD_SIZE + (unsigned long) current) - 1); + current->thread.uregs = current->thread.kregs; + } +} + +void release_thread(struct task_struct *dead_task) +{ + /* do nothing */ +} + +/* Fill in the fpu structure for a core dump.. */ +int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) +{ +#ifndef CONFIG_NOFPU_SUPPORT + int fpvalid; + struct task_struct *tsk = current; + + fpvalid = tsk->used_math; + if (fpvalid) { + if (current == last_task_used_math) { + grab_fpu(); + fpsave(&tsk->thread.fpu.hard); + release_fpu(); + last_task_used_math = 0; + regs->sr |= SR_FD; + } + + memcpy(fpu, &tsk->thread.fpu.hard, sizeof(*fpu)); + } + + return fpvalid; +#else + return 0; /* Task didn't use the fpu at all. */ +#endif +} + +asmlinkage void ret_from_fork(void); + +int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, + unsigned long unused, + struct task_struct *p, struct pt_regs *regs) +{ + struct pt_regs *childregs; + unsigned long long se; /* Sign extension */ + +#ifndef CONFIG_NOFPU_SUPPORT + if(last_task_used_math == current) { + grab_fpu(); + fpsave(¤t->thread.fpu.hard); + release_fpu(); + last_task_used_math = NULL; + regs->sr |= SR_FD; + } +#endif + /* Copy from sh version */ + childregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long) p->thread_info )) - 1; + + *childregs = *regs; + + if (user_mode(regs)) { + childregs->regs[15] = usp; + p->thread.uregs = childregs; + } else { + childregs->regs[15] = (unsigned long)p->thread_info + THREAD_SIZE; + } + + childregs->regs[9] = 0; /* Set return value for child */ + childregs->sr |= SR_FD; /* Invalidate FPU flag */ + + /* From sh */ + p->set_child_tid = p->clear_child_tid = NULL; + + p->thread.sp = (unsigned long) childregs; + p->thread.pc = (unsigned long) ret_from_fork; + + /* + * Sign extend the edited stack. + * Note that thread.pc and thread.pc will stay + * 32-bit wide and context switch must take care + * of NEFF sign extension. + */ + + se = childregs->regs[15]; + se = (se & NEFF_SIGN) ? (se | NEFF_MASK) : se; + childregs->regs[15] = se; + + return 0; +} + +/* + * fill in the user structure for a core dump.. + */ +void dump_thread(struct pt_regs * regs, struct user * dump) +{ + dump->magic = CMAGIC; + dump->start_code = current->mm->start_code; + dump->start_data = current->mm->start_data; + dump->start_stack = regs->regs[15] & ~(PAGE_SIZE - 1); + dump->u_tsize = (current->mm->end_code - dump->start_code) >> PAGE_SHIFT; + dump->u_dsize = (current->mm->brk + (PAGE_SIZE-1) - dump->start_data) >> PAGE_SHIFT; + dump->u_ssize = (current->mm->start_stack - dump->start_stack + + PAGE_SIZE - 1) >> PAGE_SHIFT; + /* Debug registers will come here. */ + + dump->regs = *regs; + + dump->u_fpvalid = dump_fpu(regs, &dump->fpu); +} + +asmlinkage int sys_fork(unsigned long r2, unsigned long r3, + unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7, + struct pt_regs *pregs) +{ + return do_fork(SIGCHLD, pregs->regs[15], pregs, 0, 0, 0); +} + +asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, + unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7, + struct pt_regs *pregs) +{ + if (!newsp) + newsp = pregs->regs[15]; + return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, pregs, 0, 0, 0); +} + +/* + * This is trivial, and on the face of it looks like it + * could equally well be done in user mode. + * + * Not so, for quite unobvious reasons - register pressure. + * In user mode vfork() cannot have a stack frame, and if + * done by calling the "clone()" system call directly, you + * do not have enough call-clobbered registers to hold all + * the information you need. + */ +asmlinkage int sys_vfork(unsigned long r2, unsigned long r3, + unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7, + struct pt_regs *pregs) +{ + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, pregs->regs[15], pregs, 0, 0, 0); +} + +/* + * sys_execve() executes a new program. + */ +asmlinkage int sys_execve(char *ufilename, char **uargv, + char **uenvp, unsigned long r5, + unsigned long r6, unsigned long r7, + struct pt_regs *pregs) +{ + int error; + char *filename; + + lock_kernel(); + filename = getname((char __user *)ufilename); + error = PTR_ERR(filename); + if (IS_ERR(filename)) + goto out; + + error = do_execve(filename, + (char __user * __user *)uargv, + (char __user * __user *)uenvp, + pregs); + if (error == 0) + current->ptrace &= ~PT_DTRACE; + putname(filename); +out: + unlock_kernel(); + return error; +} + +/* + * These bracket the sleeping functions.. + */ +extern void interruptible_sleep_on(wait_queue_head_t *q); + +#define mid_sched ((unsigned long) interruptible_sleep_on) + +static int in_sh64_switch_to(unsigned long pc) +{ + extern char __sh64_switch_to_end; + /* For a sleeping task, the PC is somewhere in the middle of the function, + so we don't have to worry about masking the LSB off */ + return (pc >= (unsigned long) sh64_switch_to) && + (pc < (unsigned long) &__sh64_switch_to_end); +} + +unsigned long get_wchan(struct task_struct *p) +{ + unsigned long schedule_fp; + unsigned long sh64_switch_to_fp; + unsigned long schedule_caller_pc; + unsigned long pc; + + if (!p || p == current || p->state == TASK_RUNNING) + return 0; + + /* + * The same comment as on the Alpha applies here, too ... + */ + pc = thread_saved_pc(p); + +#if CONFIG_FRAME_POINTER + if (in_sh64_switch_to(pc)) { + sh64_switch_to_fp = (long) p->thread.sp; + /* r14 is saved at offset 4 in the sh64_switch_to frame */ + schedule_fp = *(unsigned long *) (long)(sh64_switch_to_fp + 4); + + /* and the caller of 'schedule' is (currently!) saved at offset 24 + in the frame of schedule (from disasm) */ + schedule_caller_pc = *(unsigned long *) (long)(schedule_fp + 24); + return schedule_caller_pc; + } +#endif + return pc; +} + +/* Provide a /proc/asids file that lists out the + ASIDs currently associated with the processes. (If the DM.PC register is + examined through the debug link, this shows ASID + PC. To make use of this, + the PID->ASID relationship needs to be known. This is primarily for + debugging.) + */ + +#if defined(CONFIG_SH64_PROC_ASIDS) +#include +#include + +static int +asids_proc_info(char *buf, char **start, off_t fpos, int length, int *eof, void *data) +{ + int len=0; + struct task_struct *p; + read_lock(&tasklist_lock); + for_each_task(p) { + int pid = p->pid; + struct mm_struct *mm; + if (!pid) continue; + mm = p->mm; + if (mm) { + unsigned long asid, context; + context = mm->context; + asid = (context & 0xff); + len += sprintf(buf+len, "%5d : %02x\n", pid, asid); + } else { + len += sprintf(buf+len, "%5d : (none)\n", pid); + } + } + read_unlock(&tasklist_lock); + *eof = 1; + return len; +} + +static int __init register_proc_asids(void) +{ + create_proc_read_entry("asids", 0, NULL, asids_proc_info, NULL); + return 0; +} + +__initcall(register_proc_asids); +#endif + diff -puN /dev/null arch/sh64/kernel/ptrace.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/kernel/ptrace.c 2004-06-28 13:30:30.671141120 -0700 @@ -0,0 +1,362 @@ +/* + * 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. + * + * arch/sh64/kernel/ptrace.c + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003 Paul Mundt + * + * Started from SH3/4 version: + * SuperH version: Copyright (C) 1999, 2000 Kaz Kojima & Niibe Yutaka + * + * Original x86 implementation: + * By Ross Biro 1/23/92 + * edited by Linus Torvalds + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* This mask defines the bits of the SR which the user is not allowed to + change, which are everything except S, Q, M, PR, SZ, FR. */ +#define SR_MASK (0xffff8cfd) + +/* + * does not yet catch signals sent when the child dies. + * in exit.c or in signal.c. + */ + +/* + * This routine will get a word from the user area in the process kernel stack. + */ +static inline int get_stack_long(struct task_struct *task, int offset) +{ + unsigned char *stack; + + stack = (unsigned char *)(task->thread.uregs); + stack += offset; + return (*((int *)stack)); +} + +static inline unsigned long +get_fpu_long(struct task_struct *task, unsigned long addr) +{ + unsigned long tmp; + struct pt_regs *regs; + regs = (struct pt_regs*)((unsigned char *)task + THREAD_SIZE) - 1; + + if (!task->used_math) { + if (addr == offsetof(struct user_fpu_struct, fpscr)) { + tmp = FPSCR_INIT; + } else { + tmp = 0xffffffffUL; /* matches initial value in fpu.c */ + } + return tmp; + } + + if (last_task_used_math == task) { + grab_fpu(); + fpsave(&task->thread.fpu.hard); + release_fpu(); + last_task_used_math = 0; + regs->sr |= SR_FD; + } + + tmp = ((long *)&task->thread.fpu)[addr / sizeof(unsigned long)]; + return tmp; +} + +/* + * This routine will put a word into the user area in the process kernel stack. + */ +static inline int put_stack_long(struct task_struct *task, int offset, + unsigned long data) +{ + unsigned char *stack; + + stack = (unsigned char *)(task->thread.uregs); + stack += offset; + *(unsigned long *) stack = data; + return 0; +} + +static inline int +put_fpu_long(struct task_struct *task, unsigned long addr, unsigned long data) +{ + struct pt_regs *regs; + + regs = (struct pt_regs*)((unsigned char *)task + THREAD_SIZE) - 1; + + if (!task->used_math) { + fpinit(&task->thread.fpu.hard); + task->used_math = 1; + } else if (last_task_used_math == task) { + grab_fpu(); + fpsave(&task->thread.fpu.hard); + release_fpu(); + last_task_used_math = 0; + regs->sr |= SR_FD; + } + + ((long *)&task->thread.fpu)[addr / sizeof(unsigned long)] = data; + return 0; +} + +asmlinkage int sys_ptrace(long request, long pid, long addr, long data) +{ + struct task_struct *child; + int ret; + + lock_kernel(); + ret = -EPERM; + if (request == PTRACE_TRACEME) { + /* are we already being traced? */ + if (current->ptrace & PT_PTRACED) + goto out; + /* set the ptrace bit in the process flags. */ + current->ptrace |= PT_PTRACED; + ret = 0; + goto out; + } + ret = -ESRCH; + read_lock(&tasklist_lock); + child = find_task_by_pid(pid); + if (child) + get_task_struct(child); + read_unlock(&tasklist_lock); + if (!child) + goto out; + + ret = -EPERM; + if (pid == 1) /* you may not mess with init */ + goto out_tsk; + + if (request == PTRACE_ATTACH) { + ret = ptrace_attach(child); + goto out_tsk; + } + + ret = ptrace_check_attach(child, request == PTRACE_KILL); + if (ret < 0) + goto out_tsk; + + switch (request) { + /* when I and D space are separate, these will need to be fixed. */ + case PTRACE_PEEKTEXT: /* read word at location addr. */ + case PTRACE_PEEKDATA: { + unsigned long tmp; + int copied; + + copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + ret = -EIO; + if (copied != sizeof(tmp)) + break; + ret = put_user(tmp,(unsigned long *) data); + break; + } + + /* read the word at location addr in the USER area. */ + case PTRACE_PEEKUSR: { + unsigned long tmp; + + ret = -EIO; + if ((addr & 3) || addr < 0) + break; + + if (addr < sizeof(struct pt_regs)) + tmp = get_stack_long(child, addr); + else if ((addr >= offsetof(struct user, fpu)) && + (addr < offsetof(struct user, u_fpvalid))) { + tmp = get_fpu_long(child, addr - offsetof(struct user, fpu)); + } else if (addr == offsetof(struct user, u_fpvalid)) { + tmp = child->used_math; + } else { + break; + } + ret = put_user(tmp, (unsigned long *)data); + break; + } + + /* when I and D space are separate, this will have to be fixed. */ + case PTRACE_POKETEXT: /* write the word at location addr. */ + case PTRACE_POKEDATA: + ret = 0; + if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) + break; + ret = -EIO; + break; + + case PTRACE_POKEUSR: + /* write the word at location addr in the USER area. We must + disallow any changes to certain SR bits or u_fpvalid, since + this could crash the kernel or result in a security + loophole. */ + ret = -EIO; + if ((addr & 3) || addr < 0) + break; + + if (addr < sizeof(struct pt_regs)) { + /* Ignore change of top 32 bits of SR */ + if (addr == offsetof (struct pt_regs, sr)+4) + { + ret = 0; + break; + } + /* If lower 32 bits of SR, ignore non-user bits */ + if (addr == offsetof (struct pt_regs, sr)) + { + long cursr = get_stack_long(child, addr); + data &= ~(SR_MASK); + data |= (cursr & SR_MASK); + } + ret = put_stack_long(child, addr, data); + } + else if ((addr >= offsetof(struct user, fpu)) && + (addr < offsetof(struct user, u_fpvalid))) { + ret = put_fpu_long(child, addr - offsetof(struct user, fpu), data); + } + break; + + case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ + case PTRACE_CONT: { /* restart after signal. */ + ret = -EIO; + if ((unsigned long) data > _NSIG) + break; + if (request == PTRACE_SYSCALL) + set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + else + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + child->exit_code = data; + wake_up_process(child); + ret = 0; + break; + } + +/* + * make the child exit. Best I can do is send it a sigkill. + * perhaps it should be put in the status that it wants to + * exit. + */ + case PTRACE_KILL: { + ret = 0; + if (child->state == TASK_ZOMBIE) /* already dead */ + break; + child->exit_code = SIGKILL; + wake_up_process(child); + break; + } + + case PTRACE_SINGLESTEP: { /* set the trap flag. */ + struct pt_regs *regs; + + ret = -EIO; + if ((unsigned long) data > _NSIG) + break; + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + if ((child->ptrace & PT_DTRACE) == 0) { + /* Spurious delayed TF traps may occur */ + child->ptrace |= PT_DTRACE; + } + + regs = child->thread.uregs; + + regs->sr |= SR_SSTEP; /* auto-resetting upon exception */ + + child->exit_code = data; + /* give it a chance to run. */ + wake_up_process(child); + ret = 0; + break; + } + + case PTRACE_DETACH: /* detach a process that was attached. */ + ret = ptrace_detach(child, data); + break; + + default: + ret = ptrace_request(child, request, addr, data); + break; + } +out_tsk: + put_task_struct(child); +out: + unlock_kernel(); + return ret; +} + +asmlinkage void syscall_trace(void) +{ + struct task_struct *tsk = current; + + if (!test_thread_flag(TIF_SYSCALL_TRACE)) + return; + if (!(tsk->ptrace & PT_PTRACED)) + return; + + tsk->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) + ? 0x80 : 0); + tsk->state = TASK_STOPPED; + notify_parent(tsk, SIGCHLD); + schedule(); + /* + * this isn't the same as continuing with a signal, but it will do + * for normal use. strace only continues with a signal if the + * stopping signal is not SIGTRAP. -brl + */ + if (tsk->exit_code) { + send_sig(tsk->exit_code, tsk, 1); + tsk->exit_code = 0; + } +} + +/* Called with interrupts disabled */ +asmlinkage void do_single_step(unsigned long long vec, struct pt_regs *regs) +{ + /* This is called after a single step exception (DEBUGSS). + There is no need to change the PC, as it is a post-execution + exception, as entry.S does not do anything to the PC for DEBUGSS. + We need to clear the Single Step setting in SR to avoid + continually stepping. */ + local_irq_enable(); + regs->sr &= ~SR_SSTEP; + force_sig(SIGTRAP, current); +} + +/* Called with interrupts disabled */ +asmlinkage void do_software_break_point(unsigned long long vec, + struct pt_regs *regs) +{ + /* We need to forward step the PC, to counteract the backstep done + in signal.c. */ + local_irq_enable(); + force_sig(SIGTRAP, current); + regs->pc += 4; +} + +/* + * Called by kernel/ptrace.c when detaching.. + * + * Make sure single step bits etc are not set. + */ +void ptrace_disable(struct task_struct *child) +{ + /* nothing to do.. */ +} diff -puN /dev/null arch/sh64/kernel/semaphore.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/kernel/semaphore.c 2004-06-28 13:30:30.671141120 -0700 @@ -0,0 +1,140 @@ +/* + * Just taken from alpha implementation. + * This can't work well, perhaps. + */ +/* + * Generic semaphore code. Buyer beware. Do your own + * specific changes in + */ + +#include +#include +#include +#include +#include +#include +#include + +spinlock_t semaphore_wake_lock; + +/* + * Semaphores are implemented using a two-way counter: + * The "count" variable is decremented for each process + * that tries to sleep, while the "waking" variable is + * incremented when the "up()" code goes to wake up waiting + * processes. + * + * Notably, the inline "up()" and "down()" functions can + * efficiently test if they need to do any extra work (up + * needs to do something only if count was negative before + * the increment operation. + * + * waking_non_zero() (from asm/semaphore.h) must execute + * atomically. + * + * When __up() is called, the count was negative before + * incrementing it, and we need to wake up somebody. + * + * This routine adds one to the count of processes that need to + * wake up and exit. ALL waiting processes actually wake up but + * only the one that gets to the "waking" field first will gate + * through and acquire the semaphore. The others will go back + * to sleep. + * + * Note that these functions are only called when there is + * contention on the lock, and as such all this is the + * "non-critical" part of the whole semaphore business. The + * critical part is the inline stuff in + * where we want to avoid any extra jumps and calls. + */ +void __up(struct semaphore *sem) +{ + wake_one_more(sem); + wake_up(&sem->wait); +} + +/* + * Perform the "down" function. Return zero for semaphore acquired, + * return negative for signalled out of the function. + * + * If called from __down, the return is ignored and the wait loop is + * not interruptible. This means that a task waiting on a semaphore + * using "down()" cannot be killed until someone does an "up()" on + * the semaphore. + * + * If called from __down_interruptible, the return value gets checked + * upon return. If the return value is negative then the task continues + * with the negative value in the return register (it can be tested by + * the caller). + * + * Either form may be used in conjunction with "up()". + * + */ + +#define DOWN_VAR \ + struct task_struct *tsk = current; \ + wait_queue_t wait; \ + init_waitqueue_entry(&wait, tsk); + +#define DOWN_HEAD(task_state) \ + \ + \ + tsk->state = (task_state); \ + add_wait_queue(&sem->wait, &wait); \ + \ + /* \ + * Ok, we're set up. sem->count is known to be less than zero \ + * so we must wait. \ + * \ + * We can let go the lock for purposes of waiting. \ + * We re-acquire it after awaking so as to protect \ + * all semaphore operations. \ + * \ + * If "up()" is called before we call waking_non_zero() then \ + * we will catch it right away. If it is called later then \ + * we will have to go through a wakeup cycle to catch it. \ + * \ + * Multiple waiters contend for the semaphore lock to see \ + * who gets to gate through and who has to wait some more. \ + */ \ + for (;;) { + +#define DOWN_TAIL(task_state) \ + tsk->state = (task_state); \ + } \ + tsk->state = TASK_RUNNING; \ + remove_wait_queue(&sem->wait, &wait); + +void __sched __down(struct semaphore * sem) +{ + DOWN_VAR + DOWN_HEAD(TASK_UNINTERRUPTIBLE) + if (waking_non_zero(sem)) + break; + schedule(); + DOWN_TAIL(TASK_UNINTERRUPTIBLE) +} + +int __sched __down_interruptible(struct semaphore * sem) +{ + int ret = 0; + DOWN_VAR + DOWN_HEAD(TASK_INTERRUPTIBLE) + + ret = waking_non_zero_interruptible(sem, tsk); + if (ret) + { + if (ret == 1) + /* ret != 0 only if we get interrupted -arca */ + ret = 0; + break; + } + schedule(); + DOWN_TAIL(TASK_INTERRUPTIBLE) + return ret; +} + +int __down_trylock(struct semaphore * sem) +{ + return waking_non_zero_trylock(sem); +} diff -puN /dev/null arch/sh64/kernel/setup.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/kernel/setup.c 2004-06-28 13:30:30.673140816 -0700 @@ -0,0 +1,400 @@ +/* + * 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. + * + * arch/sh64/kernel/setup.c + * + * sh64 Arch Support + * + * This file handles the architecture-dependent parts of initialization + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003, 2004 Paul Mundt + * + * benedict.gaster@superh.com: 2nd May 2002 + * Modified to use the empty_zero_page to pass command line arguments. + * + * benedict.gaster@superh.com: 3rd May 2002 + * Added support for ramdisk, removing statically linked romfs at the same time. + * + * lethal@linux-sh.org: 15th May 2003 + * Added generic procfs cpuinfo reporting. Make boards just export their name. + * + * lethal@linux-sh.org: 25th May 2003 + * Added generic get_cpu_subtype() for subtype reporting from cpu_data->type. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_VT +#include +#endif + +struct screen_info screen_info; + +/* On a PC this would be initialised as a result of the BIOS detecting the + * mouse. */ +unsigned char aux_device_present = 0xaa; + +#ifdef CONFIG_BLK_DEV_RAM +extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */ +extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */ +extern int rd_image_start; /* starting block # of image */ +#endif + +extern int root_mountflags; +extern char *get_system_type(void); +extern void platform_setup(void); +extern void platform_monitor(void); +extern void platform_reserve(void); +extern int sh64_cache_init(void); +extern int sh64_tlb_init(void); + +#define RAMDISK_IMAGE_START_MASK 0x07FF +#define RAMDISK_PROMPT_FLAG 0x8000 +#define RAMDISK_LOAD_FLAG 0x4000 + +#define PARAM ((unsigned char *)empty_zero_page) +#define MOUNT_ROOT_RDONLY (*(unsigned long *) (PARAM+0x000)) +#define RAMDISK_FLAGS (*(unsigned long *) (PARAM+0x004)) +#define ORIG_ROOT_DEV (*(unsigned long *) (PARAM+0x008)) +#define LOADER_TYPE (*(unsigned long *) (PARAM+0x00c)) +#define INITRD_START (*(unsigned long *) (PARAM+0x010)) +#define INITRD_SIZE (*(unsigned long *) (PARAM+0x014)) + +#define COMMAND_LINE ((char *) (PARAM+256)) +#define COMMAND_LINE_SIZE 256 + +static char command_line[COMMAND_LINE_SIZE] = { 0, }; + char saved_command_line[COMMAND_LINE_SIZE]; +unsigned long long memory_start = CONFIG_MEMORY_START; +unsigned long long memory_end = CONFIG_MEMORY_START + (CONFIG_MEMORY_SIZE_IN_MB * 1024 * 1024); + +struct sh_cpuinfo boot_cpu_data; + +static inline void parse_mem_cmdline (char ** cmdline_p) +{ + char c = ' ', *to = command_line, *from = COMMAND_LINE; + int len = 0; + + /* Save unparsed command line copy for /proc/cmdline */ + memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); + saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; + + for (;;) { + /* + * "mem=XXX[kKmM]" defines a size of memory. + */ + if (c == ' ' && !memcmp(from, "mem=", 4)) { + if (to != command_line) + to--; + { + unsigned long mem_size; + + mem_size = memparse(from+4, &from); + memory_end = memory_start + mem_size; + } + } + c = *(from++); + if (!c) + break; + if (COMMAND_LINE_SIZE <= ++len) + break; + *(to++) = c; + } + *to = '\0'; + + *cmdline_p = command_line; +} + +static void __init sh64_cpu_type_detect(void) +{ + extern unsigned long long peek_real_address_q(unsigned long long addr); + unsigned long long cir; + /* Do peeks in real mode to avoid having to set up a mapping for the + WPC registers. On SH5-101 cut2, such a mapping would be exposed to + an address translation erratum which would make it hard to set up + correctly. */ + cir = peek_real_address_q(0x0d000008); + + if ((cir & 0xffff) == 0x5103) { + boot_cpu_data.type = CPU_SH5_103; + } else if (((cir >> 32) & 0xffff) == 0x51e2) { + /* CPU.VCR aliased at CIR address on SH5-101 */ + boot_cpu_data.type = CPU_SH5_101; + } else { + boot_cpu_data.type = CPU_SH_NONE; + } +} + +void __init setup_arch(char **cmdline_p) +{ + unsigned long bootmap_size, i; + unsigned long first_pfn, start_pfn, last_pfn, pages; + +#ifdef CONFIG_EARLY_PRINTK + extern void enable_early_printk(void); + + /* + * Setup Early SCIF console + */ + enable_early_printk(); +#endif + + /* + * Setup TLB mappings + */ + sh64_tlb_init(); + + /* + * Caches are already initialized by the time we get here, so we just + * fill in cpu_data info for the caches. + */ + sh64_cache_init(); + + platform_setup(); + platform_monitor(); + + sh64_cpu_type_detect(); + + ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV); + +#ifdef CONFIG_BLK_DEV_RAM + rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK; + rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); + rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0); +#endif + + if (!MOUNT_ROOT_RDONLY) + root_mountflags &= ~MS_RDONLY; + init_mm.start_code = (unsigned long) _text; + init_mm.end_code = (unsigned long) _etext; + init_mm.end_data = (unsigned long) _edata; + init_mm.brk = (unsigned long) _end; + + code_resource.start = __pa(_text); + code_resource.end = __pa(_etext)-1; + data_resource.start = __pa(_etext); + data_resource.end = __pa(_edata)-1; + + parse_mem_cmdline(cmdline_p); + + /* + * Find the lowest and highest page frame numbers we have available + */ + first_pfn = PFN_DOWN(memory_start); + last_pfn = PFN_DOWN(memory_end); + pages = last_pfn - first_pfn; + + /* + * Partially used pages are not usable - thus + * we are rounding upwards: + */ + start_pfn = PFN_UP(__pa(_end)); + + /* + * Find a proper area for the bootmem bitmap. After this + * bootstrap step all allocations (until the page allocator + * is intact) must be done via bootmem_alloc(). + */ + bootmap_size = init_bootmem_node(NODE_DATA(0), start_pfn, + first_pfn, + last_pfn); + /* + * Round it up. + */ + bootmap_size = PFN_PHYS(PFN_UP(bootmap_size)); + + /* + * Register fully available RAM pages with the bootmem allocator. + */ + free_bootmem_node(NODE_DATA(0), PFN_PHYS(first_pfn), PFN_PHYS(pages)); + + /* + * Reserve all kernel sections + bootmem bitmap + a guard page. + */ + reserve_bootmem_node(NODE_DATA(0), PFN_PHYS(first_pfn), + (PFN_PHYS(start_pfn) + bootmap_size + PAGE_SIZE) - PFN_PHYS(first_pfn)); + + /* + * Reserve platform dependent sections + */ + platform_reserve(); + +#ifdef CONFIG_BLK_DEV_INITRD + if (LOADER_TYPE && INITRD_START) { + if (INITRD_START + INITRD_SIZE <= (PFN_PHYS(last_pfn))) { + reserve_bootmem_node(NODE_DATA(0), INITRD_START + __MEMORY_START, INITRD_SIZE); + + initrd_start = + (long) INITRD_START ? INITRD_START + PAGE_OFFSET + __MEMORY_START : 0; + + initrd_end = initrd_start + INITRD_SIZE; + } else { + printk("initrd extends beyond end of memory " + "(0x%08lx > 0x%08lx)\ndisabling initrd\n", + (long) INITRD_START + INITRD_SIZE, + PFN_PHYS(last_pfn)); + initrd_start = 0; + } + } +#endif + + /* + * Claim all RAM, ROM, and I/O resources. + */ + + /* Kernel RAM */ + request_resource(&iomem_resource, &code_resource); + request_resource(&iomem_resource, &data_resource); + + /* Other KRAM space */ + for (i = 0; i < STANDARD_KRAM_RESOURCES - 2; i++) + request_resource(&iomem_resource, + &platform_parms.kram_res_p[i]); + + /* XRAM space */ + for (i = 0; i < STANDARD_XRAM_RESOURCES; i++) + request_resource(&iomem_resource, + &platform_parms.xram_res_p[i]); + + /* ROM space */ + for (i = 0; i < STANDARD_ROM_RESOURCES; i++) + request_resource(&iomem_resource, + &platform_parms.rom_res_p[i]); + + /* I/O space */ + for (i = 0; i < STANDARD_IO_RESOURCES; i++) + request_resource(&ioport_resource, + &platform_parms.io_res_p[i]); + + +#ifdef CONFIG_VT +#if defined(CONFIG_VGA_CONSOLE) + conswitchp = &vga_con; +#elif defined(CONFIG_DUMMY_CONSOLE) + conswitchp = &dummy_con; +#endif +#endif + + printk("Hardware FPU: %s\n", fpu_in_use ? "enabled" : "disabled"); + + paging_init(); +} + +void __xchg_called_with_bad_pointer(void) +{ + printk(KERN_EMERG "xchg() called with bad pointer !\n"); +} + +static struct cpu cpu[1]; + +static int __init topology_init(void) +{ + return register_cpu(cpu, 0, NULL); +} + +subsys_initcall(topology_init); + +/* + * Get CPU information + */ +static const char *cpu_name[] = { + [CPU_SH5_101] = "SH5-101", + [CPU_SH5_103] = "SH5-103", + [CPU_SH_NONE] = "Unknown", +}; + +const char *get_cpu_subtype(void) +{ + return cpu_name[boot_cpu_data.type]; +} + +#ifdef CONFIG_PROC_FS +static int show_cpuinfo(struct seq_file *m,void *v) +{ + unsigned int cpu = smp_processor_id(); + + if (!cpu) + seq_printf(m, "machine\t\t: %s\n", get_system_type()); + + seq_printf(m, "processor\t: %d\n", cpu); + seq_printf(m, "cpu family\t: SH-5\n"); + seq_printf(m, "cpu type\t: %s\n", get_cpu_subtype()); + + seq_printf(m, "icache size\t: %dK-bytes\n", + (boot_cpu_data.icache.ways * + boot_cpu_data.icache.sets * + boot_cpu_data.icache.linesz) >> 10); + seq_printf(m, "dcache size\t: %dK-bytes\n", + (boot_cpu_data.dcache.ways * + boot_cpu_data.dcache.sets * + boot_cpu_data.dcache.linesz) >> 10); + seq_printf(m, "itlb entries\t: %d\n", boot_cpu_data.itlb.entries); + seq_printf(m, "dtlb entries\t: %d\n", boot_cpu_data.dtlb.entries); + +#define PRINT_CLOCK(name, value) \ + seq_printf(m, name " clock\t: %d.%02dMHz\n", \ + ((value) / 1000000), ((value) % 1000000)/10000) + + PRINT_CLOCK("cpu", boot_cpu_data.cpu_clock); + PRINT_CLOCK("bus", boot_cpu_data.bus_clock); + PRINT_CLOCK("module", boot_cpu_data.module_clock); + + seq_printf(m, "bogomips\t: %lu.%02lu\n\n", + (loops_per_jiffy*HZ+2500)/500000, + ((loops_per_jiffy*HZ+2500)/5000) % 100); + + return 0; +} + +static void *c_start(struct seq_file *m, loff_t *pos) +{ + return (void*)(*pos == 0); +} +static void *c_next(struct seq_file *m, void *v, loff_t *pos) +{ + return NULL; +} +static void c_stop(struct seq_file *m, void *v) +{ +} +struct seq_operations cpuinfo_op = { + .start = c_start, + .next = c_next, + .stop = c_stop, + .show = show_cpuinfo, +}; +#endif /* CONFIG_PROC_FS */ diff -puN /dev/null arch/sh64/kernel/sh_ksyms.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/kernel/sh_ksyms.c 2004-06-28 13:30:30.674140664 -0700 @@ -0,0 +1,84 @@ +/* + * 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. + * + * arch/sh64/kernel/sh_ksyms.c + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +extern void dump_thread(struct pt_regs *, struct user *); +extern int dump_fpu(struct pt_regs *, elf_fpregset_t *); + +#if 0 +/* Not yet - there's no declaration of drive_info anywhere. */ +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) || defined(CONFIG_BLK_DEV_IDE_MODULE) || defined(CONFIG_BLK_DEV_HD_MODULE) +extern struct drive_info_struct drive_info; +EXPORT_SYMBOL(drive_info); +#endif +#endif + +/* platform dependent support */ +EXPORT_SYMBOL(dump_thread); +EXPORT_SYMBOL(dump_fpu); +EXPORT_SYMBOL(iounmap); +EXPORT_SYMBOL(enable_irq); +EXPORT_SYMBOL(disable_irq); +EXPORT_SYMBOL(kernel_thread); + +/* Networking helper routines. */ +EXPORT_SYMBOL(csum_partial_copy); + +EXPORT_SYMBOL(strtok); +EXPORT_SYMBOL(strpbrk); +EXPORT_SYMBOL(strstr); + +#ifdef CONFIG_VT +EXPORT_SYMBOL(screen_info); +#endif + +EXPORT_SYMBOL_NOVERS(__down); +EXPORT_SYMBOL_NOVERS(__down_trylock); +EXPORT_SYMBOL_NOVERS(__up); +EXPORT_SYMBOL_NOVERS(__put_user_asm_l); +EXPORT_SYMBOL_NOVERS(__get_user_asm_l); +EXPORT_SYMBOL_NOVERS(memcmp); +EXPORT_SYMBOL_NOVERS(memcpy); +EXPORT_SYMBOL_NOVERS(memset); +EXPORT_SYMBOL_NOVERS(memscan); +EXPORT_SYMBOL_NOVERS(strchr); +EXPORT_SYMBOL_NOVERS(strlen); + +EXPORT_SYMBOL(flush_dcache_page); + +/* Ugh. These come in from libgcc.a at link time. */ + +extern void __sdivsi3(void); +extern void __muldi3(void); +extern void __udivsi3(void); +EXPORT_SYMBOL_NOVERS(__sdivsi3); +EXPORT_SYMBOL_NOVERS(__muldi3); +EXPORT_SYMBOL_NOVERS(__udivsi3); + diff -puN /dev/null arch/sh64/kernel/signal.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/kernel/signal.c 2004-06-28 13:30:30.678140056 -0700 @@ -0,0 +1,737 @@ +/* + * 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. + * + * arch/sh64/kernel/signal.c + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003 Paul Mundt + * Copyright (C) 2004 Richard Curnow + * + * Started from sh version. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define REG_RET 9 +#define REG_ARG1 2 +#define REG_ARG2 3 +#define REG_ARG3 4 +#define REG_SP 15 +#define REG_PR 18 +#define REF_REG_RET regs->regs[REG_RET] +#define REF_REG_SP regs->regs[REG_SP] +#define DEREF_REG_PR regs->regs[REG_PR] + +#define DEBUG_SIG 0 + +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + +asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); + +/* + * Atomically swap in the new signal mask, and wait for a signal. + */ + +asmlinkage int +sys_sigsuspend(old_sigset_t mask, + unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7, + struct pt_regs * regs) +{ + sigset_t saveset; + + mask &= _BLOCKABLE; + spin_lock_irq(¤t->sighand->siglock); + saveset = current->blocked; + siginitset(¤t->blocked, mask); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + REF_REG_RET = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + regs->pc += 4; /* because sys_sigreturn decrements the pc */ + if (do_signal(regs, &saveset)) { + /* pc now points at signal handler. Need to decrement + it because entry.S will increment it. */ + regs->pc -= 4; + return -EINTR; + } + } +} + +asmlinkage int +sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, + unsigned long r4, unsigned long r5, unsigned long r6, + unsigned long r7, + struct pt_regs * regs) +{ + sigset_t saveset, newset; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + if (copy_from_user(&newset, unewset, sizeof(newset))) + return -EFAULT; + sigdelsetmask(&newset, ~_BLOCKABLE); + spin_lock_irq(¤t->sighand->siglock); + saveset = current->blocked; + current->blocked = newset; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + REF_REG_RET = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + regs->pc += 4; /* because sys_sigreturn decrements the pc */ + if (do_signal(regs, &saveset)) { + /* pc now points at signal handler. Need to decrement + it because entry.S will increment it. */ + regs->pc -= 4; + return -EINTR; + } + } +} + +asmlinkage int +sys_sigaction(int sig, const struct old_sigaction __user *act, + struct old_sigaction __user *oact) +{ + struct k_sigaction new_ka, old_ka; + int ret; + + if (act) { + old_sigset_t mask; + if (verify_area(VERIFY_READ, act, sizeof(*act)) || + __get_user(new_ka.sa.sa_handler, &act->sa_handler) || + __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) + return -EFAULT; + __get_user(new_ka.sa.sa_flags, &act->sa_flags); + __get_user(mask, &act->sa_mask); + siginitset(&new_ka.sa.sa_mask, mask); + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || + __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || + __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) + return -EFAULT; + __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); + } + + return ret; +} + +asmlinkage int +sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, + unsigned long r4, unsigned long r5, unsigned long r6, + unsigned long r7, + struct pt_regs * regs) +{ + return do_sigaltstack(uss, uoss, REF_REG_SP); +} + + +/* + * Do a signal return; undo the signal stack. + */ + +struct sigframe +{ + struct sigcontext sc; + unsigned long extramask[_NSIG_WORDS-1]; + long long retcode[2]; +}; + +struct rt_sigframe +{ + struct siginfo __user *pinfo; + void *puc; + struct siginfo info; + struct ucontext uc; + long long retcode[2]; +}; + +#ifndef CONFIG_NOFPU_SUPPORT +static inline int +restore_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc) +{ + int err = 0; + int fpvalid; + + err |= __get_user (fpvalid, &sc->sc_fpvalid); + current->used_math = fpvalid; + if (! fpvalid) + return err; + + if (current == last_task_used_math) { + last_task_used_math = NULL; + regs->sr |= SR_FD; + } + + err |= __copy_from_user(¤t->thread.fpu.hard, &sc->sc_fpregs[0], + (sizeof(long long) * 32) + (sizeof(int) * 1)); + + return err; +} + +static inline int +setup_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc) +{ + int err = 0; + int fpvalid; + + fpvalid = current->used_math; + err |= __put_user(fpvalid, &sc->sc_fpvalid); + if (! fpvalid) + return err; + + if (current == last_task_used_math) { + grab_fpu(); + fpsave(¤t->thread.fpu.hard); + release_fpu(); + last_task_used_math = NULL; + regs->sr |= SR_FD; + } + + err |= __copy_to_user(&sc->sc_fpregs[0], ¤t->thread.fpu.hard, + (sizeof(long long) * 32) + (sizeof(int) * 1)); + current->used_math = 0; + + return err; +} +#else +static inline int +restore_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc) +{} +static inline int +setup_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc) +{} +#endif + +static int +restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, long long *r2_p) +{ + unsigned int err = 0; + unsigned long long current_sr, new_sr; +#define SR_MASK 0xffff8cfd + +#define COPY(x) err |= __get_user(regs->x, &sc->sc_##x) + + COPY(regs[0]); COPY(regs[1]); COPY(regs[2]); COPY(regs[3]); + COPY(regs[4]); COPY(regs[5]); COPY(regs[6]); COPY(regs[7]); + COPY(regs[8]); COPY(regs[9]); COPY(regs[10]); COPY(regs[11]); + COPY(regs[12]); COPY(regs[13]); COPY(regs[14]); COPY(regs[15]); + COPY(regs[16]); COPY(regs[17]); COPY(regs[18]); COPY(regs[19]); + COPY(regs[20]); COPY(regs[21]); COPY(regs[22]); COPY(regs[23]); + COPY(regs[24]); COPY(regs[25]); COPY(regs[26]); COPY(regs[27]); + COPY(regs[28]); COPY(regs[29]); COPY(regs[30]); COPY(regs[31]); + COPY(regs[32]); COPY(regs[33]); COPY(regs[34]); COPY(regs[35]); + COPY(regs[36]); COPY(regs[37]); COPY(regs[38]); COPY(regs[39]); + COPY(regs[40]); COPY(regs[41]); COPY(regs[42]); COPY(regs[43]); + COPY(regs[44]); COPY(regs[45]); COPY(regs[46]); COPY(regs[47]); + COPY(regs[48]); COPY(regs[49]); COPY(regs[50]); COPY(regs[51]); + COPY(regs[52]); COPY(regs[53]); COPY(regs[54]); COPY(regs[55]); + COPY(regs[56]); COPY(regs[57]); COPY(regs[58]); COPY(regs[59]); + COPY(regs[60]); COPY(regs[61]); COPY(regs[62]); + COPY(tregs[0]); COPY(tregs[1]); COPY(tregs[2]); COPY(tregs[3]); + COPY(tregs[4]); COPY(tregs[5]); COPY(tregs[6]); COPY(tregs[7]); + + /* Prevent the signal handler manipulating SR in a way that can + crash the kernel. i.e. only allow S, Q, M, PR, SZ, FR to be + modified */ + current_sr = regs->sr; + err |= __get_user(new_sr, &sc->sc_sr); + regs->sr &= SR_MASK; + regs->sr |= (new_sr & ~SR_MASK); + + COPY(pc); + +#undef COPY + + /* Must do this last in case it sets regs->sr.fd (i.e. after rest of sr + * has been restored above.) */ + err |= restore_sigcontext_fpu(regs, sc); + + regs->syscall_nr = -1; /* disable syscall checks */ + err |= __get_user(*r2_p, &sc->sc_regs[REG_RET]); + return err; +} + +asmlinkage int sys_sigreturn(unsigned long r2, unsigned long r3, + unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7, + struct pt_regs * regs) +{ + struct sigframe __user *frame = (struct sigframe __user *) (long) REF_REG_SP; + sigset_t set; + long long ret; + + if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + + if (__get_user(set.sig[0], &frame->sc.oldmask) + || (_NSIG_WORDS > 1 + && __copy_from_user(&set.sig[1], &frame->extramask, + sizeof(frame->extramask)))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + + spin_lock_irq(¤t->sighand->siglock); + current->blocked = set; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + if (restore_sigcontext(regs, &frame->sc, &ret)) + goto badframe; + regs->pc -= 4; + + return (int) ret; + +badframe: + force_sig(SIGSEGV, current); + return 0; +} + +asmlinkage int sys_rt_sigreturn(unsigned long r2, unsigned long r3, + unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7, + struct pt_regs * regs) +{ + struct rt_sigframe __user *frame = (struct rt_sigframe __user *) (long) REF_REG_SP; + sigset_t set; + stack_t __user st; + long long ret; + + if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + + if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sighand->siglock); + current->blocked = set; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ret)) + goto badframe; + regs->pc -= 4; + + if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) + goto badframe; + /* It is more difficult to avoid calling this function than to + call it and ignore errors. */ + do_sigaltstack(&st, NULL, REF_REG_SP); + + return (int) ret; + +badframe: + force_sig(SIGSEGV, current); + return 0; +} + +/* + * Set up a signal frame. + */ + +static int +setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, + unsigned long mask) +{ + int err = 0; + + /* Do this first, otherwise is this sets sr->fd, that value isn't preserved. */ + err |= setup_sigcontext_fpu(regs, sc); + +#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x) + + COPY(regs[0]); COPY(regs[1]); COPY(regs[2]); COPY(regs[3]); + COPY(regs[4]); COPY(regs[5]); COPY(regs[6]); COPY(regs[7]); + COPY(regs[8]); COPY(regs[9]); COPY(regs[10]); COPY(regs[11]); + COPY(regs[12]); COPY(regs[13]); COPY(regs[14]); COPY(regs[15]); + COPY(regs[16]); COPY(regs[17]); COPY(regs[18]); COPY(regs[19]); + COPY(regs[20]); COPY(regs[21]); COPY(regs[22]); COPY(regs[23]); + COPY(regs[24]); COPY(regs[25]); COPY(regs[26]); COPY(regs[27]); + COPY(regs[28]); COPY(regs[29]); COPY(regs[30]); COPY(regs[31]); + COPY(regs[32]); COPY(regs[33]); COPY(regs[34]); COPY(regs[35]); + COPY(regs[36]); COPY(regs[37]); COPY(regs[38]); COPY(regs[39]); + COPY(regs[40]); COPY(regs[41]); COPY(regs[42]); COPY(regs[43]); + COPY(regs[44]); COPY(regs[45]); COPY(regs[46]); COPY(regs[47]); + COPY(regs[48]); COPY(regs[49]); COPY(regs[50]); COPY(regs[51]); + COPY(regs[52]); COPY(regs[53]); COPY(regs[54]); COPY(regs[55]); + COPY(regs[56]); COPY(regs[57]); COPY(regs[58]); COPY(regs[59]); + COPY(regs[60]); COPY(regs[61]); COPY(regs[62]); + COPY(tregs[0]); COPY(tregs[1]); COPY(tregs[2]); COPY(tregs[3]); + COPY(tregs[4]); COPY(tregs[5]); COPY(tregs[6]); COPY(tregs[7]); + COPY(sr); COPY(pc); + +#undef COPY + + err |= __put_user(mask, &sc->oldmask); + + return err; +} + +/* + * Determine which stack to use.. + */ +static inline void __user * +get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) +{ + if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp)) + sp = current->sas_ss_sp + current->sas_ss_size; + + return (void __user *)((sp - frame_size) & -8ul); +} + +void sa_default_restorer(void); /* See comments below */ +void sa_default_rt_restorer(void); /* See comments below */ + +static void setup_frame(int sig, struct k_sigaction *ka, + sigset_t *set, struct pt_regs *regs) +{ + struct sigframe __user *frame; + int err = 0; + int signal; + + frame = get_sigframe(ka, regs->regs[REG_SP], sizeof(*frame)); + + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + goto give_sigsegv; + + signal = current_thread_info()->exec_domain + && current_thread_info()->exec_domain->signal_invmap + && sig < 32 + ? current_thread_info()->exec_domain->signal_invmap[sig] + : sig; + + err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); + + /* Give up earlier as i386, in case */ + if (err) + goto give_sigsegv; + + if (_NSIG_WORDS > 1) { + err |= __copy_to_user(frame->extramask, &set->sig[1], + sizeof(frame->extramask)); } + + /* Give up earlier as i386, in case */ + if (err) + goto give_sigsegv; + + /* Set up to return from userspace. If provided, use a stub + already in userspace. */ + if (ka->sa.sa_flags & SA_RESTORER) { + DEREF_REG_PR = (unsigned long) ka->sa.sa_restorer | 0x1; + + /* + * On SH5 all edited pointers are subject to NEFF + */ + DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ? + (DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR; + } else { + /* + * Different approach on SH5. + * . Endianness independent asm code gets placed in entry.S . + * This is limited to four ASM instructions corresponding + * to two long longs in size. + * . err checking is done on the else branch only + * . flush_icache_range() is called upon __put_user() only + * . all edited pointers are subject to NEFF + * . being code, linker turns ShMedia bit on, always + * dereference index -1. + */ + DEREF_REG_PR = (unsigned long) frame->retcode | 0x01; + DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ? + (DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR; + + if (__copy_to_user(frame->retcode, + (unsigned long long)sa_default_restorer & (~1), 16) != 0) + goto give_sigsegv; + + /* Cohere the trampoline with the I-cache. */ + flush_cache_sigtramp(DEREF_REG_PR-1, DEREF_REG_PR-1+16); + } + + /* + * Set up registers for signal handler. + * All edited pointers are subject to NEFF. + */ + regs->regs[REG_SP] = (unsigned long) frame; + regs->regs[REG_SP] = (regs->regs[REG_SP] & NEFF_SIGN) ? + (regs->regs[REG_SP] | NEFF_MASK) : regs->regs[REG_SP]; + regs->regs[REG_ARG1] = signal; /* Arg for signal handler */ + + /* FIXME: + The glibc profiling support for SH-5 needs to be passed a sigcontext + so it can retrieve the PC. At some point during 2003 the glibc + support was changed to receive the sigcontext through the 2nd + argument, but there are still versions of libc.so in use that use + the 3rd argument. Until libc.so is stabilised, pass the sigcontext + through both 2nd and 3rd arguments. + */ + + regs->regs[REG_ARG2] = (unsigned long long)(unsigned long)(signed long)&frame->sc; + regs->regs[REG_ARG3] = (unsigned long long)(unsigned long)(signed long)&frame->sc; + + regs->pc = (unsigned long) ka->sa.sa_handler; + regs->pc = (regs->pc & NEFF_SIGN) ? (regs->pc | NEFF_MASK) : regs->pc; + + set_fs(USER_DS); + +#if DEBUG_SIG + /* Broken %016Lx */ + printk("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n", + signal, + current->comm, current->pid, frame, + regs->pc >> 32, regs->pc & 0xffffffff, + DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff); +#endif + + return; + +give_sigsegv: + if (sig == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + force_sig(SIGSEGV, current); +} + +static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *set, struct pt_regs *regs) +{ + struct rt_sigframe __user *frame; + int err = 0; + int signal; + + frame = get_sigframe(ka, regs->regs[REG_SP], sizeof(*frame)); + + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + goto give_sigsegv; + + signal = current_thread_info()->exec_domain + && current_thread_info()->exec_domain->signal_invmap + && sig < 32 + ? current_thread_info()->exec_domain->signal_invmap[sig] + : sig; + + err |= __put_user(&frame->info, &frame->pinfo); + err |= __put_user(&frame->uc, &frame->puc); + err |= copy_siginfo_to_user(&frame->info, info); + + /* Give up earlier as i386, in case */ + if (err) + goto give_sigsegv; + + /* Create the ucontext. */ + err |= __put_user(0, &frame->uc.uc_flags); + err |= __put_user(0, &frame->uc.uc_link); + err |= __put_user((void *)current->sas_ss_sp, + &frame->uc.uc_stack.ss_sp); + err |= __put_user(sas_ss_flags(regs->regs[REG_SP]), + &frame->uc.uc_stack.ss_flags); + err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); + err |= setup_sigcontext(&frame->uc.uc_mcontext, + regs, set->sig[0]); + err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); + + /* Give up earlier as i386, in case */ + if (err) + goto give_sigsegv; + + /* Set up to return from userspace. If provided, use a stub + already in userspace. */ + if (ka->sa.sa_flags & SA_RESTORER) { + DEREF_REG_PR = (unsigned long) ka->sa.sa_restorer | 0x1; + + /* + * On SH5 all edited pointers are subject to NEFF + */ + DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ? + (DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR; + } else { + /* + * Different approach on SH5. + * . Endianness independent asm code gets placed in entry.S . + * This is limited to four ASM instructions corresponding + * to two long longs in size. + * . err checking is done on the else branch only + * . flush_icache_range() is called upon __put_user() only + * . all edited pointers are subject to NEFF + * . being code, linker turns ShMedia bit on, always + * dereference index -1. + */ + + DEREF_REG_PR = (unsigned long) frame->retcode | 0x01; + DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ? + (DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR; + + if (__copy_to_user(frame->retcode, + (unsigned long long)sa_default_rt_restorer & (~1), 16) != 0) + goto give_sigsegv; + + flush_icache_range(DEREF_REG_PR-1, DEREF_REG_PR-1+15); + } + + /* + * Set up registers for signal handler. + * All edited pointers are subject to NEFF. + */ + regs->regs[REG_SP] = (unsigned long) frame; + regs->regs[REG_SP] = (regs->regs[REG_SP] & NEFF_SIGN) ? + (regs->regs[REG_SP] | NEFF_MASK) : regs->regs[REG_SP]; + regs->regs[REG_ARG1] = signal; /* Arg for signal handler */ + regs->regs[REG_ARG2] = (unsigned long long)(unsigned long)(signed long)&frame->info; + regs->regs[REG_ARG3] = (unsigned long long)(unsigned long)(signed long)&frame->uc.uc_mcontext; + regs->pc = (unsigned long) ka->sa.sa_handler; + regs->pc = (regs->pc & NEFF_SIGN) ? (regs->pc | NEFF_MASK) : regs->pc; + + set_fs(USER_DS); + +#if DEBUG_SIG + /* Broken %016Lx */ + printk("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n", + signal, + current->comm, current->pid, frame, + regs->pc >> 32, regs->pc & 0xffffffff, + DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff); +#endif + + return; + +give_sigsegv: + if (sig == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + force_sig(SIGSEGV, current); +} + +/* + * OK, we're invoking a handler + */ + +static void +handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset, + struct pt_regs * regs) +{ + struct k_sigaction *ka = ¤t->sighand->action[sig-1]; + + /* Are we from a system call? */ + if (regs->syscall_nr >= 0) { + /* If so, check system call restarting.. */ + switch (regs->regs[REG_RET]) { + case -ERESTARTNOHAND: + regs->regs[REG_RET] = -EINTR; + break; + + case -ERESTARTSYS: + if (!(ka->sa.sa_flags & SA_RESTART)) { + regs->regs[REG_RET] = -EINTR; + break; + } + /* fallthrough */ + case -ERESTARTNOINTR: + /* Decode syscall # */ + regs->regs[REG_RET] = regs->syscall_nr; + regs->pc -= 4; + } + } + + /* Set up the stack frame */ + if (ka->sa.sa_flags & SA_SIGINFO) + setup_rt_frame(sig, ka, info, oldset, regs); + else + setup_frame(sig, ka, oldset, regs); + + if (ka->sa.sa_flags & SA_ONESHOT) + ka->sa.sa_handler = SIG_DFL; + + if (!(ka->sa.sa_flags & SA_NODEFER)) { + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigaddset(¤t->blocked,sig); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + } +} + +/* + * Note that 'init' is a special process: it doesn't get signals it doesn't + * want to handle. Thus you cannot kill init even with a SIGKILL even by + * mistake. + * + * Note that we go through the signals twice: once to check the signals that + * the kernel can handle, and then we build all the user-level signal handling + * stack-frames in one go after that. + */ +int do_signal(struct pt_regs *regs, sigset_t *oldset) +{ + siginfo_t info; + int signr; + + /* + * We want the common case to go fast, which + * is why we may in certain cases get here from + * kernel mode. Just return without doing anything + * if so. + */ + if (!user_mode(regs)) + return 1; + + if (current->flags & PF_FREEZE) { + refrigerator(0); + goto no_signal; + } + + if (!oldset) + oldset = ¤t->blocked; + + signr = get_signal_to_deliver(&info, regs, 0); + + if (signr > 0) { + /* Whee! Actually deliver the signal. */ + handle_signal(signr, &info, oldset, regs); + return 1; + } + +no_signal: + /* Did we come from a system call? */ + if (regs->syscall_nr >= 0) { + /* Restart the system call - no handlers present */ + if (regs->regs[REG_RET] == -ERESTARTNOHAND || + regs->regs[REG_RET] == -ERESTARTSYS || + regs->regs[REG_RET] == -ERESTARTNOINTR) { + /* Decode Syscall # */ + regs->regs[REG_RET] = regs->syscall_nr; + regs->pc -= 4; + } + } + return 0; +} diff -puN /dev/null arch/sh64/kernel/switchto.S --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/kernel/switchto.S 2004-06-28 13:30:30.679139904 -0700 @@ -0,0 +1,199 @@ +/* + * arch/sh64/kernel/switchto.S + * + * sh64 context switch + * + * Copyright (C) 2004 Richard Curnow + * + * 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. +*/ + + .section .text..SHmedia32,"ax" + .little + + .balign 32 + + .type sh64_switch_to,@function + .global sh64_switch_to + .global __sh64_switch_to_end +sh64_switch_to: + +/* Incoming args + r2 - prev + r3 - &prev->thread + r4 - next + r5 - &next->thread + + Outgoing results + r2 - last (=prev) + + Want to create a full (struct pt_regs) on the stack to allow backtracing + functions to work. However, we only need to populate the callee-save + register slots in this structure; since we're a function our ancestors must + have themselves preserved all caller saved state in the stack. This saves + some wasted effort since we won't need to look at the values. + + In particular, all caller-save registers are immediately available for + scratch use. + +*/ + +#define FRAME_SIZE (76*8 + 8) + + movi FRAME_SIZE, r0 + sub.l r15, r0, r15 + ! Do normal-style register save to support backtrace + + st.l r15, 0, r18 ! save link reg + st.l r15, 4, r14 ! save fp + add.l r15, r63, r14 ! setup frame pointer + + ! hopefully this looks normal to the backtrace now. + + addi.l r15, 8, r1 ! base of pt_regs + addi.l r1, 24, r0 ! base of pt_regs.regs + addi.l r0, (63*8), r8 ! base of pt_regs.trregs + + /* Note : to be fixed? + struct pt_regs is really designed for holding the state on entry + to an exception, i.e. pc,sr,regs etc. However, for the context + switch state, some of this is not required. But the unwinder takes + struct pt_regs * as an arg so we have to build this structure + to allow unwinding switched tasks in show_state() */ + + st.q r0, ( 9*8), r9 + st.q r0, (10*8), r10 + st.q r0, (11*8), r11 + st.q r0, (12*8), r12 + st.q r0, (13*8), r13 + st.q r0, (14*8), r14 ! for unwind, want to look as though we took a trap at + ! the point where the process is left in suspended animation, i.e. current + ! fp here, not the saved one. + st.q r0, (16*8), r16 + + st.q r0, (24*8), r24 + st.q r0, (25*8), r25 + st.q r0, (26*8), r26 + st.q r0, (27*8), r27 + st.q r0, (28*8), r28 + st.q r0, (29*8), r29 + st.q r0, (30*8), r30 + st.q r0, (31*8), r31 + st.q r0, (32*8), r32 + st.q r0, (33*8), r33 + st.q r0, (34*8), r34 + st.q r0, (35*8), r35 + + st.q r0, (44*8), r44 + st.q r0, (45*8), r45 + st.q r0, (46*8), r46 + st.q r0, (47*8), r47 + st.q r0, (48*8), r48 + st.q r0, (49*8), r49 + st.q r0, (50*8), r50 + st.q r0, (51*8), r51 + st.q r0, (52*8), r52 + st.q r0, (53*8), r53 + st.q r0, (54*8), r54 + st.q r0, (55*8), r55 + st.q r0, (56*8), r56 + st.q r0, (57*8), r57 + st.q r0, (58*8), r58 + st.q r0, (59*8), r59 + + ! do this early as pta->gettr has no pipeline forwarding (=> 5 cycle latency) + ! Use a local label to avoid creating a symbol that will confuse the ! + ! backtrace + pta .Lsave_pc, tr0 + + gettr tr5, r45 + gettr tr6, r46 + gettr tr7, r47 + st.q r8, (5*8), r45 + st.q r8, (6*8), r46 + st.q r8, (7*8), r47 + + ! Now switch context + gettr tr0, r9 + st.l r3, 0, r15 ! prev->thread.sp + st.l r3, 8, r1 ! prev->thread.kregs + st.l r3, 4, r9 ! prev->thread.pc + st.q r1, 0, r9 ! save prev->thread.pc into pt_regs->pc + + ! Load PC for next task (init value or save_pc later) + ld.l r5, 4, r18 ! next->thread.pc + ! Switch stacks + ld.l r5, 0, r15 ! next->thread.sp + ptabs r18, tr0 + + ! Update current + ld.l r4, 4, r9 ! next->thread_info (2nd element of next task_struct) + putcon r9, kcr0 ! current = next->thread_info + + ! go to save_pc for a reschedule, or the initial thread.pc for a new process + blink tr0, r63 + + ! Restore (when we come back to a previously saved task) +.Lsave_pc: + addi.l r15, 32, r0 ! r0 = next's regs + addi.l r0, (63*8), r8 ! r8 = next's tr_regs + + ld.q r8, (5*8), r45 + ld.q r8, (6*8), r46 + ld.q r8, (7*8), r47 + ptabs r45, tr5 + ptabs r46, tr6 + ptabs r47, tr7 + + ld.q r0, ( 9*8), r9 + ld.q r0, (10*8), r10 + ld.q r0, (11*8), r11 + ld.q r0, (12*8), r12 + ld.q r0, (13*8), r13 + ld.q r0, (14*8), r14 + ld.q r0, (16*8), r16 + + ld.q r0, (24*8), r24 + ld.q r0, (25*8), r25 + ld.q r0, (26*8), r26 + ld.q r0, (27*8), r27 + ld.q r0, (28*8), r28 + ld.q r0, (29*8), r29 + ld.q r0, (30*8), r30 + ld.q r0, (31*8), r31 + ld.q r0, (32*8), r32 + ld.q r0, (33*8), r33 + ld.q r0, (34*8), r34 + ld.q r0, (35*8), r35 + + ld.q r0, (44*8), r44 + ld.q r0, (45*8), r45 + ld.q r0, (46*8), r46 + ld.q r0, (47*8), r47 + ld.q r0, (48*8), r48 + ld.q r0, (49*8), r49 + ld.q r0, (50*8), r50 + ld.q r0, (51*8), r51 + ld.q r0, (52*8), r52 + ld.q r0, (53*8), r53 + ld.q r0, (54*8), r54 + ld.q r0, (55*8), r55 + ld.q r0, (56*8), r56 + ld.q r0, (57*8), r57 + ld.q r0, (58*8), r58 + ld.q r0, (59*8), r59 + + ! epilogue + ld.l r15, 0, r18 + ld.l r15, 4, r14 + ori r4, 0, r2 ! last = prev + ptabs r18, tr0 + movi FRAME_SIZE, r0 + add r15, r0, r15 + blink tr0, r63 +__sh64_switch_to_end: +.LFE1: + .size sh64_switch_to,.LFE1-sh64_switch_to + diff -puN /dev/null arch/sh64/kernel/syscalls.S --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/kernel/syscalls.S 2004-06-28 13:30:30.680139752 -0700 @@ -0,0 +1,340 @@ +/* + * arch/sh64/kernel/syscalls.S + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2004 Paul Mundt + * Copyright (C) 2003, 2004 Richard Curnow + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include + + .section .text..SHmedia32,"ax" + .balign 32 + +/* + * System calls jump table + */ + .globl sys_call_table +sys_call_table: + .long sys_ni_syscall /* 0 - old "setup()" system call */ + .long sys_exit + .long sys_fork + .long sys_read + .long sys_write + .long sys_open /* 5 */ + .long sys_close + .long sys_waitpid + .long sys_creat + .long sys_link + .long sys_unlink /* 10 */ + .long sys_execve + .long sys_chdir + .long sys_time + .long sys_mknod + .long sys_chmod /* 15 */ + .long sys_lchown16 + .long sys_ni_syscall /* old break syscall holder */ + .long sys_stat + .long sys_lseek + .long sys_getpid /* 20 */ + .long sys_mount + .long sys_oldumount + .long sys_setuid16 + .long sys_getuid16 + .long sys_stime /* 25 */ + .long sys_ptrace + .long sys_alarm + .long sys_fstat + .long sys_pause + .long sys_utime /* 30 */ + .long sys_ni_syscall /* old stty syscall holder */ + .long sys_ni_syscall /* old gtty syscall holder */ + .long sys_access + .long sys_nice + .long sys_ni_syscall /* 35 */ /* old ftime syscall holder */ + .long sys_sync + .long sys_kill + .long sys_rename + .long sys_mkdir + .long sys_rmdir /* 40 */ + .long sys_dup + .long sys_pipe + .long sys_times + .long sys_ni_syscall /* old prof syscall holder */ + .long sys_brk /* 45 */ + .long sys_setgid16 + .long sys_getgid16 + .long sys_signal + .long sys_geteuid16 + .long sys_getegid16 /* 50 */ + .long sys_acct + .long sys_umount /* recycled never used phys( */ + .long sys_ni_syscall /* old lock syscall holder */ + .long sys_ioctl + .long sys_fcntl /* 55 */ + .long sys_ni_syscall /* old mpx syscall holder */ + .long sys_setpgid + .long sys_ni_syscall /* old ulimit syscall holder */ + .long sys_ni_syscall /* sys_olduname */ + .long sys_umask /* 60 */ + .long sys_chroot + .long sys_ustat + .long sys_dup2 + .long sys_getppid + .long sys_getpgrp /* 65 */ + .long sys_setsid + .long sys_sigaction + .long sys_sgetmask + .long sys_ssetmask + .long sys_setreuid16 /* 70 */ + .long sys_setregid16 + .long sys_sigsuspend + .long sys_sigpending + .long sys_sethostname + .long sys_setrlimit /* 75 */ + .long sys_old_getrlimit + .long sys_getrusage + .long sys_gettimeofday + .long sys_settimeofday + .long sys_getgroups16 /* 80 */ + .long sys_setgroups16 + .long sys_ni_syscall /* sys_oldselect */ + .long sys_symlink + .long sys_lstat + .long sys_readlink /* 85 */ + .long sys_uselib + .long sys_swapon + .long sys_reboot + .long old_readdir + .long old_mmap /* 90 */ + .long sys_munmap + .long sys_truncate + .long sys_ftruncate + .long sys_fchmod + .long sys_fchown16 /* 95 */ + .long sys_getpriority + .long sys_setpriority + .long sys_ni_syscall /* old profil syscall holder */ + .long sys_statfs + .long sys_fstatfs /* 100 */ + .long sys_ni_syscall /* ioperm */ + .long sys_socketcall /* Obsolete implementation of socket syscall */ + .long sys_syslog + .long sys_setitimer + .long sys_getitimer /* 105 */ + .long sys_newstat + .long sys_newlstat + .long sys_newfstat + .long sys_uname + .long sys_ni_syscall /* 110 */ /* iopl */ + .long sys_vhangup + .long sys_ni_syscall /* idle */ + .long sys_ni_syscall /* vm86old */ + .long sys_wait4 + .long sys_swapoff /* 115 */ + .long sys_sysinfo + .long sys_ipc /* Obsolete ipc syscall implementation */ + .long sys_fsync + .long sys_sigreturn + .long sys_clone /* 120 */ + .long sys_setdomainname + .long sys_newuname + .long sys_ni_syscall /* sys_modify_ldt */ + .long sys_adjtimex + .long sys_mprotect /* 125 */ + .long sys_sigprocmask + .long sys_ni_syscall /* old "create_module" */ + .long sys_init_module + .long sys_delete_module + .long sys_ni_syscall /* 130: old "get_kernel_syms" */ + .long sys_quotactl + .long sys_getpgid + .long sys_fchdir + .long sys_bdflush + .long sys_sysfs /* 135 */ + .long sys_personality + .long sys_ni_syscall /* for afs_syscall */ + .long sys_setfsuid16 + .long sys_setfsgid16 + .long sys_llseek /* 140 */ + .long sys_getdents + .long sys_select + .long sys_flock + .long sys_msync + .long sys_readv /* 145 */ + .long sys_writev + .long sys_getsid + .long sys_fdatasync + .long sys_sysctl + .long sys_mlock /* 150 */ + .long sys_munlock + .long sys_mlockall + .long sys_munlockall + .long sys_sched_setparam + .long sys_sched_getparam /* 155 */ + .long sys_sched_setscheduler + .long sys_sched_getscheduler + .long sys_sched_yield + .long sys_sched_get_priority_max + .long sys_sched_get_priority_min /* 160 */ + .long sys_sched_rr_get_interval + .long sys_nanosleep + .long sys_mremap + .long sys_setresuid16 + .long sys_getresuid16 /* 165 */ + .long sys_ni_syscall /* vm86 */ + .long sys_ni_syscall /* old "query_module" */ + .long sys_poll + .long sys_nfsservctl + .long sys_setresgid16 /* 170 */ + .long sys_getresgid16 + .long sys_prctl + .long sys_rt_sigreturn + .long sys_rt_sigaction + .long sys_rt_sigprocmask /* 175 */ + .long sys_rt_sigpending + .long sys_rt_sigtimedwait + .long sys_rt_sigqueueinfo + .long sys_rt_sigsuspend + .long sys_pread64 /* 180 */ + .long sys_pwrite64 + .long sys_chown16 + .long sys_getcwd + .long sys_capget + .long sys_capset /* 185 */ + .long sys_sigaltstack + .long sys_sendfile + .long sys_ni_syscall /* streams1 */ + .long sys_ni_syscall /* streams2 */ + .long sys_vfork /* 190 */ + .long sys_getrlimit + .long sys_mmap2 + .long sys_truncate64 + .long sys_ftruncate64 + .long sys_stat64 /* 195 */ + .long sys_lstat64 + .long sys_fstat64 + .long sys_lchown + .long sys_getuid + .long sys_getgid /* 200 */ + .long sys_geteuid + .long sys_getegid + .long sys_setreuid + .long sys_setregid + .long sys_getgroups /* 205 */ + .long sys_setgroups + .long sys_fchown + .long sys_setresuid + .long sys_getresuid + .long sys_setresgid /* 210 */ + .long sys_getresgid + .long sys_chown + .long sys_setuid + .long sys_setgid + .long sys_setfsuid /* 215 */ + .long sys_setfsgid + .long sys_pivot_root + .long sys_mincore + .long sys_madvise + /* Broken-out socket family (maintain backwards compatibility in syscall + numbering with 2.4) */ + .long sys_socket /* 220 */ + .long sys_bind + .long sys_connect + .long sys_listen + .long sys_accept + .long sys_getsockname /* 225 */ + .long sys_getpeername + .long sys_socketpair + .long sys_send + .long sys_sendto + .long sys_recv /* 230*/ + .long sys_recvfrom + .long sys_shutdown + .long sys_setsockopt + .long sys_getsockopt + .long sys_sendmsg /* 235 */ + .long sys_recvmsg + /* Broken-out IPC family (maintain backwards compatibility in syscall + numbering with 2.4) */ + .long sys_semop + .long sys_semget + .long sys_semctl + .long sys_msgsnd /* 240 */ + .long sys_msgrcv + .long sys_msgget + .long sys_msgctl + .long sys_ni_syscall /* sys_shmatcall */ + .long sys_shmdt /* 245 */ + .long sys_shmget + .long sys_shmctl + /* Rest of syscalls listed in 2.4 i386 unistd.h */ + .long sys_getdents64 + .long sys_fcntl64 + .long sys_ni_syscall /* 250 reserved for TUX */ + .long sys_ni_syscall /* Reserved for Security */ + .long sys_gettid + .long sys_readahead + .long sys_setxattr + .long sys_lsetxattr /* 255 */ + .long sys_fsetxattr + .long sys_getxattr + .long sys_lgetxattr + .long sys_fgetxattr + .long sys_listxattr /* 260 */ + .long sys_llistxattr + .long sys_flistxattr + .long sys_removexattr + .long sys_lremovexattr + .long sys_fremovexattr /* 265 */ + .long sys_tkill + .long sys_sendfile64 + .long sys_futex + .long sys_sched_setaffinity + .long sys_sched_getaffinity /* 270 */ + .long sys_ni_syscall + .long sys_ni_syscall + .long sys_io_setup + .long sys_io_destroy + .long sys_io_getevents /* 275 */ + .long sys_io_submit + .long sys_io_cancel + .long sys_fadvise64 + .long sys_ni_syscall + .long sys_exit_group /* 280 */ + /* Rest of new 2.6 syscalls */ + .long sys_lookup_dcookie + .long sys_epoll_create + .long sys_epoll_ctl + .long sys_epoll_wait + .long sys_remap_file_pages /* 285 */ + .long sys_set_tid_address + .long sys_timer_create + .long sys_timer_settime + .long sys_timer_gettime + .long sys_timer_getoverrun /* 290 */ + .long sys_timer_delete + .long sys_clock_settime + .long sys_clock_gettime + .long sys_clock_getres + .long sys_clock_nanosleep /* 295 */ + .long sys_statfs64 + .long sys_fstatfs64 + .long sys_tgkill + .long sys_utimes + .long sys_fadvise64_64 /* 300 */ + .long sys_ni_syscall /* Reserved for vserver */ + .long sys_ni_syscall /* Reserved for mbind */ + .long sys_ni_syscall /* get_mempolicy */ + .long sys_ni_syscall /* set_mempolicy */ + .long sys_mq_open /* 305 */ + .long sys_mq_unlink + .long sys_mq_timedsend + .long sys_mq_timedreceive + .long sys_mq_notify + .long sys_mq_getsetattr /* 310 */ + diff -puN /dev/null arch/sh64/kernel/sys_sh64.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/kernel/sys_sh64.c 2004-06-28 13:30:30.682139448 -0700 @@ -0,0 +1,286 @@ +/* + * 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. + * + * arch/sh64/kernel/sys_sh64.c + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + * This file contains various random system calls that + * have a non-standard calling sequence on the Linux/SH5 + * platform. + * + * Mostly taken from i386 version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define REG_3 3 + +/* + * sys_pipe() is the normal C calling standard for creating + * a pipe. It's not the way Unix traditionally does this, though. + */ +#ifdef NEW_PIPE_IMPLEMENTATION +asmlinkage int sys_pipe(unsigned long * fildes, + unsigned long dummy_r3, + unsigned long dummy_r4, + unsigned long dummy_r5, + unsigned long dummy_r6, + unsigned long dummy_r7, + struct pt_regs * regs) /* r8 = pt_regs forced by entry.S */ +{ + int fd[2]; + int ret; + + ret = do_pipe(fd); + if (ret == 0) + /* + *********************************************************************** + * To avoid the copy_to_user we prefer to break the ABIs convention, * + * packing the valid pair of file IDs into a single register (r3); * + * while r2 is the return code as defined by the sh5-ABIs. * + * BE CAREFUL: pipe stub, into glibc, must be aware of this solution * + *********************************************************************** + +#ifdef __LITTLE_ENDIAN__ + regs->regs[REG_3] = (((unsigned long long) fd[1]) << 32) | ((unsigned long long) fd[0]); +#else + regs->regs[REG_3] = (((unsigned long long) fd[0]) << 32) | ((unsigned long long) fd[1]); +#endif + + */ + /* although not very clever this is endianess independent */ + regs->regs[REG_3] = (unsigned long long) *((unsigned long long *) fd); + + return ret; +} + +#else +asmlinkage int sys_pipe(unsigned long * fildes) +{ + int fd[2]; + int error; + + error = do_pipe(fd); + if (!error) { + if (copy_to_user(fildes, fd, 2*sizeof(int))) + error = -EFAULT; + } + return error; +} + +#endif + +/* + * To avoid cache alias, we map the shard page with same color. + */ +#define COLOUR_ALIGN(addr) (((addr)+SHMLBA-1)&~(SHMLBA-1)) + +unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, + unsigned long len, unsigned long pgoff, unsigned long flags) +{ + struct vm_area_struct *vma; + + if (flags & MAP_FIXED) { + /* We do not accept a shared mapping if it would violate + * cache aliasing constraints. + */ + if ((flags & MAP_SHARED) && (addr & (SHMLBA - 1))) + return -EINVAL; + return addr; + } + + if (len > TASK_SIZE) + return -ENOMEM; + if (!addr) + addr = TASK_UNMAPPED_BASE; + + if (flags & MAP_PRIVATE) + addr = PAGE_ALIGN(addr); + else + addr = COLOUR_ALIGN(addr); + + for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) { + /* At this point: (!vma || addr < vma->vm_end). */ + if (TASK_SIZE - len < addr) + return -ENOMEM; + if (!vma || addr + len <= vma->vm_start) + return addr; + addr = vma->vm_end; + if (!(flags & MAP_PRIVATE)) + addr = COLOUR_ALIGN(addr); + } +} + +/* common code for old and new mmaps */ +static inline long do_mmap2( + unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff) +{ + int error = -EBADF; + struct file * file = NULL; + + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + if (!(flags & MAP_ANONYMOUS)) { + file = fget(fd); + if (!file) + goto out; + } + + down_write(¤t->mm->mmap_sem); + error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); + up_write(¤t->mm->mmap_sem); + + if (file) + fput(file); +out: + return error; +} + +asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff) +{ + return do_mmap2(addr, len, prot, flags, fd, pgoff); +} + +asmlinkage int old_mmap(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + int fd, unsigned long off) +{ + if (off & ~PAGE_MASK) + return -EINVAL; + return do_mmap2(addr, len, prot, flags, fd, off>>PAGE_SHIFT); +} + +/* + * sys_ipc() is the de-multiplexer for the SysV IPC calls.. + * + * This is really horribly ugly. + */ +asmlinkage int sys_ipc(uint call, int first, int second, + int third, void __user *ptr, long fifth) +{ + int version, ret; + + version = call >> 16; /* hack for backward compatibility */ + call &= 0xffff; + + if (call <= SEMCTL) + switch (call) { + case SEMOP: + return sys_semtimedop(first, (struct sembuf __user *)ptr, + second, NULL); + case SEMTIMEDOP: + return sys_semtimedop(first, (struct sembuf __user *)ptr, + second, + (const struct timespec __user *)fifth); + case SEMGET: + return sys_semget (first, second, third); + case SEMCTL: { + union semun fourth; + if (!ptr) + return -EINVAL; + if (get_user(fourth.__pad, (void * __user *) ptr)) + return -EFAULT; + return sys_semctl (first, second, third, fourth); + } + default: + return -EINVAL; + } + + if (call <= MSGCTL) + switch (call) { + case MSGSND: + return sys_msgsnd (first, (struct msgbuf __user *) ptr, + second, third); + case MSGRCV: + switch (version) { + case 0: { + struct ipc_kludge tmp; + if (!ptr) + return -EINVAL; + + if (copy_from_user(&tmp, + (struct ipc_kludge __user *) ptr, + sizeof (tmp))) + return -EFAULT; + return sys_msgrcv (first, tmp.msgp, second, + tmp.msgtyp, third); + } + default: + return sys_msgrcv (first, + (struct msgbuf __user *) ptr, + second, fifth, third); + } + case MSGGET: + return sys_msgget ((key_t) first, second); + case MSGCTL: + return sys_msgctl (first, second, + (struct msqid_ds __user *) ptr); + default: + return -EINVAL; + } + if (call <= SHMCTL) + switch (call) { + case SHMAT: + switch (version) { + default: { + ulong raddr; + ret = do_shmat (first, (char __user *) ptr, + second, &raddr); + if (ret) + return ret; + return put_user (raddr, (ulong __user *) third); + } + case 1: /* iBCS2 emulator entry point */ + if (!segment_eq(get_fs(), get_ds())) + return -EINVAL; + return do_shmat (first, (char __user *) ptr, + second, (ulong *) third); + } + case SHMDT: + return sys_shmdt ((char __user *)ptr); + case SHMGET: + return sys_shmget (first, second, third); + case SHMCTL: + return sys_shmctl (first, second, + (struct shmid_ds __user *) ptr); + default: + return -EINVAL; + } + + return -EINVAL; +} + +asmlinkage int sys_uname(struct old_utsname * name) +{ + int err; + if (!name) + return -EFAULT; + down_read(&uts_sem); + err=copy_to_user(name, &system_utsname, sizeof (*name)); + up_read(&uts_sem); + return err?-EFAULT:0; +} + diff -puN /dev/null arch/sh64/kernel/time.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/kernel/time.c 2004-06-28 13:30:30.685138992 -0700 @@ -0,0 +1,637 @@ +/* + * 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. + * + * arch/sh64/kernel/time.c + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003, 2004 Paul Mundt + * Copyright (C) 2003 Richard Curnow + * + * Original TMU/RTC code taken from sh version. + * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka + * Some code taken from i386 version. + * Copyright (C) 1991, 1992, 1995 Linus Torvalds + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include /* required by inline __asm__ stmt. */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#define TMU_TOCR_INIT 0x00 +#define TMU0_TCR_INIT 0x0020 +#define TMU_TSTR_INIT 1 + +/* RCR1 Bits */ +#define RCR1_CF 0x80 /* Carry Flag */ +#define RCR1_CIE 0x10 /* Carry Interrupt Enable */ +#define RCR1_AIE 0x08 /* Alarm Interrupt Enable */ +#define RCR1_AF 0x01 /* Alarm Flag */ + +/* RCR2 Bits */ +#define RCR2_PEF 0x80 /* PEriodic interrupt Flag */ +#define RCR2_PESMASK 0x70 /* Periodic interrupt Set */ +#define RCR2_RTCEN 0x08 /* ENable RTC */ +#define RCR2_ADJ 0x04 /* ADJustment (30-second) */ +#define RCR2_RESET 0x02 /* Reset bit */ +#define RCR2_START 0x01 /* Start bit */ + +/* Clock, Power and Reset Controller */ +#define CPRC_BLOCK_OFF 0x01010000 +#define CPRC_BASE PHYS_PERIPHERAL_BLOCK + CPRC_BLOCK_OFF + +#define FRQCR (cprc_base+0x0) +#define WTCSR (cprc_base+0x0018) +#define STBCR (cprc_base+0x0030) + +/* Time Management Unit */ +#define TMU_BLOCK_OFF 0x01020000 +#define TMU_BASE PHYS_PERIPHERAL_BLOCK + TMU_BLOCK_OFF +#define TMU0_BASE tmu_base + 0x8 + (0xc * 0x0) +#define TMU1_BASE tmu_base + 0x8 + (0xc * 0x1) +#define TMU2_BASE tmu_base + 0x8 + (0xc * 0x2) + +#define TMU_TOCR tmu_base+0x0 /* Byte access */ +#define TMU_TSTR tmu_base+0x4 /* Byte access */ + +#define TMU0_TCOR TMU0_BASE+0x0 /* Long access */ +#define TMU0_TCNT TMU0_BASE+0x4 /* Long access */ +#define TMU0_TCR TMU0_BASE+0x8 /* Word access */ + +/* Real Time Clock */ +#define RTC_BLOCK_OFF 0x01040000 +#define RTC_BASE PHYS_PERIPHERAL_BLOCK + RTC_BLOCK_OFF + +#define R64CNT rtc_base+0x00 +#define RSECCNT rtc_base+0x04 +#define RMINCNT rtc_base+0x08 +#define RHRCNT rtc_base+0x0c +#define RWKCNT rtc_base+0x10 +#define RDAYCNT rtc_base+0x14 +#define RMONCNT rtc_base+0x18 +#define RYRCNT rtc_base+0x1c /* 16bit */ +#define RSECAR rtc_base+0x20 +#define RMINAR rtc_base+0x24 +#define RHRAR rtc_base+0x28 +#define RWKAR rtc_base+0x2c +#define RDAYAR rtc_base+0x30 +#define RMONAR rtc_base+0x34 +#define RCR1 rtc_base+0x38 +#define RCR2 rtc_base+0x3c + +#ifndef BCD_TO_BIN +#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10) +#endif + +#ifndef BIN_TO_BCD +#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10) +#endif + +#define TICK_SIZE (tick_nsec / 1000) + +extern unsigned long wall_jiffies; + +u64 jiffies_64 = INITIAL_JIFFIES; + +static unsigned long tmu_base, rtc_base; +unsigned long cprc_base; + +/* Variables to allow interpolation of time of day to resolution better than a + * jiffy. */ + +/* This is effectively protected by xtime_lock */ +static unsigned long ctc_last_interrupt; +static unsigned long long usecs_per_jiffy = 1000000/HZ; /* Approximation */ + +#define CTC_JIFFY_SCALE_SHIFT 40 + +/* 2**CTC_JIFFY_SCALE_SHIFT / ctc_ticks_per_jiffy */ +static unsigned long long scaled_recip_ctc_ticks_per_jiffy; + +/* Estimate number of microseconds that have elapsed since the last timer tick, + by scaling the delta that has occured in the CTC register. + + WARNING WARNING WARNING : This algorithm relies on the CTC decrementing at + the CPU clock rate. If the CPU sleeps, the CTC stops counting. Bear this + in mind if enabling SLEEP_WORKS in process.c. In that case, this algorithm + probably needs to use TMU.TCNT0 instead. This will work even if the CPU is + sleeping, though will be coarser. + + FIXME : What if usecs_per_tick is moving around too much, e.g. if an adjtime + is running or if the freq or tick arguments of adjtimex are modified after + we have calibrated the scaling factor? This will result in either a jump at + the end of a tick period, or a wrap backwards at the start of the next one, + if the application is reading the time of day often enough. I think we + ought to do better than this. For this reason, usecs_per_jiffy is left + separated out in the calculation below. This allows some future hook into + the adjtime-related stuff in kernel/timer.c to remove this hazard. + +*/ + +static unsigned long usecs_since_tick(void) +{ + unsigned long long current_ctc; + long ctc_ticks_since_interrupt; + unsigned long long ull_ctc_ticks_since_interrupt; + unsigned long result; + + unsigned long long mul1_out; + unsigned long long mul1_out_high; + unsigned long long mul2_out_low, mul2_out_high; + + /* Read CTC register */ + asm ("getcon cr62, %0" : "=r" (current_ctc)); + /* Note, the CTC counts down on each CPU clock, not up. + Note(2), use long type to get correct wraparound arithmetic when + the counter crosses zero. */ + ctc_ticks_since_interrupt = (long) ctc_last_interrupt - (long) current_ctc; + ull_ctc_ticks_since_interrupt = (unsigned long long) ctc_ticks_since_interrupt; + + /* Inline assembly to do 32x32x32->64 multiplier */ + asm volatile ("mulu.l %1, %2, %0" : + "=r" (mul1_out) : + "r" (ull_ctc_ticks_since_interrupt), "r" (usecs_per_jiffy)); + + mul1_out_high = mul1_out >> 32; + + asm volatile ("mulu.l %1, %2, %0" : + "=r" (mul2_out_low) : + "r" (mul1_out), "r" (scaled_recip_ctc_ticks_per_jiffy)); + +#if 1 + asm volatile ("mulu.l %1, %2, %0" : + "=r" (mul2_out_high) : + "r" (mul1_out_high), "r" (scaled_recip_ctc_ticks_per_jiffy)); +#endif + + result = (unsigned long) (((mul2_out_high << 32) + mul2_out_low) >> CTC_JIFFY_SCALE_SHIFT); + + return result; +} + +void do_gettimeofday(struct timeval *tv) +{ + unsigned long flags; + unsigned long seq; + unsigned long usec, sec; + + do { + seq = read_seqbegin_irqsave(&xtime_lock, flags); + usec = usecs_since_tick(); + { + unsigned long lost = jiffies - wall_jiffies; + + if (lost) + usec += lost * (1000000 / HZ); + } + + sec = xtime.tv_sec; + usec += xtime.tv_nsec / 1000; + } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); + + while (usec >= 1000000) { + usec -= 1000000; + sec++; + } + + tv->tv_sec = sec; + tv->tv_usec = usec; +} + +int do_settimeofday(struct timespec *tv) +{ + time_t wtm_sec, sec = tv->tv_sec; + long wtm_nsec, nsec = tv->tv_nsec; + + if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) + return -EINVAL; + + write_seqlock_irq(&xtime_lock); + /* + * This is revolting. We need to set "xtime" correctly. However, the + * value in this location is the value at the most recent update of + * wall time. Discover what correction gettimeofday() would have + * made, and then undo it! + */ + nsec -= 1000 * (usecs_since_tick() + + (jiffies - wall_jiffies) * (1000000 / HZ)); + + wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); + wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); + + set_normalized_timespec(&xtime, sec, nsec); + set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); + + time_adjust = 0; /* stop active adjtime() */ + time_status |= STA_UNSYNC; + time_maxerror = NTP_PHASE_LIMIT; + time_esterror = NTP_PHASE_LIMIT; + write_sequnlock_irq(&xtime_lock); + clock_was_set(); + + return 0; +} + +static int set_rtc_time(unsigned long nowtime) +{ + int retval = 0; + int real_seconds, real_minutes, cmos_minutes; + + ctrl_outb(RCR2_RESET, RCR2); /* Reset pre-scaler & stop RTC */ + + cmos_minutes = ctrl_inb(RMINCNT); + BCD_TO_BIN(cmos_minutes); + + /* + * since we're only adjusting minutes and seconds, + * don't interfere with hour overflow. This avoids + * messing with unknown time zones but requires your + * RTC not to be off by more than 15 minutes + */ + real_seconds = nowtime % 60; + real_minutes = nowtime / 60; + if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) + real_minutes += 30; /* correct for half hour time zone */ + real_minutes %= 60; + + if (abs(real_minutes - cmos_minutes) < 30) { + BIN_TO_BCD(real_seconds); + BIN_TO_BCD(real_minutes); + ctrl_outb(real_seconds, RSECCNT); + ctrl_outb(real_minutes, RMINCNT); + } else { + printk(KERN_WARNING + "set_rtc_time: can't update from %d to %d\n", + cmos_minutes, real_minutes); + retval = -1; + } + + ctrl_outb(RCR2_RTCEN|RCR2_START, RCR2); /* Start RTC */ + + return retval; +} + +/* last time the RTC clock got updated */ +static long last_rtc_update = 0; + +static inline void sh64_do_profile(struct pt_regs *regs) +{ + extern int _stext; + unsigned long pc; + + profile_hook(regs); + + if (user_mode(regs)) + return; + + /* Don't profile cpu_idle.. */ + if (!prof_buffer || !current->pid) + return; + + pc = instruction_pointer(regs); + pc -= (unsigned long) &_stext; + pc >>= prof_shift; + + /* + * Don't ignore out-of-bounds PC values silently, put them into the + * last histogram slot, so if present, they will show up as a sharp + * peak. + */ + if (pc > prof_len - 1) + pc = prof_len - 1; + + /* We could just be sloppy and not lock against a re-entry on this + increment, but the profiling code won't always be linked in anyway. */ + atomic_inc((atomic_t *)&prof_buffer[pc]); +} + +/* + * timer_interrupt() needs to keep up the real-time clock, + * as well as call the "do_timer()" routine every clocktick + */ +static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned long long current_ctc; + asm ("getcon cr62, %0" : "=r" (current_ctc)); + ctc_last_interrupt = (unsigned long) current_ctc; + + do_timer(regs); + + sh64_do_profile(regs); + +#ifdef CONFIG_HEARTBEAT + { + extern void heartbeat(void); + + heartbeat(); + } +#endif + + /* + * If we have an externally synchronized Linux clock, then update + * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be + * called as close as possible to 500 ms before the new second starts. + */ + if ((time_status & STA_UNSYNC) == 0 && + xtime.tv_sec > last_rtc_update + 660 && + (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 && + (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) { + if (set_rtc_time(xtime.tv_sec) == 0) + last_rtc_update = xtime.tv_sec; + else + last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ + } +} + +/* + * This is the same as the above, except we _also_ save the current + * Time Stamp Counter value at the time of the timer interrupt, so that + * we later on can estimate the time of day more exactly. + */ +static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned long timer_status; + + /* Clear UNF bit */ + timer_status = ctrl_inw(TMU0_TCR); + timer_status &= ~0x100; + ctrl_outw(timer_status, TMU0_TCR); + + /* + * Here we are in the timer irq handler. We just have irqs locally + * disabled but we don't know if the timer_bh is running on the other + * CPU. We need to avoid to SMP race with it. NOTE: we don' t need + * the irq version of write_lock because as just said we have irq + * locally disabled. -arca + */ + write_lock(&xtime_lock); + do_timer_interrupt(irq, NULL, regs); + write_unlock(&xtime_lock); + + return IRQ_HANDLED; +} + +static unsigned long get_rtc_time(void) +{ + unsigned int sec, min, hr, wk, day, mon, yr, yr100; + + again: + do { + ctrl_outb(0, RCR1); /* Clear CF-bit */ + sec = ctrl_inb(RSECCNT); + min = ctrl_inb(RMINCNT); + hr = ctrl_inb(RHRCNT); + wk = ctrl_inb(RWKCNT); + day = ctrl_inb(RDAYCNT); + mon = ctrl_inb(RMONCNT); + yr = ctrl_inw(RYRCNT); + yr100 = (yr >> 8); + yr &= 0xff; + } while ((ctrl_inb(RCR1) & RCR1_CF) != 0); + + BCD_TO_BIN(yr100); + BCD_TO_BIN(yr); + BCD_TO_BIN(mon); + BCD_TO_BIN(day); + BCD_TO_BIN(hr); + BCD_TO_BIN(min); + BCD_TO_BIN(sec); + + if (yr > 99 || mon < 1 || mon > 12 || day > 31 || day < 1 || + hr > 23 || min > 59 || sec > 59) { + printk(KERN_ERR + "SH RTC: invalid value, resetting to 1 Jan 2000\n"); + ctrl_outb(RCR2_RESET, RCR2); /* Reset & Stop */ + ctrl_outb(0, RSECCNT); + ctrl_outb(0, RMINCNT); + ctrl_outb(0, RHRCNT); + ctrl_outb(6, RWKCNT); + ctrl_outb(1, RDAYCNT); + ctrl_outb(1, RMONCNT); + ctrl_outw(0x2000, RYRCNT); + ctrl_outb(RCR2_RTCEN|RCR2_START, RCR2); /* Start */ + goto again; + } + + return mktime(yr100 * 100 + yr, mon, day, hr, min, sec); +} + +static __init unsigned int get_cpu_hz(void) +{ + unsigned int count; + unsigned long __dummy; + unsigned long ctc_val_init, ctc_val; + + /* + ** Regardless the toolchain, force the compiler to use the + ** arbitrary register r3 as a clock tick counter. + ** NOTE: r3 must be in accordance with rtc_interrupt() + */ + register unsigned long long __rtc_irq_flag __asm__ ("r3"); + + sti(); + do {} while (ctrl_inb(R64CNT) != 0); + ctrl_outb(RCR1_CIE, RCR1); /* Enable carry interrupt */ + + /* + * r3 is arbitrary. CDC does not support "=z". + */ + ctc_val_init = 0xffffffff; + ctc_val = ctc_val_init; + + asm volatile("gettr tr0, %1\n\t" + "putcon %0, " __CTC "\n\t" + "and %2, r63, %2\n\t" + "pta $+4, tr0\n\t" + "beq/l %2, r63, tr0\n\t" + "ptabs %1, tr0\n\t" + "getcon " __CTC ", %0\n\t" + : "=r"(ctc_val), "=r" (__dummy), "=r" (__rtc_irq_flag) + : "0" (0)); + cli(); + /* + * SH-3: + * CPU clock = 4 stages * loop + * tst rm,rm if id ex + * bt/s 1b if id ex + * add #1,rd if id ex + * (if) pipe line stole + * tst rm,rm if id ex + * .... + * + * + * SH-4: + * CPU clock = 6 stages * loop + * I don't know why. + * .... + * + * SH-5: + * Use CTC register to count. This approach returns the right value + * even if the I-cache is disabled (e.g. whilst debugging.) + * + */ + + count = ctc_val_init - ctc_val; /* CTC counts down */ + +#if defined (CONFIG_SH_SIMULATOR) + /* + * Let's pretend we are a 5MHz SH-5 to avoid a too + * little timer interval. Also to keep delay + * calibration within a reasonable time. + */ + return 5000000; +#else + /* + * This really is count by the number of clock cycles + * by the ratio between a complete R64CNT + * wrap-around (128) and CUI interrupt being raised (64). + */ + return count*2; +#endif +} + +static irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + ctrl_outb(0, RCR1); /* Disable Carry Interrupts */ + regs->regs[3] = 1; /* Using r3 */ + + return IRQ_HANDLED; +} + +static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL}; +static struct irqaction irq1 = { rtc_interrupt, SA_INTERRUPT, 0, "rtc", NULL, NULL}; + +void __init time_init(void) +{ + unsigned int cpu_clock, master_clock, bus_clock, module_clock; + unsigned long interval; + unsigned long frqcr, ifc, pfc; + static int ifc_table[] = { 2, 4, 6, 8, 10, 12, 16, 24 }; +#define bfc_table ifc_table /* Same */ +#define pfc_table ifc_table /* Same */ + + tmu_base = onchip_remap(TMU_BASE, 1024, "TMU"); + if (!tmu_base) { + panic("Unable to remap TMU\n"); + } + + rtc_base = onchip_remap(RTC_BASE, 1024, "RTC"); + if (!rtc_base) { + panic("Unable to remap RTC\n"); + } + + cprc_base = onchip_remap(CPRC_BASE, 1024, "CPRC"); + if (!cprc_base) { + panic("Unable to remap CPRC\n"); + } + + xtime.tv_sec = get_rtc_time(); + xtime.tv_nsec = 0; + + setup_irq(TIMER_IRQ, &irq0); + setup_irq(RTC_IRQ, &irq1); + + /* Check how fast it is.. */ + cpu_clock = get_cpu_hz(); + + /* Note careful order of operations to maintain reasonable precision and avoid overflow. */ + scaled_recip_ctc_ticks_per_jiffy = ((1ULL << CTC_JIFFY_SCALE_SHIFT) / (unsigned long long)(cpu_clock / HZ)); + + disable_irq(RTC_IRQ); + + printk("CPU clock: %d.%02dMHz\n", + (cpu_clock / 1000000), (cpu_clock % 1000000)/10000); + { + unsigned short bfc; + frqcr = ctrl_inl(FRQCR); + ifc = ifc_table[(frqcr>> 6) & 0x0007]; + bfc = bfc_table[(frqcr>> 3) & 0x0007]; + pfc = pfc_table[(frqcr>> 12) & 0x0007]; + master_clock = cpu_clock * ifc; + bus_clock = master_clock/bfc; + } + + printk("Bus clock: %d.%02dMHz\n", + (bus_clock/1000000), (bus_clock % 1000000)/10000); + module_clock = master_clock/pfc; + printk("Module clock: %d.%02dMHz\n", + (module_clock/1000000), (module_clock % 1000000)/10000); + interval = (module_clock/(HZ*4)); + + printk("Interval = %ld\n", interval); + + current_cpu_data.cpu_clock = cpu_clock; + current_cpu_data.master_clock = master_clock; + current_cpu_data.bus_clock = bus_clock; + current_cpu_data.module_clock = module_clock; + + /* Start TMU0 */ + ctrl_outb(TMU_TOCR_INIT, TMU_TOCR); + ctrl_outw(TMU0_TCR_INIT, TMU0_TCR); + ctrl_outl(interval, TMU0_TCOR); + ctrl_outl(interval, TMU0_TCNT); + ctrl_outb(TMU_TSTR_INIT, TMU_TSTR); +} + +void enter_deep_standby(void) +{ + /* Disable watchdog timer */ + ctrl_outl(0xa5000000, WTCSR); + /* Configure deep standby on sleep */ + ctrl_outl(0x03, STBCR); + +#ifdef CONFIG_SH_ALPHANUMERIC + { + extern void mach_alphanum(int position, unsigned char value); + extern void mach_alphanum_brightness(int setting); + char halted[] = "Halted. "; + int i; + mach_alphanum_brightness(6); /* dimmest setting above off */ + for (i=0; i<8; i++) { + mach_alphanum(i, halted[i]); + } + asm __volatile__ ("synco"); + } +#endif + + asm __volatile__ ("sleep"); + asm __volatile__ ("synci"); + asm __volatile__ ("nop"); + asm __volatile__ ("nop"); + asm __volatile__ ("nop"); + asm __volatile__ ("nop"); + panic("Unexpected wakeup!\n"); +} + +/* + * Scheduler clock - returns current time in nanosec units. + */ +unsigned long long sched_clock(void) +{ + return (unsigned long long)jiffies * (1000000000 / HZ); +} + diff -puN /dev/null arch/sh64/kernel/traps.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/kernel/traps.c 2004-06-28 13:30:30.689138384 -0700 @@ -0,0 +1,958 @@ +/* + * 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. + * + * arch/sh64/kernel/traps.c + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003, 2004 Paul Mundt + * Copyright (C) 2003, 2004 Richard Curnow + * + */ + +/* + * 'Traps.c' handles hardware traps and faults after we have saved some + * state in 'entry.S'. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#undef DEBUG_EXCEPTION +#ifdef DEBUG_EXCEPTION +/* implemented in ../lib/dbg.c */ +extern void show_excp_regs(char *fname, int trapnr, int signr, + struct pt_regs *regs); +#else +#define show_excp_regs(a, b, c, d) +#endif + +static void do_unhandled_exception(int trapnr, int signr, char *str, char *fn_name, + unsigned long error_code, struct pt_regs *regs, struct task_struct *tsk); + +#define DO_ERROR(trapnr, signr, str, name, tsk) \ +asmlinkage void do_##name(unsigned long error_code, struct pt_regs *regs) \ +{ \ + do_unhandled_exception(trapnr, signr, str, __stringify(name), error_code, regs, current); \ +} + +spinlock_t die_lock; + +void die(const char * str, struct pt_regs * regs, long err) +{ + console_verbose(); + spin_lock_irq(&die_lock); + printk("%s: %lx\n", str, (err & 0xffffff)); + show_regs(regs); + spin_unlock_irq(&die_lock); + do_exit(SIGSEGV); +} + +static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err) +{ + if (!user_mode(regs)) + die(str, regs, err); +} + +static void die_if_no_fixup(const char * str, struct pt_regs * regs, long err) +{ + if (!user_mode(regs)) { + const struct exception_table_entry *fixup; + fixup = search_exception_tables(regs->pc); + if (fixup) { + regs->pc = fixup->fixup; + return; + } + die(str, regs, err); + } +} + +DO_ERROR(13, SIGILL, "illegal slot instruction", illegal_slot_inst, current) +DO_ERROR(87, SIGSEGV, "address error (exec)", address_error_exec, current) + + +/* Implement misaligned load/store handling for kernel (and optionally for user + mode too). Limitation : only SHmedia mode code is handled - there is no + handling at all for misaligned accesses occurring in SHcompact code yet. */ + +static int misaligned_fixup(struct pt_regs *regs); + +asmlinkage void do_address_error_load(unsigned long error_code, struct pt_regs *regs) +{ + if (misaligned_fixup(regs) < 0) { + do_unhandled_exception(7, SIGSEGV, "address error(load)", + "do_address_error_load", + error_code, regs, current); + } + return; +} + +asmlinkage void do_address_error_store(unsigned long error_code, struct pt_regs *regs) +{ + if (misaligned_fixup(regs) < 0) { + do_unhandled_exception(8, SIGSEGV, "address error(store)", + "do_address_error_store", + error_code, regs, current); + } + return; +} + +#if defined(CONFIG_SH64_ID2815_WORKAROUND) + +#define OPCODE_INVALID 0 +#define OPCODE_USER_VALID 1 +#define OPCODE_PRIV_VALID 2 + +/* getcon/putcon - requires checking which control register is referenced. */ +#define OPCODE_CTRL_REG 3 + +/* Table of valid opcodes for SHmedia mode. + Form a 10-bit value by concatenating the major/minor opcodes i.e. + opcode[31:26,20:16]. The 6 MSBs of this value index into the following + array. The 4 LSBs select the bit-pair in the entry (bits 1:0 correspond to + LSBs==4'b0000 etc). */ +static unsigned long shmedia_opcode_table[64] = { + 0x55554044,0x54445055,0x15141514,0x14541414,0x00000000,0x10001000,0x01110055,0x04050015, + 0x00000444,0xc0000000,0x44545515,0x40405555,0x55550015,0x10005555,0x55555505,0x04050000, + 0x00000555,0x00000404,0x00040445,0x15151414,0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000055,0x40404444,0x00000404,0xc0009495,0x00000000,0x00000000,0x00000000,0x00000000, + 0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555, + 0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555, + 0x80005050,0x04005055,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555, + 0x81055554,0x00000404,0x55555555,0x55555555,0x00000000,0x00000000,0x00000000,0x00000000 +}; + +void do_reserved_inst(unsigned long error_code, struct pt_regs *regs) +{ + /* Workaround SH5-101 cut2 silicon defect #2815 : + in some situations, inter-mode branches from SHcompact -> SHmedia + which should take ITLBMISS or EXECPROT exceptions at the target + falsely take RESINST at the target instead. */ + + unsigned long opcode = 0x6ff4fff0; /* guaranteed reserved opcode */ + unsigned long pc, aligned_pc; + int get_user_error; + int trapnr = 12; + int signr = SIGILL; + char *exception_name = "reserved_instruction"; + + pc = regs->pc; + if ((pc & 3) == 1) { + /* SHmedia : check for defect. This requires executable vmas + to be readable too. */ + aligned_pc = pc & ~3; + if (!access_ok(VERIFY_READ, aligned_pc, sizeof(unsigned long))) { + get_user_error = -EFAULT; + } else { + get_user_error = __get_user(opcode, (unsigned long *)aligned_pc); + } + if (get_user_error >= 0) { + unsigned long index, shift; + unsigned long major, minor, combined; + unsigned long reserved_field; + reserved_field = opcode & 0xf; /* These bits are currently reserved as zero in all valid opcodes */ + major = (opcode >> 26) & 0x3f; + minor = (opcode >> 16) & 0xf; + combined = (major << 4) | minor; + index = major; + shift = minor << 1; + if (reserved_field == 0) { + int opcode_state = (shmedia_opcode_table[index] >> shift) & 0x3; + switch (opcode_state) { + case OPCODE_INVALID: + /* Trap. */ + break; + case OPCODE_USER_VALID: + /* Restart the instruction : the branch to the instruction will now be from an RTE + not from SHcompact so the silicon defect won't be triggered. */ + return; + case OPCODE_PRIV_VALID: + if (!user_mode(regs)) { + /* Should only ever get here if a module has + SHcompact code inside it. If so, the same fix up is needed. */ + return; /* same reason */ + } + /* Otherwise, user mode trying to execute a privileged instruction - + fall through to trap. */ + break; + case OPCODE_CTRL_REG: + /* If in privileged mode, return as above. */ + if (!user_mode(regs)) return; + /* In user mode ... */ + if (combined == 0x9f) { /* GETCON */ + unsigned long regno = (opcode >> 20) & 0x3f; + if (regno >= 62) { + return; + } + /* Otherwise, reserved or privileged control register, => trap */ + } else if (combined == 0x1bf) { /* PUTCON */ + unsigned long regno = (opcode >> 4) & 0x3f; + if (regno >= 62) { + return; + } + /* Otherwise, reserved or privileged control register, => trap */ + } else { + /* Trap */ + } + break; + default: + /* Fall through to trap. */ + break; + } + } + /* fall through to normal resinst processing */ + } else { + /* Error trying to read opcode. This typically means a + real fault, not a RESINST any more. So change the + codes. */ + trapnr = 87; + exception_name = "address error (exec)"; + signr = SIGSEGV; + } + } + + do_unhandled_exception(trapnr, signr, exception_name, "do_reserved_inst", error_code, regs, current); +} + +#else /* CONFIG_SH64_ID2815_WORKAROUND */ + +/* If the workaround isn't needed, this is just a straightforward reserved + instruction */ +DO_ERROR(12, SIGILL, "reserved instruction", reserved_inst, current) + +#endif /* CONFIG_SH64_ID2815_WORKAROUND */ + + +#include + +/* Called with interrupts disabled */ +asmlinkage void do_exception_error(unsigned long ex, struct pt_regs *regs) +{ + PLS(); + show_excp_regs(__FUNCTION__, -1, -1, regs); + die_if_kernel("exception", regs, ex); +} + +int do_unknown_trapa(unsigned long scId, struct pt_regs *regs) +{ + /* Syscall debug */ + printk("System call ID error: [0x1#args:8 #syscall:16 0x%lx]\n", scId); + + die_if_kernel("unknown trapa", regs, scId); + + return -ENOSYS; +} + +void show_stack(struct task_struct *tsk, unsigned long *sp) +{ +#ifdef CONFIG_KALLSYMS + extern void sh64_unwind(struct pt_regs *regs); + struct pt_regs *regs; + + regs = tsk ? tsk->thread.kregs : NULL; + + sh64_unwind(regs); +#else + printk(KERN_ERR "Can't backtrace on sh64 without CONFIG_KALLSYMS\n"); +#endif +} + +void show_task(unsigned long *sp) +{ + show_stack(NULL, sp); +} + +void dump_stack(void) +{ + show_task(NULL); +} + +static void do_unhandled_exception(int trapnr, int signr, char *str, char *fn_name, + unsigned long error_code, struct pt_regs *regs, struct task_struct *tsk) +{ + show_excp_regs(fn_name, trapnr, signr, regs); + tsk->thread.error_code = error_code; + tsk->thread.trap_no = trapnr; + + if (user_mode(regs)) + force_sig(signr, tsk); + + die_if_no_fixup(str, regs, error_code); +} + +static int read_opcode(unsigned long long pc, unsigned long *result_opcode, int from_user_mode) +{ + int get_user_error; + unsigned long aligned_pc; + unsigned long opcode; + + if ((pc & 3) == 1) { + /* SHmedia */ + aligned_pc = pc & ~3; + if (from_user_mode) { + if (!access_ok(VERIFY_READ, aligned_pc, sizeof(unsigned long))) { + get_user_error = -EFAULT; + } else { + get_user_error = __get_user(opcode, (unsigned long *)aligned_pc); + *result_opcode = opcode; + } + return get_user_error; + } else { + /* If the fault was in the kernel, we can either read + * this directly, or if not, we fault. + */ + *result_opcode = *(unsigned long *) aligned_pc; + return 0; + } + } else if ((pc & 1) == 0) { + /* SHcompact */ + /* TODO : provide handling for this. We don't really support + user-mode SHcompact yet, and for a kernel fault, this would + have to come from a module built for SHcompact. */ + return -EFAULT; + } else { + /* misaligned */ + return -EFAULT; + } +} + +static int address_is_sign_extended(__u64 a) +{ + __u64 b; +#if (NEFF == 32) + b = (__u64)(__s64)(__s32)(a & 0xffffffffUL); + return (b == a) ? 1 : 0; +#else +#error "Sign extend check only works for NEFF==32" +#endif +} + +static int generate_and_check_address(struct pt_regs *regs, + __u32 opcode, + int displacement_not_indexed, + int width_shift, + __u64 *address) +{ + /* return -1 for fault, 0 for OK */ + + __u64 base_address, addr; + int basereg; + + basereg = (opcode >> 20) & 0x3f; + base_address = regs->regs[basereg]; + if (displacement_not_indexed) { + __s64 displacement; + displacement = (opcode >> 10) & 0x3ff; + displacement = ((displacement << 54) >> 54); /* sign extend */ + addr = (__u64)((__s64)base_address + (displacement << width_shift)); + } else { + __u64 offset; + int offsetreg; + offsetreg = (opcode >> 10) & 0x3f; + offset = regs->regs[offsetreg]; + addr = base_address + offset; + } + + /* Check sign extended */ + if (!address_is_sign_extended(addr)) { + return -1; + } + +#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP) + /* Check accessible. For misaligned access in the kernel, assume the + address is always accessible (and if not, just fault when the + load/store gets done.) */ + if (user_mode(regs)) { + if (addr >= TASK_SIZE) { + return -1; + } + /* Do access_ok check later - it depends on whether it's a load or a store. */ + } +#endif + + *address = addr; + return 0; +} + +/* Default value as for sh */ +#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP) +static int user_mode_unaligned_fixup_count = 10; +static int user_mode_unaligned_fixup_enable = 1; +#endif + +static int kernel_mode_unaligned_fixup_count = 32; + +static void misaligned_kernel_word_load(__u64 address, int do_sign_extend, __u64 *result) +{ + unsigned short x; + unsigned char *p, *q; + p = (unsigned char *) (int) address; + q = (unsigned char *) &x; + q[0] = p[0]; + q[1] = p[1]; + + if (do_sign_extend) { + *result = (__u64)(__s64) *(short *) &x; + } else { + *result = (__u64) x; + } +} + +static void misaligned_kernel_word_store(__u64 address, __u64 value) +{ + unsigned short x; + unsigned char *p, *q; + p = (unsigned char *) (int) address; + q = (unsigned char *) &x; + + x = (__u16) value; + p[0] = q[0]; + p[1] = q[1]; +} + +static int misaligned_load(struct pt_regs *regs, + __u32 opcode, + int displacement_not_indexed, + int width_shift, + int do_sign_extend) +{ + /* Return -1 for a fault, 0 for OK */ + int error; + int destreg; + __u64 address; + + error = generate_and_check_address(regs, opcode, + displacement_not_indexed, width_shift, &address); + if (error < 0) { + return error; + } + + destreg = (opcode >> 4) & 0x3f; +#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP) + if (user_mode(regs)) { + __u64 buffer; + + if (!access_ok(VERIFY_READ, (unsigned long) address, 1UL< 0) { + return -1; /* fault */ + } + switch (width_shift) { + case 1: + if (do_sign_extend) { + regs->regs[destreg] = (__u64)(__s64) *(__s16 *) &buffer; + } else { + regs->regs[destreg] = (__u64) *(__u16 *) &buffer; + } + break; + case 2: + regs->regs[destreg] = (__u64)(__s64) *(__s32 *) &buffer; + break; + case 3: + regs->regs[destreg] = buffer; + break; + default: + printk("Unexpected width_shift %d in misaligned_load, PC=%08lx\n", + width_shift, (unsigned long) regs->pc); + break; + } + } else +#endif + { + /* kernel mode - we can take short cuts since if we fault, it's a genuine bug */ + __u64 lo, hi; + + switch (width_shift) { + case 1: + misaligned_kernel_word_load(address, do_sign_extend, ®s->regs[destreg]); + break; + case 2: + asm ("ldlo.l %1, 0, %0" : "=r" (lo) : "r" (address)); + asm ("ldhi.l %1, 3, %0" : "=r" (hi) : "r" (address)); + regs->regs[destreg] = lo | hi; + break; + case 3: + asm ("ldlo.q %1, 0, %0" : "=r" (lo) : "r" (address)); + asm ("ldhi.q %1, 7, %0" : "=r" (hi) : "r" (address)); + regs->regs[destreg] = lo | hi; + break; + + default: + printk("Unexpected width_shift %d in misaligned_load, PC=%08lx\n", + width_shift, (unsigned long) regs->pc); + break; + } + } + + return 0; + +} + +static int misaligned_store(struct pt_regs *regs, + __u32 opcode, + int displacement_not_indexed, + int width_shift) +{ + /* Return -1 for a fault, 0 for OK */ + int error; + int srcreg; + __u64 address; + + error = generate_and_check_address(regs, opcode, + displacement_not_indexed, width_shift, &address); + if (error < 0) { + return error; + } + + srcreg = (opcode >> 4) & 0x3f; +#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP) + if (user_mode(regs)) { + __u64 buffer; + + if (!access_ok(VERIFY_WRITE, (unsigned long) address, 1UL<regs[srcreg]; + break; + case 2: + *(__u32 *) &buffer = (__u32) regs->regs[srcreg]; + break; + case 3: + buffer = regs->regs[srcreg]; + break; + default: + printk("Unexpected width_shift %d in misaligned_store, PC=%08lx\n", + width_shift, (unsigned long) regs->pc); + break; + } + + if (__copy_user((void *)(int)address, &buffer, (1 << width_shift)) > 0) { + return -1; /* fault */ + } + } else +#endif + { + /* kernel mode - we can take short cuts since if we fault, it's a genuine bug */ + __u64 val = regs->regs[srcreg]; + + switch (width_shift) { + case 1: + misaligned_kernel_word_store(address, val); + break; + case 2: + asm ("stlo.l %1, 0, %0" : : "r" (val), "r" (address)); + asm ("sthi.l %1, 3, %0" : : "r" (val), "r" (address)); + break; + case 3: + asm ("stlo.q %1, 0, %0" : : "r" (val), "r" (address)); + asm ("sthi.q %1, 7, %0" : : "r" (val), "r" (address)); + break; + + default: + printk("Unexpected width_shift %d in misaligned_store, PC=%08lx\n", + width_shift, (unsigned long) regs->pc); + break; + } + } + + return 0; + +} + +#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP) +/* Never need to fix up misaligned FPU accesses within the kernel since that's a real + error. */ +static int misaligned_fpu_load(struct pt_regs *regs, + __u32 opcode, + int displacement_not_indexed, + int width_shift, + int do_paired_load) +{ + /* Return -1 for a fault, 0 for OK */ + int error; + int destreg; + __u64 address; + + error = generate_and_check_address(regs, opcode, + displacement_not_indexed, width_shift, &address); + if (error < 0) { + return error; + } + + destreg = (opcode >> 4) & 0x3f; + if (user_mode(regs)) { + __u64 buffer; + __u32 buflo, bufhi; + + if (!access_ok(VERIFY_READ, (unsigned long) address, 1UL< 0) { + return -1; /* fault */ + } + /* 'current' may be the current owner of the FPU state, so + context switch the registers into memory so they can be + indexed by register number. */ + if (last_task_used_math == current) { + grab_fpu(); + fpsave(¤t->thread.fpu.hard); + release_fpu(); + last_task_used_math = NULL; + regs->sr |= SR_FD; + } + + buflo = *(__u32*) &buffer; + bufhi = *(1 + (__u32*) &buffer); + + switch (width_shift) { + case 2: + current->thread.fpu.hard.fp_regs[destreg] = buflo; + break; + case 3: + if (do_paired_load) { + current->thread.fpu.hard.fp_regs[destreg] = buflo; + current->thread.fpu.hard.fp_regs[destreg+1] = bufhi; + } else { +#if defined(CONFIG_LITTLE_ENDIAN) + current->thread.fpu.hard.fp_regs[destreg] = bufhi; + current->thread.fpu.hard.fp_regs[destreg+1] = buflo; +#else + current->thread.fpu.hard.fp_regs[destreg] = buflo; + current->thread.fpu.hard.fp_regs[destreg+1] = bufhi; +#endif + } + break; + default: + printk("Unexpected width_shift %d in misaligned_fpu_load, PC=%08lx\n", + width_shift, (unsigned long) regs->pc); + break; + } + return 0; + } else { + die ("Misaligned FPU load inside kernel", regs, 0); + return -1; + } + + +} + +static int misaligned_fpu_store(struct pt_regs *regs, + __u32 opcode, + int displacement_not_indexed, + int width_shift, + int do_paired_load) +{ + /* Return -1 for a fault, 0 for OK */ + int error; + int srcreg; + __u64 address; + + error = generate_and_check_address(regs, opcode, + displacement_not_indexed, width_shift, &address); + if (error < 0) { + return error; + } + + srcreg = (opcode >> 4) & 0x3f; + if (user_mode(regs)) { + __u64 buffer; + /* Initialise these to NaNs. */ + __u32 buflo=0xffffffffUL, bufhi=0xffffffffUL; + + if (!access_ok(VERIFY_WRITE, (unsigned long) address, 1UL<thread.fpu.hard); + release_fpu(); + last_task_used_math = NULL; + regs->sr |= SR_FD; + } + + switch (width_shift) { + case 2: + buflo = current->thread.fpu.hard.fp_regs[srcreg]; + break; + case 3: + if (do_paired_load) { + buflo = current->thread.fpu.hard.fp_regs[srcreg]; + bufhi = current->thread.fpu.hard.fp_regs[srcreg+1]; + } else { +#if defined(CONFIG_LITTLE_ENDIAN) + bufhi = current->thread.fpu.hard.fp_regs[srcreg]; + buflo = current->thread.fpu.hard.fp_regs[srcreg+1]; +#else + buflo = current->thread.fpu.hard.fp_regs[srcreg]; + bufhi = current->thread.fpu.hard.fp_regs[srcreg+1]; +#endif + } + break; + default: + printk("Unexpected width_shift %d in misaligned_fpu_store, PC=%08lx\n", + width_shift, (unsigned long) regs->pc); + break; + } + + *(__u32*) &buffer = buflo; + *(1 + (__u32*) &buffer) = bufhi; + if (__copy_user((void *)(int)address, &buffer, (1 << width_shift)) > 0) { + return -1; /* fault */ + } + return 0; + } else { + die ("Misaligned FPU load inside kernel", regs, 0); + return -1; + } +} +#endif + +static int misaligned_fixup(struct pt_regs *regs) +{ + unsigned long opcode; + int error; + int major, minor; + +#if !defined(CONFIG_SH64_USER_MISALIGNED_FIXUP) + /* Never fixup user mode misaligned accesses without this option enabled. */ + return -1; +#else + if (!user_mode_unaligned_fixup_enable) return -1; +#endif + + error = read_opcode(regs->pc, &opcode, user_mode(regs)); + if (error < 0) { + return error; + } + major = (opcode >> 26) & 0x3f; + minor = (opcode >> 16) & 0xf; + +#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP) + if (user_mode(regs) && (user_mode_unaligned_fixup_count > 0)) { + --user_mode_unaligned_fixup_count; + /* Only do 'count' worth of these reports, to remove a potential DoS against syslog */ + printk("Fixing up unaligned userspace access in \"%s\" pid=%d pc=0x%08x ins=0x%08lx\n", + current->comm, current->pid, (__u32)regs->pc, opcode); + } else +#endif + if (!user_mode(regs) && (kernel_mode_unaligned_fixup_count > 0)) { + --kernel_mode_unaligned_fixup_count; + if (in_interrupt()) { + printk("Fixing up unaligned kernelspace access in interrupt pc=0x%08x ins=0x%08lx\n", + (__u32)regs->pc, opcode); + } else { + printk("Fixing up unaligned kernelspace access in \"%s\" pid=%d pc=0x%08x ins=0x%08lx\n", + current->comm, current->pid, (__u32)regs->pc, opcode); + } + } + + + switch (major) { + case (0x84>>2): /* LD.W */ + error = misaligned_load(regs, opcode, 1, 1, 1); + break; + case (0xb0>>2): /* LD.UW */ + error = misaligned_load(regs, opcode, 1, 1, 0); + break; + case (0x88>>2): /* LD.L */ + error = misaligned_load(regs, opcode, 1, 2, 1); + break; + case (0x8c>>2): /* LD.Q */ + error = misaligned_load(regs, opcode, 1, 3, 0); + break; + + case (0xa4>>2): /* ST.W */ + error = misaligned_store(regs, opcode, 1, 1); + break; + case (0xa8>>2): /* ST.L */ + error = misaligned_store(regs, opcode, 1, 2); + break; + case (0xac>>2): /* ST.Q */ + error = misaligned_store(regs, opcode, 1, 3); + break; + + case (0x40>>2): /* indexed loads */ + switch (minor) { + case 0x1: /* LDX.W */ + error = misaligned_load(regs, opcode, 0, 1, 1); + break; + case 0x5: /* LDX.UW */ + error = misaligned_load(regs, opcode, 0, 1, 0); + break; + case 0x2: /* LDX.L */ + error = misaligned_load(regs, opcode, 0, 2, 1); + break; + case 0x3: /* LDX.Q */ + error = misaligned_load(regs, opcode, 0, 3, 0); + break; + default: + error = -1; + break; + } + break; + + case (0x60>>2): /* indexed stores */ + switch (minor) { + case 0x1: /* STX.W */ + error = misaligned_store(regs, opcode, 0, 1); + break; + case 0x2: /* STX.L */ + error = misaligned_store(regs, opcode, 0, 2); + break; + case 0x3: /* STX.Q */ + error = misaligned_store(regs, opcode, 0, 3); + break; + default: + error = -1; + break; + } + break; + +#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP) + case (0x94>>2): /* FLD.S */ + error = misaligned_fpu_load(regs, opcode, 1, 2, 0); + break; + case (0x98>>2): /* FLD.P */ + error = misaligned_fpu_load(regs, opcode, 1, 3, 1); + break; + case (0x9c>>2): /* FLD.D */ + error = misaligned_fpu_load(regs, opcode, 1, 3, 0); + break; + case (0x1c>>2): /* floating indexed loads */ + switch (minor) { + case 0x8: /* FLDX.S */ + error = misaligned_fpu_load(regs, opcode, 0, 2, 0); + break; + case 0xd: /* FLDX.P */ + error = misaligned_fpu_load(regs, opcode, 0, 3, 1); + break; + case 0x9: /* FLDX.D */ + error = misaligned_fpu_load(regs, opcode, 0, 3, 0); + break; + default: + error = -1; + break; + } + break; + case (0xb4>>2): /* FLD.S */ + error = misaligned_fpu_store(regs, opcode, 1, 2, 0); + break; + case (0xb8>>2): /* FLD.P */ + error = misaligned_fpu_store(regs, opcode, 1, 3, 1); + break; + case (0xbc>>2): /* FLD.D */ + error = misaligned_fpu_store(regs, opcode, 1, 3, 0); + break; + case (0x3c>>2): /* floating indexed stores */ + switch (minor) { + case 0x8: /* FSTX.S */ + error = misaligned_fpu_store(regs, opcode, 0, 2, 0); + break; + case 0xd: /* FSTX.P */ + error = misaligned_fpu_store(regs, opcode, 0, 3, 1); + break; + case 0x9: /* FSTX.D */ + error = misaligned_fpu_store(regs, opcode, 0, 3, 0); + break; + default: + error = -1; + break; + } + break; +#endif + + default: + /* Fault */ + error = -1; + break; + } + + if (error < 0) { + return error; + } else { + regs->pc += 4; /* Skip the instruction that's just been emulated */ + return 0; + } + +} + +static ctl_table unaligned_table[] = { + {1, "kernel_reports", &kernel_mode_unaligned_fixup_count, + sizeof(int), 0644, NULL, &proc_dointvec}, +#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP) + {2, "user_reports", &user_mode_unaligned_fixup_count, + sizeof(int), 0644, NULL, &proc_dointvec}, + {3, "user_enable", &user_mode_unaligned_fixup_enable, + sizeof(int), 0644, NULL, &proc_dointvec}, +#endif + {0} +}; + +static ctl_table unaligned_root[] = { + {1, "unaligned_fixup", NULL, 0, 0555, unaligned_table}, + {0} +}; + +static ctl_table sh64_root[] = { + {1, "sh64", NULL, 0, 0555, unaligned_root}, + {0} +}; +static struct ctl_table_header *sysctl_header; +static int __init init_sysctl(void) +{ + sysctl_header = register_sysctl_table(sh64_root, 0); + return 0; +} + +__initcall(init_sysctl); + + +asmlinkage void do_debug_interrupt(unsigned long code, struct pt_regs *regs) +{ + u64 peek_real_address_q(u64 addr); + u64 poke_real_address_q(u64 addr, u64 val); + unsigned long long DM_EXP_CAUSE_PHY = 0x0c100010; + unsigned long long exp_cause; + /* It's not worth ioremapping the debug module registers for the amount + of access we make to them - just go direct to their physical + addresses. */ + exp_cause = peek_real_address_q(DM_EXP_CAUSE_PHY); + if (exp_cause & ~4) { + printk("DM.EXP_CAUSE had unexpected bits set (=%08lx)\n", + (unsigned long)(exp_cause & 0xffffffff)); + } + show_state(); + /* Clear all DEBUGINT causes */ + poke_real_address_q(DM_EXP_CAUSE_PHY, 0x0); +} + diff -puN /dev/null arch/sh64/kernel/unwind.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/kernel/unwind.c 2004-06-28 13:30:30.691138080 -0700 @@ -0,0 +1,326 @@ +/* + * arch/sh64/kernel/unwind.c + * + * Copyright (C) 2004 Paul Mundt + * Copyright (C) 2004 Richard Curnow + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +static u8 regcache[63]; + +/* + * Finding the previous stack frame isn't horribly straightforward as it is + * on some other platforms. In the sh64 case, we don't have "linked" stack + * frames, so we need to do a bit of work to determine the previous frame, + * and in turn, the previous r14/r18 pair. + * + * There are generally a few cases which determine where we can find out + * the r14/r18 values. In the general case, this can be determined by poking + * around the prologue of the symbol PC is in (note that we absolutely must + * have frame pointer support as well as the kernel symbol table mapped, + * otherwise we can't even get this far). + * + * In other cases, such as the interrupt/exception path, we can poke around + * the sp/fp. + * + * Notably, this entire approach is somewhat error prone, and in the event + * that the previous frame cannot be determined, that's all we can do. + * Either way, this still leaves us with a more correct backtrace then what + * we would be able to come up with by walking the stack (which is garbage + * for anything beyond the first frame). + * -- PFM. + */ +static int lookup_prev_stack_frame(unsigned long fp, unsigned long pc, + unsigned long *pprev_fp, unsigned long *pprev_pc, + struct pt_regs *regs) +{ + const char *sym; + char *modname, namebuf[128]; + unsigned long offset, size; + unsigned long prologue = 0; + unsigned long fp_displacement = 0; + unsigned long fp_prev = 0; + unsigned long offset_r14 = 0, offset_r18 = 0; + int i, found_prologue_end = 0; + + sym = kallsyms_lookup(pc, &size, &offset, &modname, namebuf); + if (!sym) + return -EINVAL; + + prologue = pc - offset; + if (!prologue) + return -EINVAL; + + /* Validate fp, to avoid risk of dereferencing a bad pointer later. + Assume 128Mb since that's the amount of RAM on a Cayman. Modify + when there is an SH-5 board with more. */ + if ((fp < (unsigned long) phys_to_virt(__MEMORY_START)) || + (fp >= (unsigned long)(phys_to_virt(__MEMORY_START)) + 128*1024*1024) || + ((fp & 7) != 0)) { + return -EINVAL; + } + + /* + * Depth to walk, depth is completely arbitrary. + */ + for (i = 0; i < 100; i++, prologue += sizeof(unsigned long)) { + unsigned long op; + u8 major, minor; + u8 src, dest, disp; + + op = *(unsigned long *)prologue; + + major = (op >> 26) & 0x3f; + src = (op >> 20) & 0x3f; + minor = (op >> 16) & 0xf; + disp = (op >> 10) & 0x3f; + dest = (op >> 4) & 0x3f; + + /* + * Stack frame creation happens in a number of ways.. in the + * general case when the stack frame is less than 511 bytes, + * it's generally created by an addi or addi.l: + * + * addi/addi.l r15, -FRAME_SIZE, r15 + * + * in the event that the frame size is bigger than this, it's + * typically created using a movi/sub pair as follows: + * + * movi FRAME_SIZE, rX + * sub r15, rX, r15 + */ + + switch (major) { + case (0x00 >> 2): + switch (minor) { + case 0x8: /* add.l */ + case 0x9: /* add */ + /* Look for r15, r63, r14 */ + if (src == 15 && disp == 63 && dest == 14) + found_prologue_end = 1; + + break; + case 0xa: /* sub.l */ + case 0xb: /* sub */ + if (src != 15 || dest != 15) + continue; + + fp_displacement -= regcache[disp]; + fp_prev = fp - fp_displacement; + break; + } + break; + case (0xa8 >> 2): /* st.l */ + if (src != 15) + continue; + + switch (dest) { + case 14: + if (offset_r14 || fp_displacement == 0) + continue; + + offset_r14 = (u64)(((((s64)op >> 10) & 0x3ff) << 54) >> 54); + offset_r14 *= sizeof(unsigned long); + offset_r14 += fp_displacement; + break; + case 18: + if (offset_r18 || fp_displacement == 0) + continue; + + offset_r18 = (u64)(((((s64)op >> 10) & 0x3ff) << 54) >> 54); + offset_r18 *= sizeof(unsigned long); + offset_r18 += fp_displacement; + break; + } + + break; + case (0xcc >> 2): /* movi */ + if (dest >= 63) { + printk(KERN_NOTICE "%s: Invalid dest reg %d " + "specified in movi handler. Failed " + "opcode was 0x%lx: ", __FUNCTION__, + dest, op); + + continue; + } + + /* Sign extend */ + regcache[dest] = + ((((s64)(u64)op >> 10) & 0xffff) << 54) >> 54; + break; + case (0xd0 >> 2): /* addi */ + case (0xd4 >> 2): /* addi.l */ + /* Look for r15, -FRAME_SIZE, r15 */ + if (src != 15 || dest != 15) + continue; + + /* Sign extended frame size.. */ + fp_displacement += + (u64)(((((s64)op >> 10) & 0x3ff) << 54) >> 54); + fp_prev = fp - fp_displacement; + break; + } + + if (found_prologue_end && offset_r14 && (offset_r18 || *pprev_pc) && fp_prev) + break; + } + + if (offset_r14 == 0 || fp_prev == 0) { + if (!offset_r14) + pr_debug("Unable to find r14 offset\n"); + if (!fp_prev) + pr_debug("Unable to find previous fp\n"); + + return -EINVAL; + } + + /* For innermost leaf function, there might not be a offset_r18 */ + if (!*pprev_pc && (offset_r18 == 0)) + return -EINVAL; + + *pprev_fp = *(unsigned long *)(fp_prev + offset_r14); + + if (offset_r18) + *pprev_pc = *(unsigned long *)(fp_prev + offset_r18); + + *pprev_pc &= ~1; + + return 0; +} + +/* Don't put this on the stack since we'll want to call sh64_unwind + * when we're close to underflowing the stack anyway. */ +static struct pt_regs here_regs; + +extern const char syscall_ret; +extern const char ret_from_syscall; +extern const char ret_from_exception; +extern const char ret_from_irq; + +static void sh64_unwind_inner(struct pt_regs *regs); + +static void unwind_nested (unsigned long pc, unsigned long fp) +{ + if ((fp >= __MEMORY_START) && + ((fp & 7) == 0)) { + sh64_unwind_inner((struct pt_regs *) fp); + } +} + +static void sh64_unwind_inner(struct pt_regs *regs) +{ + unsigned long pc, fp; + int ofs = 0; + int first_pass; + + pc = regs->pc & ~1; + fp = regs->regs[14]; + + first_pass = 1; + for (;;) { + int cond; + unsigned long next_fp, next_pc; + + if (pc == ((unsigned long) &syscall_ret & ~1)) { + printk("SYSCALL\n"); + unwind_nested(pc,fp); + return; + } + + if (pc == ((unsigned long) &ret_from_syscall & ~1)) { + printk("SYSCALL (PREEMPTED)\n"); + unwind_nested(pc,fp); + return; + } + + /* In this case, the PC is discovered by lookup_prev_stack_frame but + it has 4 taken off it to look like the 'caller' */ + if (pc == ((unsigned long) &ret_from_exception & ~1)) { + printk("EXCEPTION\n"); + unwind_nested(pc,fp); + return; + } + + if (pc == ((unsigned long) &ret_from_irq & ~1)) { + printk("IRQ\n"); + unwind_nested(pc,fp); + return; + } + + cond = ((pc >= __MEMORY_START) && (fp >= __MEMORY_START) && + ((pc & 3) == 0) && ((fp & 7) == 0)); + + pc -= ofs; + + printk("[<%08lx>] ", pc); + print_symbol("%s\n", pc); + + if (first_pass) { + /* If the innermost frame is a leaf function, it's + * possible that r18 is never saved out to the stack. + */ + next_pc = regs->regs[18]; + } else { + next_pc = 0; + } + + if (lookup_prev_stack_frame(fp, pc, &next_fp, &next_pc, regs) == 0) { + ofs = sizeof(unsigned long); + pc = next_pc & ~1; + fp = next_fp; + } else { + printk("Unable to lookup previous stack frame\n"); + break; + } + first_pass = 0; + } + + printk("\n"); + +} + +void sh64_unwind(struct pt_regs *regs) +{ + if (!regs) { + /* + * Fetch current regs if we have no other saved state to back + * trace from. + */ + regs = &here_regs; + + __asm__ __volatile__ ("ori r14, 0, %0" : "=r" (regs->regs[14])); + __asm__ __volatile__ ("ori r15, 0, %0" : "=r" (regs->regs[15])); + __asm__ __volatile__ ("ori r18, 0, %0" : "=r" (regs->regs[18])); + + __asm__ __volatile__ ("gettr tr0, %0" : "=r" (regs->tregs[0])); + __asm__ __volatile__ ("gettr tr1, %0" : "=r" (regs->tregs[1])); + __asm__ __volatile__ ("gettr tr2, %0" : "=r" (regs->tregs[2])); + __asm__ __volatile__ ("gettr tr3, %0" : "=r" (regs->tregs[3])); + __asm__ __volatile__ ("gettr tr4, %0" : "=r" (regs->tregs[4])); + __asm__ __volatile__ ("gettr tr5, %0" : "=r" (regs->tregs[5])); + __asm__ __volatile__ ("gettr tr6, %0" : "=r" (regs->tregs[6])); + __asm__ __volatile__ ("gettr tr7, %0" : "=r" (regs->tregs[7])); + + __asm__ __volatile__ ( + "pta 0f, tr0\n\t" + "blink tr0, %0\n\t" + "0: nop" + : "=r" (regs->pc) + ); + } + + printk("\nCall Trace:\n"); + sh64_unwind_inner(regs); +} + diff -puN /dev/null arch/sh64/kernel/vmlinux.lds.S --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/kernel/vmlinux.lds.S 2004-06-28 13:30:30.692137928 -0700 @@ -0,0 +1,183 @@ +/* + * 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. + * + * arch/sh5/vmlinux.lds.S + * + * ld script to make ST50 Linux kernel + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + * benedict.gaster@superh.com: 2nd May 2002 + * Add definition of empty_zero_page to be the first page of kernel image. + * + * benedict.gaster@superh.com: 3rd May 2002 + * Added support for ramdisk, removing statically linked romfs at the same time. + * + * lethal@linux-sh.org: 9th May 2003 + * Kill off GLOBAL_NAME() usage and other CDC-isms. + * + * lethal@linux-sh.org: 19th May 2003 + * Remove support for ancient toolchains. + */ + +#include +#include +#include +#include +#include + +#define LOAD_OFFSET CONFIG_CACHED_MEMORY_OFFSET +#include + +#ifdef NOTDEF +#ifdef CONFIG_LITTLE_ENDIAN +OUTPUT_FORMAT("elf32-sh64l-linux", "elf32-sh64l-linux", "elf32-sh64l-linux") +#else +OUTPUT_FORMAT("elf32-sh64", "elf32-sh64", "elf32-sh64") +#endif +#endif + +OUTPUT_ARCH(sh:sh5) + +#define C_PHYS(x) AT (ADDR(x) - LOAD_OFFSET) + +ENTRY(__start) +SECTIONS +{ + . = CONFIG_CACHED_MEMORY_OFFSET + CONFIG_MEMORY_START + PAGE_SIZE; + _text = .; /* Text and read-only data */ + text = .; /* Text and read-only data */ + + .empty_zero_page : C_PHYS(.empty_zero_page) { + *(.empty_zero_page) + } = 0 + + .text : C_PHYS(.text) { + *(.text) + *(.text64) + *(.text..SHmedia32) + SCHED_TEXT + *(.fixup) + *(.gnu.warning) +#ifdef CONFIG_LITTLE_ENDIAN + } = 0x6ff0fff0 +#else + } = 0xf0fff06f +#endif + + /* We likely want __ex_table to be Cache Line aligned */ + . = ALIGN(L1_CACHE_BYTES); /* Exception table */ + __start___ex_table = .; + __ex_table : C_PHYS(__ex_table) { *(__ex_table) } + __stop___ex_table = .; + + RODATA + + _etext = .; /* End of text section */ + + .data : C_PHYS(.data) { /* Data */ + *(.data) + CONSTRUCTORS + } + + . = ALIGN(PAGE_SIZE); + .data.page_aligned : C_PHYS(.data.page_aligned) { *(.data.page_aligned) } + + . = ALIGN(L1_CACHE_BYTES); + __per_cpu_start = .; + .data.percpu : C_PHYS(.data.percpu) { *(.data.percpu) } + __per_cpu_end = . ; + .data.cacheline_aligned : C_PHYS(.data.cacheline_aligned) { *(.data.cacheline_aligned) } + + _edata = .; /* End of data section */ + + . = ALIGN(THREAD_SIZE); /* init_task: structure size aligned */ + .data.init_task : C_PHYS(.data.init_task) { *(.data.init_task) } + + . = ALIGN(PAGE_SIZE); /* Init code and data */ + __init_begin = .; + _sinittext = .; + .init.text : C_PHYS(.init.text) { *(.init.text) } + _einittext = .; + .init.data : C_PHYS(.init.data) { *(.init.data) } + . = ALIGN(L1_CACHE_BYTES); /* Better if Cache Line aligned */ + __setup_start = .; + .init.setup : C_PHYS(.init.setup) { *(.init.setup) } + __setup_end = .; + __start___param = .; + __param : C_PHYS(__param) { *(__param) } + __stop___param = .; + __initcall_start = .; + .initcall.init : C_PHYS(.initcall.init) { + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + } + __initcall_end = .; + __con_initcall_start = .; + .con_initcall.init : C_PHYS(.con_initcall.init) { *(.con_initcall.init) } + __con_initcall_end = .; + SECURITY_INIT + __initramfs_start = .; + .init.ramfs : C_PHYS(.init.ramfs) { *(.init.ramfs) } + __initramfs_end = .; + . = ALIGN(PAGE_SIZE); + __init_end = .; + + /* Align to the biggest single data representation, head and tail */ + . = ALIGN(8); + __bss_start = .; /* BSS */ + .bss : C_PHYS(.bss) { + *(.bss) + } + . = ALIGN(8); + _end = . ; + + /* Sections to be discarded */ + /DISCARD/ : { + *(.exit.text) + *(.exit.data) + *(.exitcall.exit) + } + + /* Stabs debugging sections. */ + .stab 0 : C_PHYS(.stab) { *(.stab) } + .stabstr 0 : C_PHYS(.stabstr) { *(.stabstr) } + .stab.excl 0 : C_PHYS(.stab.excl) { *(.stab.excl) } + .stab.exclstr 0 : C_PHYS(.stab.exclstr) { *(.stab.exclstr) } + .stab.index 0 : C_PHYS(.stab.index) { *(.stab.index) } + .stab.indexstr 0 : C_PHYS(.stab.indexstr) { *(.stab.indexstr) } + .comment 0 : C_PHYS(.comment) { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging section are relative to the beginning + of the section so we begin .debug at 0. */ + /* DWARF 1 */ + .debug 0 : C_PHYS(.debug) { *(.debug) } + .line 0 : C_PHYS(.line) { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : C_PHYS(.debug_srcinfo) { *(.debug_srcinfo) } + .debug_sfnames 0 : C_PHYS(.debug_sfnames) { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : C_PHYS(.debug_aranges) { *(.debug_aranges) } + .debug_pubnames 0 : C_PHYS(.debug_pubnames) { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : C_PHYS(.debug_info) { *(.debug_info) } + .debug_abbrev 0 : C_PHYS(.debug_abbrev) { *(.debug_abbrev) } + .debug_line 0 : C_PHYS(.debug_line) { *(.debug_line) } + .debug_frame 0 : C_PHYS(.debug_frame) { *(.debug_frame) } + .debug_str 0 : C_PHYS(.debug_str) { *(.debug_str) } + .debug_loc 0 : C_PHYS(.debug_loc) { *(.debug_loc) } + .debug_macinfo 0 : C_PHYS(.debug_macinfo) { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : C_PHYS(.debug_weaknames) { *(.debug_weaknames) } + .debug_funcnames 0 : C_PHYS(.debug_funcnames) { *(.debug_funcnames) } + .debug_typenames 0 : C_PHYS(.debug_typenames) { *(.debug_typenames) } + .debug_varnames 0 : C_PHYS(.debug_varnames) { *(.debug_varnames) } + /* These must appear regardless of . */ +} diff -puN /dev/null arch/sh64/lib/c-checksum.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/lib/c-checksum.c 2004-06-28 13:30:30.693137776 -0700 @@ -0,0 +1,231 @@ +/* + * arch/sh/lib/csum_parial.c + * + * This file contains network checksum routines that are better done + * in an architecture-specific manner due to speed.. + */ + +#undef DEBUG + +#include +#include +#include +#include +#include +#include + +static inline unsigned short from64to16(unsigned long long x) +{ + /* add up 32-bit words for 33 bits */ + x = (x & 0xffffffff) + (x >> 32); + /* add up 16-bit and 17-bit words for 17+c bits */ + x = (x & 0xffff) + (x >> 16); + /* add up 16-bit and 2-bit for 16+c bit */ + x = (x & 0xffff) + (x >> 16); + /* add up carry.. */ + x = (x & 0xffff) + (x >> 16); + return x; +} + +static inline unsigned short foldto16(unsigned long x) +{ + /* add up 16-bit for 17 bits */ + x = (x & 0xffff) + (x >> 16); + /* add up carry.. */ + x = (x & 0xffff) + (x >> 16); + return x; +} + +static inline unsigned short myfoldto16(unsigned long long x) +{ + /* Fold down to 32-bits so we don't loose in the typedef-less + network stack. */ + /* 64 to 33 */ + x = (x & 0xffffffff) + (x >> 32); + /* 33 to 32 */ + x = (x & 0xffffffff) + (x >> 32); + + /* add up 16-bit for 17 bits */ + x = (x & 0xffff) + (x >> 16); + /* add up carry.. */ + x = (x & 0xffff) + (x >> 16); + return x; +} + +#define odd(x) ((x)&1) +#define U16(x) ntohs(x) + +static unsigned long do_csum(const unsigned char *buff, int len) +{ + int odd, count; + unsigned long result = 0; + + pr_debug("do_csum buff %p, len %d (0x%x)\n", buff, len, len); +#ifdef DEBUG + for (i = 0; i < len; i++) { + if ((i % 26) == 0) + printk("\n"); + printk("%02X ", buff[i]); + } +#endif + + if (len <= 0) + goto out; + + odd = 1 & (unsigned long) buff; + if (odd) { + result = *buff << 8; + len--; + buff++; + } + count = len >> 1; /* nr of 16-bit words.. */ + if (count) { + if (2 & (unsigned long) buff) { + result += *(unsigned short *) buff; + count--; + len -= 2; + buff += 2; + } + count >>= 1; /* nr of 32-bit words.. */ + if (count) { + unsigned long carry = 0; + do { + unsigned long w = *(unsigned long *) buff; + buff += 4; + count--; + result += carry; + result += w; + carry = (w > result); + } while (count); + result += carry; + result = (result & 0xffff) + (result >> 16); + } + if (len & 2) { + result += *(unsigned short *) buff; + buff += 2; + } + } + if (len & 1) + result += *buff; + result = foldto16(result); + if (odd) + result = ((result >> 8) & 0xff) | ((result & 0xff) << 8); + + pr_debug("\nCHECKSUM is 0x%x\n", result); + + out: + return result; +} + +/* computes the checksum of a memory block at buff, length len, + and adds in "sum" (32-bit) */ +unsigned int csum_partial(const unsigned char *buff, int len, unsigned int sum) +{ + unsigned long long result = do_csum(buff, len); + + /* add in old sum, and carry.. */ + result += sum; + /* 32+c bits -> 32 bits */ + result = (result & 0xffffffff) + (result >> 32); + + pr_debug("csum_partial, buff %p len %d sum 0x%x result=0x%016Lx\n", + buff, len, sum, result); + + return result; +} + +/* Copy while checksumming, otherwise like csum_partial. */ +unsigned int +csum_partial_copy(const char *src, char *dst, int len, unsigned int sum) +{ + sum = csum_partial(src, len, sum); + memcpy(dst, src, len); + + return sum; +} + +/* Copy from userspace and compute checksum. If we catch an exception + then zero the rest of the buffer. */ +unsigned int +csum_partial_copy_from_user(const char *src, char *dst, int len, + unsigned int sum, int *err_ptr) +{ + int missing; + + pr_debug + ("csum_partial_copy_from_user src %p, dest %p, len %d, sum %08x, err_ptr %p\n", + src, dst, len, sum, err_ptr); + missing = copy_from_user(dst, src, len); + pr_debug(" access_ok %d\n", __access_ok((unsigned long) src, len)); + pr_debug(" missing %d\n", missing); + if (missing) { + memset(dst + len - missing, 0, missing); + *err_ptr = -EFAULT; + } + + return csum_partial(dst, len, sum); +} + +/* Copy to userspace and compute checksum. */ +unsigned int +csum_partial_copy_to_user(const char *src, char *dst, int len, + unsigned int sum, int *err_ptr) +{ + sum = csum_partial(src, len, sum); + + if (copy_to_user(dst, src, len)) + *err_ptr = -EFAULT; + + return sum; +} + +/* + * This is a version of ip_compute_csum() optimized for IP headers, + * which always checksum on 4 octet boundaries. + */ +unsigned short ip_fast_csum(unsigned char *iph, unsigned int ihl) +{ + pr_debug("ip_fast_csum %p,%d\n", iph, ihl); + + return ~do_csum(iph, ihl * 4); +} + +unsigned int csum_tcpudp_nofold(unsigned long saddr, + unsigned long daddr, + unsigned short len, + unsigned short proto, unsigned int sum) +{ + unsigned long long result; + + pr_debug("ntohs(0x%x)=0x%x\n", 0xdead, ntohs(0xdead)); + pr_debug("htons(0x%x)=0x%x\n", 0xdead, htons(0xdead)); + + result = ((unsigned long long) saddr + + (unsigned long long) daddr + + (unsigned long long) sum + + ((unsigned long long) ntohs(len) << 16) + + ((unsigned long long) proto << 8)); + + /* Fold down to 32-bits so we don't loose in the typedef-less + network stack. */ + /* 64 to 33 */ + result = (result & 0xffffffff) + (result >> 32); + /* 33 to 32 */ + result = (result & 0xffffffff) + (result >> 32); + + pr_debug("%s saddr %x daddr %x len %x proto %x sum %x result %08Lx\n", + __FUNCTION__, saddr, daddr, len, proto, sum, result); + + return result; +} + +// Post SIM: +unsigned int +csum_partial_copy_nocheck(const char *src, char *dst, int len, unsigned int sum) +{ + // unsigned dummy; + pr_debug("csum_partial_copy_nocheck src %p dst %p len %d\n", src, dst, + len); + + return csum_partial_copy(src, dst, len, sum); +} diff -puN /dev/null arch/sh64/lib/copy_user_memcpy.S --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/lib/copy_user_memcpy.S 2004-06-28 13:30:30.694137624 -0700 @@ -0,0 +1,213 @@ +! +! Fast SH memcpy +! +! by Toshiyasu Morita (tm@netcom.com) +! hacked by J"orn Rernnecke (joern.rennecke@superh.com) ("o for o-umlaut) +! SH5 code Copyright 2002 SuperH Ltd. +! +! Entry: ARG0: destination pointer +! ARG1: source pointer +! ARG2: byte count +! +! Exit: RESULT: destination pointer +! any other registers in the range r0-r7: trashed +! +! Notes: Usually one wants to do small reads and write a longword, but +! unfortunately it is difficult in some cases to concatanate bytes +! into a longword on the SH, so this does a longword read and small +! writes. +! +! This implementation makes two assumptions about how it is called: +! +! 1.: If the byte count is nonzero, the address of the last byte to be +! copied is unsigned greater than the address of the first byte to +! be copied. This could be easily swapped for a signed comparison, +! but the algorithm used needs some comparison. +! +! 2.: When there are two or three bytes in the last word of an 11-or-more +! bytes memory chunk to b copied, the rest of the word can be read +! without side effects. +! This could be easily changed by increasing the minumum size of +! a fast memcpy and the amount subtracted from r7 before L_2l_loop be 2, +! however, this would cost a few extra cyles on average. +! For SHmedia, the assumption is that any quadword can be read in its +! enirety if at least one byte is included in the copy. + +/* Imported into Linux kernel by Richard Curnow. This is used to implement the + __copy_user function in the general case, so it has to be a distinct + function from intra-kernel memcpy to allow for exception fix-ups in the + event that the user pointer is bad somewhere in the copy (e.g. due to + running off the end of the vma). + + Note, this algorithm will be slightly wasteful in the case where the source + and destination pointers are equally aligned, because the stlo/sthi pairs + could then be merged back into single stores. If there are a lot of cache + misses, this is probably offset by the stall lengths on the preloads. + +*/ + + .section .text..SHmedia32,"ax" + .little + .balign 32 + .global copy_user_memcpy + .global copy_user_memcpy_end +copy_user_memcpy: + +#define LDUAQ(P,O,D0,D1) ldlo.q P,O,D0; ldhi.q P,O+7,D1 +#define STUAQ(P,O,D0,D1) stlo.q P,O,D0; sthi.q P,O+7,D1 +#define LDUAL(P,O,D0,D1) ldlo.l P,O,D0; ldhi.l P,O+3,D1 +#define STUAL(P,O,D0,D1) stlo.l P,O,D0; sthi.l P,O+3,D1 + + ld.b r3,0,r63 + pta/l Large,tr0 + movi 25,r0 + bgeu/u r4,r0,tr0 + nsb r4,r0 + shlli r0,5,r0 + movi (L1-L0+63*32 + 1) & 0xffff,r1 + sub r1, r0, r0 +L0: ptrel r0,tr0 + add r2,r4,r5 + ptabs r18,tr1 + add r3,r4,r6 + blink tr0,r63 + +/* Rearranged to make cut2 safe */ + .balign 8 +L4_7: /* 4..7 byte memcpy cntd. */ + stlo.l r2, 0, r0 + or r6, r7, r6 + sthi.l r5, -1, r6 + stlo.l r5, -4, r6 + blink tr1,r63 + + .balign 8 +L1: /* 0 byte memcpy */ + nop + blink tr1,r63 + nop + nop + nop + nop + +L2_3: /* 2 or 3 byte memcpy cntd. */ + st.b r5,-1,r6 + blink tr1,r63 + + /* 1 byte memcpy */ + ld.b r3,0,r0 + st.b r2,0,r0 + blink tr1,r63 + +L8_15: /* 8..15 byte memcpy cntd. */ + stlo.q r2, 0, r0 + or r6, r7, r6 + sthi.q r5, -1, r6 + stlo.q r5, -8, r6 + blink tr1,r63 + + /* 2 or 3 byte memcpy */ + ld.b r3,0,r0 + ld.b r2,0,r63 + ld.b r3,1,r1 + st.b r2,0,r0 + pta/l L2_3,tr0 + ld.b r6,-1,r6 + st.b r2,1,r1 + blink tr0, r63 + + /* 4 .. 7 byte memcpy */ + LDUAL (r3, 0, r0, r1) + pta L4_7, tr0 + ldlo.l r6, -4, r7 + or r0, r1, r0 + sthi.l r2, 3, r0 + ldhi.l r6, -1, r6 + blink tr0, r63 + + /* 8 .. 15 byte memcpy */ + LDUAQ (r3, 0, r0, r1) + pta L8_15, tr0 + ldlo.q r6, -8, r7 + or r0, r1, r0 + sthi.q r2, 7, r0 + ldhi.q r6, -1, r6 + blink tr0, r63 + + /* 16 .. 24 byte memcpy */ + LDUAQ (r3, 0, r0, r1) + LDUAQ (r3, 8, r8, r9) + or r0, r1, r0 + sthi.q r2, 7, r0 + or r8, r9, r8 + sthi.q r2, 15, r8 + ldlo.q r6, -8, r7 + ldhi.q r6, -1, r6 + stlo.q r2, 8, r8 + stlo.q r2, 0, r0 + or r6, r7, r6 + sthi.q r5, -1, r6 + stlo.q r5, -8, r6 + blink tr1,r63 + +Large: + ld.b r2, 0, r63 + pta/l Loop_ua, tr1 + ori r3, -8, r7 + sub r2, r7, r22 + sub r3, r2, r6 + add r2, r4, r5 + ldlo.q r3, 0, r0 + addi r5, -16, r5 + movi 64+8, r27 ! could subtract r7 from that. + stlo.q r2, 0, r0 + sthi.q r2, 7, r0 + ldx.q r22, r6, r0 + bgtu/l r27, r4, tr1 + + addi r5, -48, r27 + pta/l Loop_line, tr0 + addi r6, 64, r36 + addi r6, -24, r19 + addi r6, -16, r20 + addi r6, -8, r21 + +Loop_line: + ldx.q r22, r36, r63 + synco + alloco r22, 32 + synco + addi r22, 32, r22 + ldx.q r22, r19, r23 + sthi.q r22, -25, r0 + ldx.q r22, r20, r24 + ldx.q r22, r21, r25 + stlo.q r22, -32, r0 + ldx.q r22, r6, r0 + sthi.q r22, -17, r23 + sthi.q r22, -9, r24 + sthi.q r22, -1, r25 + stlo.q r22, -24, r23 + stlo.q r22, -16, r24 + stlo.q r22, -8, r25 + bgeu r27, r22, tr0 + +Loop_ua: + addi r22, 8, r22 + sthi.q r22, -1, r0 + stlo.q r22, -8, r0 + ldx.q r22, r6, r0 + bgtu/l r5, r22, tr1 + + add r3, r4, r7 + ldlo.q r7, -8, r1 + sthi.q r22, 7, r0 + ldhi.q r7, -1, r7 + ptabs r18,tr1 + stlo.q r22, 0, r0 + or r1, r7, r1 + sthi.q r5, 15, r1 + stlo.q r5, 8, r1 + blink tr1, r63 +copy_user_memcpy_end: + nop diff -puN /dev/null arch/sh64/lib/dbg.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/lib/dbg.c 2004-06-28 13:30:30.696137320 -0700 @@ -0,0 +1,394 @@ +/*-------------------------------------------------------------------------- +-- +-- Identity : Linux50 Debug Funcions +-- +-- File : arch/sh64/lib/dbg.C +-- +-- Copyright 2000, 2001 STMicroelectronics Limited. +-- Copyright 2004 Richard Curnow (evt_debug etc) +-- +--------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include + +typedef u64 regType_t; + +static regType_t getConfigReg(u64 id) +{ + register u64 reg __asm__("r2"); + asm volatile ("getcfg %1, 0, %0":"=r" (reg):"r"(id)); + return (reg); +} + +/* ======================================================================= */ + +static char *szTab[] = { "4k", "64k", "1M", "512M" }; +static char *protTab[] = { "----", + "---R", + "--X-", + "--XR", + "-W--", + "-W-R", + "-WX-", + "-WXR", + "U---", + "U--R", + "U-X-", + "U-XR", + "UW--", + "UW-R", + "UWX-", + "UWXR" +}; +#define ITLB_BASE 0x00000000 +#define DTLB_BASE 0x00800000 +#define MAX_TLBs 64 +/* PTE High */ +#define GET_VALID(pte) ((pte) & 0x1) +#define GET_SHARED(pte) ((pte) & 0x2) +#define GET_ASID(pte) ((pte >> 2) & 0x0ff) +#define GET_EPN(pte) ((pte) & 0xfffff000) + +/* PTE Low */ +#define GET_CBEHAVIOR(pte) ((pte) & 0x3) +#define GET_PAGE_SIZE(pte) szTab[((pte >> 3) & 0x3)] +#define GET_PROTECTION(pte) protTab[((pte >> 6) & 0xf)] +#define GET_PPN(pte) ((pte) & 0xfffff000) + +#define PAGE_1K_MASK 0x00000000 +#define PAGE_4K_MASK 0x00000010 +#define PAGE_64K_MASK 0x00000080 +#define MMU_PAGESIZE_MASK (PAGE_64K_MASK | PAGE_4K_MASK) +#define PAGE_1MB_MASK MMU_PAGESIZE_MASK +#define PAGE_1K (1024) +#define PAGE_4K (1024 * 4) +#define PAGE_64K (1024 * 64) +#define PAGE_1MB (1024 * 1024) + +#define HOW_TO_READ_TLB_CONTENT \ + "[ ID] PPN EPN ASID Share CB P.Size PROT.\n" + +void print_single_tlb(unsigned long tlb, int single_print) +{ + regType_t pteH; + regType_t pteL; + unsigned int valid, shared, asid, epn, cb, ppn; + char *pSize; + char *pProt; + + /* + ** in case of single print is true, this implies: + ** 1) print the TLB in any case also if NOT VALID + ** 2) print out the header + */ + + pteH = getConfigReg(tlb); + valid = GET_VALID(pteH); + if (single_print) + printk(HOW_TO_READ_TLB_CONTENT); + else if (!valid) + return; + + pteL = getConfigReg(tlb + 1); + + shared = GET_SHARED(pteH); + asid = GET_ASID(pteH); + epn = GET_EPN(pteH); + cb = GET_CBEHAVIOR(pteL); + pSize = GET_PAGE_SIZE(pteL); + pProt = GET_PROTECTION(pteL); + ppn = GET_PPN(pteL); + printk("[%c%2ld] 0x%08x 0x%08x %03d %02x %02x %4s %s\n", + ((valid) ? ' ' : 'u'), ((tlb & 0x0ffff) / TLB_STEP), + ppn, epn, asid, shared, cb, pSize, pProt); +} + +void print_dtlb(void) +{ + int count; + unsigned long tlb; + + printk(" ================= SH-5 D-TLBs Status ===================\n"); + printk(HOW_TO_READ_TLB_CONTENT); + tlb = DTLB_BASE; + for (count = 0; count < MAX_TLBs; count++, tlb += TLB_STEP) + print_single_tlb(tlb, 0); + printk + (" =============================================================\n"); +} + +void print_itlb(void) +{ + int count; + unsigned long tlb; + + printk(" ================= SH-5 I-TLBs Status ===================\n"); + printk(HOW_TO_READ_TLB_CONTENT); + tlb = ITLB_BASE; + for (count = 0; count < MAX_TLBs; count++, tlb += TLB_STEP) + print_single_tlb(tlb, 0); + printk + (" =============================================================\n"); +} + +/* ======================================================================= */ + +#include "syscalltab.h" + +struct ring_node { + int evt; + int ret_addr; + int event; + int tra; + int pid; + unsigned long sp; + unsigned long pc; +}; + +static struct ring_node event_ring[16]; +static int event_ptr = 0; + +void evt_debug(int evt, int ret_addr, int event, int tra, struct pt_regs *regs) +{ + int syscallno = tra & 0xff; + unsigned long sp; + unsigned long stack_bottom; + int pid; + struct ring_node *rr; + + pid = current->pid; + stack_bottom = (unsigned long) current->thread_info; + asm volatile("ori r15, 0, %0" : "=r" (sp)); + rr = event_ring + event_ptr; + rr->evt = evt; + rr->ret_addr = ret_addr; + rr->event = event; + rr->tra = tra; + rr->pid = pid; + rr->sp = sp; + rr->pc = regs->pc; + + if (sp < stack_bottom + 3092) { + printk("evt_debug : stack underflow report\n"); + int i, j; + for (j=0, i = event_ptr; j<16; j++) { + rr = event_ring + i; + printk("evt=%08x event=%08x tra=%08x pid=%5d sp=%08lx pc=%08lx\n", + rr->evt, rr->event, rr->tra, rr->pid, rr->sp, rr->pc); + i--; + i &= 15; + } + panic("STACK UNDERFLOW\n"); + } + + event_ptr = (event_ptr + 1) & 15; + + if ((event == 2) && (evt == 0x160)) { + if (syscallno < NUM_SYSCALL_INFO_ENTRIES) + printk("Task %d: %s()\n", + current->pid, + syscall_info_table[syscallno].name); + } +} + +void evt_debug2(unsigned int ret) +{ + printk("Task %d: syscall returns %08x\n", current->pid, ret); +} + +void evt_debug_ret_from_irq(struct pt_regs *regs) +{ + int pid; + struct ring_node *rr; + + pid = current->pid; + rr = event_ring + event_ptr; + rr->evt = 0xffff; + rr->ret_addr = 0; + rr->event = 0; + rr->tra = 0; + rr->pid = pid; + rr->pc = regs->pc; + event_ptr = (event_ptr + 1) & 15; +} + +void evt_debug_ret_from_exc(struct pt_regs *regs) +{ + int pid; + struct ring_node *rr; + + pid = current->pid; + rr = event_ring + event_ptr; + rr->evt = 0xfffe; + rr->ret_addr = 0; + rr->event = 0; + rr->tra = 0; + rr->pid = pid; + rr->pc = regs->pc; + event_ptr = (event_ptr + 1) & 15; +} + +/* ======================================================================= */ + +void show_excp_regs(char *from, int trapnr, int signr, struct pt_regs *regs) +{ + + unsigned long long ah, al, bh, bl, ch, cl; + + printk("\n"); + printk("EXCEPTION - %s: task %d; Linux trap # %d; signal = %d\n", + ((from) ? from : "???"), current->pid, trapnr, signr); + + asm volatile ("getcon " __EXPEVT ", %0":"=r"(ah)); + asm volatile ("getcon " __EXPEVT ", %0":"=r"(al)); + ah = (ah) >> 32; + al = (al) & 0xffffffff; + asm volatile ("getcon " __KCR1 ", %0":"=r"(bh)); + asm volatile ("getcon " __KCR1 ", %0":"=r"(bl)); + bh = (bh) >> 32; + bl = (bl) & 0xffffffff; + asm volatile ("getcon " __INTEVT ", %0":"=r"(ch)); + asm volatile ("getcon " __INTEVT ", %0":"=r"(cl)); + ch = (ch) >> 32; + cl = (cl) & 0xffffffff; + printk("EXPE: %08Lx%08Lx KCR1: %08Lx%08Lx INTE: %08Lx%08Lx\n", + ah, al, bh, bl, ch, cl); + + asm volatile ("getcon " __PEXPEVT ", %0":"=r"(ah)); + asm volatile ("getcon " __PEXPEVT ", %0":"=r"(al)); + ah = (ah) >> 32; + al = (al) & 0xffffffff; + asm volatile ("getcon " __PSPC ", %0":"=r"(bh)); + asm volatile ("getcon " __PSPC ", %0":"=r"(bl)); + bh = (bh) >> 32; + bl = (bl) & 0xffffffff; + asm volatile ("getcon " __PSSR ", %0":"=r"(ch)); + asm volatile ("getcon " __PSSR ", %0":"=r"(cl)); + ch = (ch) >> 32; + cl = (cl) & 0xffffffff; + printk("PEXP: %08Lx%08Lx PSPC: %08Lx%08Lx PSSR: %08Lx%08Lx\n", + ah, al, bh, bl, ch, cl); + + ah = (regs->pc) >> 32; + al = (regs->pc) & 0xffffffff; + bh = (regs->regs[18]) >> 32; + bl = (regs->regs[18]) & 0xffffffff; + ch = (regs->regs[15]) >> 32; + cl = (regs->regs[15]) & 0xffffffff; + printk("PC : %08Lx%08Lx LINK: %08Lx%08Lx SP : %08Lx%08Lx\n", + ah, al, bh, bl, ch, cl); + + ah = (regs->sr) >> 32; + al = (regs->sr) & 0xffffffff; + asm volatile ("getcon " __TEA ", %0":"=r"(bh)); + asm volatile ("getcon " __TEA ", %0":"=r"(bl)); + bh = (bh) >> 32; + bl = (bl) & 0xffffffff; + asm volatile ("getcon " __KCR0 ", %0":"=r"(ch)); + asm volatile ("getcon " __KCR0 ", %0":"=r"(cl)); + ch = (ch) >> 32; + cl = (cl) & 0xffffffff; + printk("SR : %08Lx%08Lx TEA : %08Lx%08Lx KCR0: %08Lx%08Lx\n", + ah, al, bh, bl, ch, cl); + + ah = (regs->regs[0]) >> 32; + al = (regs->regs[0]) & 0xffffffff; + bh = (regs->regs[1]) >> 32; + bl = (regs->regs[1]) & 0xffffffff; + ch = (regs->regs[2]) >> 32; + cl = (regs->regs[2]) & 0xffffffff; + printk("R0 : %08Lx%08Lx R1 : %08Lx%08Lx R2 : %08Lx%08Lx\n", + ah, al, bh, bl, ch, cl); + + ah = (regs->regs[3]) >> 32; + al = (regs->regs[3]) & 0xffffffff; + bh = (regs->regs[4]) >> 32; + bl = (regs->regs[4]) & 0xffffffff; + ch = (regs->regs[5]) >> 32; + cl = (regs->regs[5]) & 0xffffffff; + printk("R3 : %08Lx%08Lx R4 : %08Lx%08Lx R5 : %08Lx%08Lx\n", + ah, al, bh, bl, ch, cl); + + ah = (regs->regs[6]) >> 32; + al = (regs->regs[6]) & 0xffffffff; + bh = (regs->regs[7]) >> 32; + bl = (regs->regs[7]) & 0xffffffff; + ch = (regs->regs[8]) >> 32; + cl = (regs->regs[8]) & 0xffffffff; + printk("R6 : %08Lx%08Lx R7 : %08Lx%08Lx R8 : %08Lx%08Lx\n", + ah, al, bh, bl, ch, cl); + + ah = (regs->regs[9]) >> 32; + al = (regs->regs[9]) & 0xffffffff; + bh = (regs->regs[10]) >> 32; + bl = (regs->regs[10]) & 0xffffffff; + ch = (regs->regs[11]) >> 32; + cl = (regs->regs[11]) & 0xffffffff; + printk("R9 : %08Lx%08Lx R10 : %08Lx%08Lx R11 : %08Lx%08Lx\n", + ah, al, bh, bl, ch, cl); + printk("....\n"); + + ah = (regs->tregs[0]) >> 32; + al = (regs->tregs[0]) & 0xffffffff; + bh = (regs->tregs[1]) >> 32; + bl = (regs->tregs[1]) & 0xffffffff; + ch = (regs->tregs[2]) >> 32; + cl = (regs->tregs[2]) & 0xffffffff; + printk("T0 : %08Lx%08Lx T1 : %08Lx%08Lx T2 : %08Lx%08Lx\n", + ah, al, bh, bl, ch, cl); + printk("....\n"); + + print_dtlb(); + print_itlb(); +} + +/* ======================================================================= */ + +/* +** Depending on scan the MMU, Data or Instrction side +** looking for a valid mapping matching Eaddr & asid. +** Return -1 if not found or the TLB id entry otherwise. +** Note: it works only for 4k pages! +*/ +static unsigned long +lookup_mmu_side(unsigned long base, unsigned long Eaddr, unsigned long asid) +{ + regType_t pteH; + unsigned long epn; + int count; + + epn = Eaddr & 0xfffff000; + + for (count = 0; count < MAX_TLBs; count++, base += TLB_STEP) { + pteH = getConfigReg(base); + if (GET_VALID(pteH)) + if ((unsigned long) GET_EPN(pteH) == epn) + if ((unsigned long) GET_ASID(pteH) == asid) + break; + } + return ((unsigned long) ((count < MAX_TLBs) ? base : -1)); +} + +unsigned long lookup_dtlb(unsigned long Eaddr) +{ + unsigned long asid = get_asid(); + return (lookup_mmu_side((u64) DTLB_BASE, Eaddr, asid)); +} + +unsigned long lookup_itlb(unsigned long Eaddr) +{ + unsigned long asid = get_asid(); + return (lookup_mmu_side((u64) ITLB_BASE, Eaddr, asid)); +} + +void print_page(struct page *page) +{ + printk(" page[%p] -> index 0x%lx, count 0x%x, flags 0x%lx\n", + page, page->index, page_count(page), page->flags); + printk(" address_space = %p, pages =%ld\n", page->mapping, + page->mapping->nrpages); + +} diff -puN /dev/null arch/sh64/lib/io.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/lib/io.c 2004-06-28 13:30:30.697137168 -0700 @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2000 David J. Mckay (david.mckay@st.com) + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * This file contains the I/O routines for use on the overdrive board + * + */ + +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_SH_CAYMAN +#include +#endif + +/* + * readX/writeX() are used to access memory mapped devices. On some + * architectures the memory mapped IO stuff needs to be accessed + * differently. On the SuperH architecture, we just read/write the + * memory location directly. + */ + +#define dprintk(x...) + +static int io_addr(int x) { + if (x < 0x400) { +#ifdef CONFIG_SH_CAYMAN + return (x << 2) | smsc_superio_virt; +#else + panic ("Illegal access to I/O port 0x%04x\n", x); + return 0; +#endif + } else { +#ifdef CONFIG_PCI + return (x + pciio_virt); +#else + panic ("Illegal access to I/O port 0x%04x\n", x); + return 0; +#endif + } +} + +unsigned long inb(unsigned long port) +{ + unsigned long r; + + r = ctrl_inb(io_addr(port)); + dprintk("inb(0x%x)=0x%x (0x%x)\n", port, r, io_addr(port)); + return r; +} + +unsigned long inw(unsigned long port) +{ + unsigned long r; + + r = ctrl_inw(io_addr(port)); + dprintk("inw(0x%x)=0x%x (0x%x)\n", port, r, io_addr(port)); + return r; +} + +unsigned long inl(unsigned long port) +{ + unsigned long r; + + r = ctrl_inl(io_addr(port)); + dprintk("inl(0x%x)=0x%x (0x%x)\n", port, r, io_addr(port)); + return r; +} + +void outb(unsigned long value, unsigned long port) +{ + dprintk("outb(0x%x,0x%x) (0x%x)\n", value, port, io_addr(port)); + ctrl_outb(value, io_addr(port)); +} + +void outw(unsigned long value, unsigned long port) +{ + dprintk("outw(0x%x,0x%x) (0x%x)\n", value, port, io_addr(port)); + ctrl_outw(value, io_addr(port)); +} + +void outl(unsigned long value, unsigned long port) +{ + dprintk("outw(0x%x,0x%x) (0x%x)\n", value, port, io_addr(port)); + ctrl_outl(value, io_addr(port)); +} + +/* This is horrible at the moment - needs more work to do something sensible */ +#define IO_DELAY() + +#define OUT_DELAY(x,type) \ +void out##x##_p(unsigned type value,unsigned long port){out##x(value,port);IO_DELAY();} + +#define IN_DELAY(x,type) \ +unsigned type in##x##_p(unsigned long port) {unsigned type tmp=in##x(port);IO_DELAY();return tmp;} + +#if 1 +OUT_DELAY(b, long) OUT_DELAY(w, long) OUT_DELAY(l, long) + IN_DELAY(b, long) IN_DELAY(w, long) IN_DELAY(l, long) +#endif +/* Now for the string version of these functions */ +void outsb(unsigned long port, const void *addr, unsigned long count) +{ + int i; + unsigned char *p = (unsigned char *) addr; + + for (i = 0; i < count; i++, p++) { + outb(*p, port); + } +} + +void insb(unsigned long port, void *addr, unsigned long count) +{ + int i; + unsigned char *p = (unsigned char *) addr; + + for (i = 0; i < count; i++, p++) { + *p = inb(port); + } +} + +/* For the 16 and 32 bit string functions, we have to worry about alignment. + * The SH does not do unaligned accesses, so we have to read as bytes and + * then write as a word or dword. + * This can be optimised a lot more, especially in the case where the data + * is aligned + */ + +void outsw(unsigned long port, const void *addr, unsigned long count) +{ + int i; + unsigned short tmp; + unsigned char *p = (unsigned char *) addr; + + for (i = 0; i < count; i++, p += 2) { + tmp = (*p) | ((*(p + 1)) << 8); + outw(tmp, port); + } +} + +void insw(unsigned long port, void *addr, unsigned long count) +{ + int i; + unsigned short tmp; + unsigned char *p = (unsigned char *) addr; + + for (i = 0; i < count; i++, p += 2) { + tmp = inw(port); + p[0] = tmp & 0xff; + p[1] = (tmp >> 8) & 0xff; + } +} + +void outsl(unsigned long port, const void *addr, unsigned long count) +{ + int i; + unsigned tmp; + unsigned char *p = (unsigned char *) addr; + + for (i = 0; i < count; i++, p += 4) { + tmp = (*p) | ((*(p + 1)) << 8) | ((*(p + 2)) << 16) | + ((*(p + 3)) << 24); + outl(tmp, port); + } +} + +void insl(unsigned long port, void *addr, unsigned long count) +{ + int i; + unsigned tmp; + unsigned char *p = (unsigned char *) addr; + + for (i = 0; i < count; i++, p += 4) { + tmp = inl(port); + p[0] = tmp & 0xff; + p[1] = (tmp >> 8) & 0xff; + p[2] = (tmp >> 16) & 0xff; + p[3] = (tmp >> 24) & 0xff; + + } +} + +void memcpy_toio(unsigned long to, const void *from, long count) +{ + unsigned char *p = (unsigned char *) from; + + while (count) { + count--; + writeb(*p++, to++); + } +} + +void memcpy_fromio(void *to, unsigned long from, long count) +{ + int i; + unsigned char *p = (unsigned char *) to; + + for (i = 0; i < count; i++) { + p[i] = readb(from); + from++; + } +} diff -puN /dev/null arch/sh64/lib/Makefile --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/lib/Makefile 2004-06-28 13:30:30.697137168 -0700 @@ -0,0 +1,19 @@ +# +# 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) 2000, 2001 Paolo Alberelli +# Coprygith (C) 2003 Paul Mundt +# +# Makefile for the SH-5 specific library files.. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +# Panic should really be compiled as PIC +lib-y := udelay.o c-checksum.o dbg.o io.o panic.o memcpy.o copy_user_memcpy.o \ + page_copy.o page_clear.o + diff -puN /dev/null arch/sh64/lib/memcpy.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/lib/memcpy.c 2004-06-28 13:30:30.698137016 -0700 @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2002 Mark Debbage (Mark.Debbage@superh.com) + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + */ + +#include +#include +#include + +// This is a simplistic optimization of memcpy to increase the +// granularity of access beyond one byte using aligned +// loads and stores. This is not an optimal implementation +// for SH-5 (especially with regard to prefetching and the cache), +// and a better version should be provided later ... + +void *memcpy(void *dest, const void *src, size_t count) +{ + char *d = (char *) dest, *s = (char *) src; + + if (count >= 32) { + int i = 8 - (((unsigned long) d) & 0x7); + + if (i != 8) + while (i-- && count--) { + *d++ = *s++; + } + + if (((((unsigned long) d) & 0x7) == 0) && + ((((unsigned long) s) & 0x7) == 0)) { + while (count >= 32) { + unsigned long long t1, t2, t3, t4; + t1 = *(unsigned long long *) (s); + t2 = *(unsigned long long *) (s + 8); + t3 = *(unsigned long long *) (s + 16); + t4 = *(unsigned long long *) (s + 24); + *(unsigned long long *) (d) = t1; + *(unsigned long long *) (d + 8) = t2; + *(unsigned long long *) (d + 16) = t3; + *(unsigned long long *) (d + 24) = t4; + d += 32; + s += 32; + count -= 32; + } + while (count >= 8) { + *(unsigned long long *) d = + *(unsigned long long *) s; + d += 8; + s += 8; + count -= 8; + } + } + + if (((((unsigned long) d) & 0x3) == 0) && + ((((unsigned long) s) & 0x3) == 0)) { + while (count >= 4) { + *(unsigned long *) d = *(unsigned long *) s; + d += 4; + s += 4; + count -= 4; + } + } + + if (((((unsigned long) d) & 0x1) == 0) && + ((((unsigned long) s) & 0x1) == 0)) { + while (count >= 2) { + *(unsigned short *) d = *(unsigned short *) s; + d += 2; + s += 2; + count -= 2; + } + } + } + + while (count--) { + *d++ = *s++; + } + + return d; +} diff -puN /dev/null arch/sh64/lib/old-checksum.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/lib/old-checksum.c 2004-06-28 13:30:30.698137016 -0700 @@ -0,0 +1,17 @@ +/* + * FIXME: old compatibility stuff, will be removed soon. + */ + +#include + +unsigned int csum_partial_copy( const char *src, char *dst, int len, int sum) +{ + int src_err=0, dst_err=0; + + sum = csum_partial_copy_generic ( src, dst, len, sum, &src_err, &dst_err); + + if (src_err || dst_err) + printk("old csum_partial_copy_fromuser(), tell mingo to convert me.\n"); + + return sum; +} diff -puN /dev/null arch/sh64/lib/page_clear.S --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/lib/page_clear.S 2004-06-28 13:30:30.699136864 -0700 @@ -0,0 +1,51 @@ +/* + Copyright 2003 Richard Curnow, SuperH (UK) Ltd. + + 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. + + Tight version of memset for the case of just clearing a page. It turns out + that having the alloco's spaced out slightly due to the increment/branch + pair causes them to contend less for access to the cache. Similarly, + keeping the stores apart from the allocos causes less contention. => Do two + separate loops. Do multiple stores per loop to amortise the + increment/branch cost a little. + + Parameters: + r2 : source effective address (start of page) + + Always clears 4096 bytes. + +*/ + + .section .text..SHmedia32,"ax" + .little + + .balign 8 + .global sh64_page_clear +sh64_page_clear: + pta/l 1f, tr1 + pta/l 2f, tr2 + ptabs/l r18, tr0 + + movi 4096, r7 + add r2, r7, r7 + add r2, r63, r6 +1: + alloco r6, 0 + addi r6, 32, r6 + bgt/l r7, r6, tr1 + + add r2, r63, r6 +2: + st.q r6, 0, r63 + st.q r6, 8, r63 + st.q r6, 16, r63 + st.q r6, 24, r63 + addi r6, 32, r6 + bgt/l r7, r6, tr2 + + blink tr0, r63 + + diff -puN /dev/null arch/sh64/lib/page_copy.S --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/lib/page_copy.S 2004-06-28 13:30:30.699136864 -0700 @@ -0,0 +1,82 @@ +/* + Copyright 2003 Richard Curnow, SuperH (UK) Ltd. + + 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. + + Tight version of mempy for the case of just copying a page. + Prefetch strategy empirically optimised against RTL simulations + of SH5-101 cut2 eval chip with Cayman board DDR memory. + + Parameters: + r2 : source effective address (start of page) + r3 : destination effective address (start of page) + + Always copies 4096 bytes. + + Points to review. + * Currently the prefetch is 4 lines ahead and the alloco is 2 lines ahead. + It seems like the prefetch needs to be at at least 4 lines ahead to get + the data into the cache in time, and the allocos contend with outstanding + prefetches for the same cache set, so it's better to have the numbers + different. + */ + + .section .text..SHmedia32,"ax" + .little + + .balign 8 + .global sh64_page_copy +sh64_page_copy: + + /* Copy 4096 bytes worth of data from r2 to r3. + Do prefetches 4 lines ahead. + Do alloco 2 lines ahead */ + + pta 1f, tr1 + pta 2f, tr2 + pta 3f, tr3 + ptabs r18, tr0 + + ld.q r2, 0x00, r63 + ld.q r2, 0x20, r63 + ld.q r2, 0x40, r63 + ld.q r2, 0x60, r63 + alloco r3, 0x00 + alloco r3, 0x20 + + movi 3968, r6 + add r3, r6, r6 + addi r6, 64, r7 + addi r7, 64, r8 + sub r2, r3, r60 + addi r60, 8, r61 + addi r61, 8, r62 + addi r62, 8, r23 + addi r60, 0x80, r22 + +/* Minimal code size. The extra branches inside the loop don't cost much + because they overlap with the time spent waiting for prefetches to + complete. */ +1: + bge/u r3, r6, tr2 ! skip prefetch for last 4 lines + ldx.q r3, r22, r63 ! prefetch 4 lines hence +2: + bge/u r3, r7, tr3 ! skip alloco for last 2 lines + alloco r3, 0x40 ! alloc destination line 2 lines ahead +3: + ldx.q r3, r60, r36 + ldx.q r3, r61, r37 + ldx.q r3, r62, r38 + ldx.q r3, r23, r39 + st.q r3, 0, r36 + st.q r3, 8, r37 + st.q r3, 16, r38 + st.q r3, 24, r39 + addi r3, 32, r3 + bgt/l r8, r3, tr1 + + blink tr0, r63 ! return + + diff -puN /dev/null arch/sh64/lib/panic.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/lib/panic.c 2004-06-28 13:30:30.700136712 -0700 @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2003 Richard Curnow, SuperH UK Limited + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include +#include +#include + +/* THIS IS A PHYSICAL ADDRESS */ +#define HDSP2534_ADDR (0x04002100) + +#ifdef CONFIG_SH_CAYMAN + +static void poor_mans_delay(void) +{ + int i; + for (i = 0; i < 2500000; i++) { + } /* poor man's delay */ +} + +static void show_value(unsigned long x) +{ + int i; + unsigned nibble; + for (i = 0; i < 8; i++) { + nibble = ((x >> (i * 4)) & 0xf); + + ctrl_outb(nibble + ((nibble > 9) ? 55 : 48), + HDSP2534_ADDR + 0xe0 + ((7 - i) << 2)); + } +} + +#endif + +void +panic_handler(unsigned long panicPC, unsigned long panicSSR, + unsigned long panicEXPEVT) +{ +#ifdef CONFIG_SH_CAYMAN + while (1) { + /* This piece of code displays the PC on the LED display */ + show_value(panicPC); + poor_mans_delay(); + show_value(panicSSR); + poor_mans_delay(); + show_value(panicEXPEVT); + poor_mans_delay(); + } +#endif + + /* Never return from the panic handler */ + for (;;) ; + +} diff -puN /dev/null arch/sh64/lib/udelay.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/lib/udelay.c 2004-06-28 13:30:30.700136712 -0700 @@ -0,0 +1,60 @@ +/* + * arch/sh64/lib/udelay.c + * + * Delay routines, using a pre-computed "loops_per_jiffy" value. + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003, 2004 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include + +extern unsigned long loops_per_jiffy; + +/* + * Use only for very small delays (< 1 msec). + * + * The active part of our cycle counter is only 32-bits wide, and + * we're treating the difference between two marks as signed. On + * a 1GHz box, that's about 2 seconds. + */ + +void __delay(int loops) +{ + long long dummy; + __asm__ __volatile__("gettr tr0, %1\n\t" + "pta $+4, tr0\n\t" + "addi %0, -1, %0\n\t" + "bne %0, r63, tr0\n\t" + "ptabs %1, tr0\n\t":"=r"(loops), + "=r"(dummy) + :"0"(loops)); +} + +void __udelay(unsigned long long usecs, unsigned long lpj) +{ + usecs *= (((unsigned long long) HZ << 32) / 1000000) * lpj; + __delay((long long) usecs >> 32); +} + +void __ndelay(unsigned long long nsecs, unsigned long lpj) +{ + nsecs *= (((unsigned long long) HZ << 32) / 1000000000) * lpj; + __delay((long long) nsecs >> 32); +} + +void udelay(unsigned long usecs) +{ + __udelay(usecs, loops_per_jiffy); +} + +void ndelay(unsigned long nsecs) +{ + __ndelay(nsecs, loops_per_jiffy); +} + diff -puN /dev/null arch/sh64/mach-cayman/irq.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/mach-cayman/irq.c 2004-06-28 13:30:30.701136560 -0700 @@ -0,0 +1,196 @@ +/* + * 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. + * + * arch/sh64/kernel/irq_cayman.c + * + * SH-5 Cayman Interrupt Support + * + * This file handles the board specific parts of the Cayman interrupt system + * + * Copyright (C) 2002 Stuart Menefy + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +unsigned long epld_virt; + +#define EPLD_BASE 0x04002000 +#define EPLD_STATUS_BASE (epld_virt + 0x10) +#define EPLD_MASK_BASE (epld_virt + 0x20) + +/* Note the SMSC SuperIO chip and SMSC LAN chip interrupts are all muxed onto + the same SH-5 interrupt */ + +static irqreturn_t cayman_interrupt_smsc(int irq, void *dev_id, struct pt_regs *regs) +{ + printk(KERN_INFO "CAYMAN: spurious SMSC interrupt\n"); + return IRQ_NONE; +} + +static irqreturn_t cayman_interrupt_pci2(int irq, void *dev_id, struct pt_regs *regs) +{ + printk(KERN_INFO "CAYMAN: spurious PCI interrupt, IRQ %d\n", irq); + return IRQ_NONE; +} + +static struct irqaction cayman_action_smsc = { + .name = "Cayman SMSC Mux", + .handler = cayman_interrupt_smsc, + .flags = SA_INTERRUPT, +}; + +static struct irqaction cayman_action_pci2 = { + .name = "Cayman PCI2 Mux", + .handler = cayman_interrupt_pci2, + .flags = SA_INTERRUPT, +}; + +static void enable_cayman_irq(unsigned int irq) +{ + unsigned long flags; + unsigned long mask; + unsigned int reg; + unsigned char bit; + + irq -= START_EXT_IRQS; + reg = EPLD_MASK_BASE + ((irq / 8) << 2); + bit = 1<<(irq % 8); + save_and_cli(flags); + mask = ctrl_inl(reg); + mask |= bit; + ctrl_outl(mask, reg); + restore_flags(flags); +} + +void disable_cayman_irq(unsigned int irq) +{ + unsigned long flags; + unsigned long mask; + unsigned int reg; + unsigned char bit; + + irq -= START_EXT_IRQS; + reg = EPLD_MASK_BASE + ((irq / 8) << 2); + bit = 1<<(irq % 8); + save_and_cli(flags); + mask = ctrl_inl(reg); + mask &= ~bit; + ctrl_outl(mask, reg); + restore_flags(flags); +} + +static void ack_cayman_irq(unsigned int irq) +{ + disable_cayman_irq(irq); +} + +static void end_cayman_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + enable_cayman_irq(irq); +} + +static unsigned int startup_cayman_irq(unsigned int irq) +{ + enable_cayman_irq(irq); + return 0; /* never anything pending */ +} + +static void shutdown_cayman_irq(unsigned int irq) +{ + disable_cayman_irq(irq); +} + +struct hw_interrupt_type cayman_irq_type = { + .typename = "Cayman-IRQ", + .startup = startup_cayman_irq, + .shutdown = shutdown_cayman_irq, + .enable = enable_cayman_irq, + .disable = disable_cayman_irq, + .ack = ack_cayman_irq, + .end = end_cayman_irq, +}; + +int cayman_irq_demux(int evt) +{ + int irq = intc_evt_to_irq[evt]; + + if (irq == SMSC_IRQ) { + unsigned long status; + int i; + + status = ctrl_inl(EPLD_STATUS_BASE) & + ctrl_inl(EPLD_MASK_BASE) & 0xff; + if (status == 0) { + irq = -1; + } else { + for (i=0; i<8; i++) { + if (status & (1<= NR_INTC_IRQS + 24) && (irq < NR_INTC_IRQS + 32)) { + return sprintf(p, "(PCI2 %d)", irq - (NR_INTC_IRQS + 24)); + } + + return 0; +} +#endif + +void init_cayman_irq(void) +{ + int i; + + epld_virt = onchip_remap(EPLD_BASE, 1024, "EPLD"); + if (!epld_virt) { + printk(KERN_ERR "Cayman IRQ: Unable to remap EPLD\n"); + return; + } + + for (i=0; i + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * Flash the LEDs + */ +#include + +/* +** It is supposed these functions to be used for a low level +** debugging (via Cayman LEDs), hence to be available as soon +** as possible. +** Unfortunately Cayman LEDs relies on Cayman EPLD to be mapped +** (this happen when IRQ are initialized... quite late). +** These triky dependencies should be removed. Temporary, it +** may be enough to NOP until EPLD is mapped. +*/ + +extern unsigned long epld_virt; + +#define LED_ADDR (epld_virt + 0x008) +#define HDSP2534_ADDR (epld_virt + 0x100) + +void mach_led(int position, int value) +{ + if (!epld_virt) + return; + + if (value) + ctrl_outl(0, LED_ADDR); + else + ctrl_outl(1, LED_ADDR); + +} + +void mach_alphanum(int position, unsigned char value) +{ + if (!epld_virt) + return; + + ctrl_outb(value, HDSP2534_ADDR + 0xe0 + (position << 2)); +} + +void mach_alphanum_brightness(int setting) +{ + ctrl_outb(setting & 7, HDSP2534_ADDR + 0xc0); +} diff -puN /dev/null arch/sh64/mach-cayman/Makefile --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/mach-cayman/Makefile 2004-06-28 13:30:30.702136408 -0700 @@ -0,0 +1,11 @@ +# +# Makefile for the Hitachi Cayman specific parts of the kernel +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +obj-y := setup.o irq.o +obj-$(CONFIG_HEARTBEAT) += led.o + diff -puN /dev/null arch/sh64/mach-cayman/setup.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/mach-cayman/setup.c 2004-06-28 13:30:30.703136256 -0700 @@ -0,0 +1,209 @@ +/* + * 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. + * + * arch/sh64/mach-cayman/setup.c + * + * SH5 Cayman support + * + * This file handles the architecture-dependent parts of initialization + * + * Copyright David J. Mckay. + * Needs major work! + * + * benedict.gaster@superh.com: 3rd May 2002 + * Added support for ramdisk, removing statically linked romfs at the same time. + * + * lethal@linux-sh.org: 15th May 2003 + * Use the generic procfs cpuinfo interface, just return a valid board name. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RES_COUNT(res) ((sizeof((res))/sizeof(struct resource))) + +/* + * Platform Dependent Interrupt Priorities. + */ + +/* Using defaults defined in irq.h */ +#define RES NO_PRIORITY /* Disabled */ +#define IR0 IRL0_PRIORITY /* IRLs */ +#define IR1 IRL1_PRIORITY +#define IR2 IRL2_PRIORITY +#define IR3 IRL3_PRIORITY +#define PCA INTA_PRIORITY /* PCI Ints */ +#define PCB INTB_PRIORITY +#define PCC INTC_PRIORITY +#define PCD INTD_PRIORITY +#define SER TOP_PRIORITY +#define ERR TOP_PRIORITY +#define PW0 TOP_PRIORITY +#define PW1 TOP_PRIORITY +#define PW2 TOP_PRIORITY +#define PW3 TOP_PRIORITY +#define DM0 NO_PRIORITY /* DMA Ints */ +#define DM1 NO_PRIORITY +#define DM2 NO_PRIORITY +#define DM3 NO_PRIORITY +#define DAE NO_PRIORITY +#define TU0 TIMER_PRIORITY /* TMU Ints */ +#define TU1 NO_PRIORITY +#define TU2 NO_PRIORITY +#define TI2 NO_PRIORITY +#define ATI NO_PRIORITY /* RTC Ints */ +#define PRI NO_PRIORITY +#define CUI RTC_PRIORITY +#define ERI SCIF_PRIORITY /* SCIF Ints */ +#define RXI SCIF_PRIORITY +#define BRI SCIF_PRIORITY +#define TXI SCIF_PRIORITY +#define ITI TOP_PRIORITY /* WDT Ints */ + +/* Setup for the SMSC FDC37C935 */ +#define SMSC_SUPERIO_BASE 0x04000000 +#define SMSC_CONFIG_PORT_ADDR 0x3f0 +#define SMSC_INDEX_PORT_ADDR SMSC_CONFIG_PORT_ADDR +#define SMSC_DATA_PORT_ADDR 0x3f1 + +#define SMSC_ENTER_CONFIG_KEY 0x55 +#define SMSC_EXIT_CONFIG_KEY 0xaa + +#define SMCS_LOGICAL_DEV_INDEX 0x07 +#define SMSC_DEVICE_ID_INDEX 0x20 +#define SMSC_DEVICE_REV_INDEX 0x21 +#define SMSC_ACTIVATE_INDEX 0x30 +#define SMSC_PRIMARY_INT_INDEX 0x70 +#define SMSC_SECONDARY_INT_INDEX 0x72 + +#define SMSC_KEYBOARD_DEVICE 7 + +#define SMSC_SUPERIO_READ_INDEXED(index) ({ \ + outb((index), SMSC_INDEX_PORT_ADDR); \ + inb(SMSC_DATA_PORT_ADDR); }) +#define SMSC_SUPERIO_WRITE_INDEXED(val, index) ({ \ + outb((index), SMSC_INDEX_PORT_ADDR); \ + outb((val), SMSC_DATA_PORT_ADDR); }) + +unsigned long smsc_superio_virt; + +/* + * Platform dependent structures: maps and parms block. + */ +struct resource io_resources[] = { + /* To be updated with external devices */ +}; + +struct resource kram_resources[] = { + { "Kernel code", 0, 0 }, /* These must be last in the array */ + { "Kernel data", 0, 0 } /* These must be last in the array */ +}; + +struct resource xram_resources[] = { + /* To be updated with external devices */ +}; + +struct resource rom_resources[] = { + /* To be updated with external devices */ +}; + +struct sh64_platform platform_parms = { + .readonly_rootfs = 1, + .initial_root_dev = 0x0100, + .loader_type = 1, + .io_res_p = io_resources, + .io_res_count = RES_COUNT(io_resources), + .kram_res_p = kram_resources, + .kram_res_count = RES_COUNT(kram_resources), + .xram_res_p = xram_resources, + .xram_res_count = RES_COUNT(xram_resources), + .rom_res_p = rom_resources, + .rom_res_count = RES_COUNT(rom_resources), +}; + +int platform_int_priority[NR_INTC_IRQS] = { + IR0, IR1, IR2, IR3, PCA, PCB, PCC, PCD, /* IRQ 0- 7 */ + RES, RES, RES, RES, SER, ERR, PW3, PW2, /* IRQ 8-15 */ + PW1, PW0, DM0, DM1, DM2, DM3, DAE, RES, /* IRQ 16-23 */ + RES, RES, RES, RES, RES, RES, RES, RES, /* IRQ 24-31 */ + TU0, TU1, TU2, TI2, ATI, PRI, CUI, ERI, /* IRQ 32-39 */ + RXI, BRI, TXI, RES, RES, RES, RES, RES, /* IRQ 40-47 */ + RES, RES, RES, RES, RES, RES, RES, RES, /* IRQ 48-55 */ + RES, RES, RES, RES, RES, RES, RES, ITI, /* IRQ 56-63 */ +}; + +static int __init smsc_superio_setup(void) +{ + unsigned char devid, devrev; + + smsc_superio_virt = onchip_remap(SMSC_SUPERIO_BASE, 1024, "SMSC SuperIO"); + if (!smsc_superio_virt) { + panic("Unable to remap SMSC SuperIO\n"); + } + + /* Initially the chip is in run state */ + /* Put it into configuration state */ + outb(SMSC_ENTER_CONFIG_KEY, SMSC_CONFIG_PORT_ADDR); + outb(SMSC_ENTER_CONFIG_KEY, SMSC_CONFIG_PORT_ADDR); + + /* Read device ID info */ + devid = SMSC_SUPERIO_READ_INDEXED(SMSC_DEVICE_ID_INDEX); + devrev = SMSC_SUPERIO_READ_INDEXED(SMSC_DEVICE_REV_INDEX); + printk("SMSC SuperIO devid %02x rev %02x\n", devid, devrev); + + /* Select the keyboard device */ + SMSC_SUPERIO_WRITE_INDEXED(SMSC_KEYBOARD_DEVICE, SMCS_LOGICAL_DEV_INDEX); + + /* enable it */ + SMSC_SUPERIO_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX); + + /* Select the interrupts */ + /* On a PC keyboard is IRQ1, mouse is IRQ12 */ + SMSC_SUPERIO_WRITE_INDEXED(1, SMSC_PRIMARY_INT_INDEX); + SMSC_SUPERIO_WRITE_INDEXED(12, SMSC_SECONDARY_INT_INDEX); + + /* Exit the configuraton state */ + outb(SMSC_EXIT_CONFIG_KEY, SMSC_CONFIG_PORT_ADDR); + + return 0; +} + +/* This is grotty, but, because kernel is always referenced on the link line + * before any devices, this is safe. + */ +__initcall(smsc_superio_setup); + +void __init platform_setup(void) +{ + /* Cayman platform leaves the decision to head.S, for now */ + platform_parms.fpu_flags = fpu_in_use; +} + +void __init platform_monitor(void) +{ + /* Nothing yet .. */ +} + +void __init platform_reserve(void) +{ + /* Nothing yet .. */ +} + +const char *get_system_type(void) +{ + return "Hitachi Cayman"; +} + diff -puN /dev/null arch/sh64/mach-harp/Makefile --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/mach-harp/Makefile 2004-06-28 13:30:30.703136256 -0700 @@ -0,0 +1,14 @@ +# +# Makefile for the ST50 Harp specific parts of the kernel +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +O_TARGET := harp.o + +obj-y := setup.o + +include $(TOPDIR)/Rules.make + diff -puN /dev/null arch/sh64/mach-harp/setup.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/mach-harp/setup.c 2004-06-28 13:30:30.704136104 -0700 @@ -0,0 +1,139 @@ +/* + * 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. + * + * arch/sh64/mach-harp/setup.c + * + * SH-5 Simulator Platform Support + * + * This file handles the architecture-dependent parts of initialization + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + * benedict.gaster@superh.com: 3rd May 2002 + * Added support for ramdisk, removing statically linked romfs at the same time. * + * + * lethal@linux-sh.org: 15th May 2003 + * Use the generic procfs cpuinfo interface, just return a valid board name. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RES_COUNT(res) ((sizeof((res))/sizeof(struct resource))) + +/* + * Platform Dependent Interrupt Priorities. + */ + +/* Using defaults defined in irq.h */ +#define RES NO_PRIORITY /* Disabled */ +#define IR0 IRL0_PRIORITY /* IRLs */ +#define IR1 IRL1_PRIORITY +#define IR2 IRL2_PRIORITY +#define IR3 IRL3_PRIORITY +#define PCA INTA_PRIORITY /* PCI Ints */ +#define PCB INTB_PRIORITY +#define PCC INTC_PRIORITY +#define PCD INTD_PRIORITY +#define SER TOP_PRIORITY +#define ERR TOP_PRIORITY +#define PW0 TOP_PRIORITY +#define PW1 TOP_PRIORITY +#define PW2 TOP_PRIORITY +#define PW3 TOP_PRIORITY +#define DM0 NO_PRIORITY /* DMA Ints */ +#define DM1 NO_PRIORITY +#define DM2 NO_PRIORITY +#define DM3 NO_PRIORITY +#define DAE NO_PRIORITY +#define TU0 TIMER_PRIORITY /* TMU Ints */ +#define TU1 NO_PRIORITY +#define TU2 NO_PRIORITY +#define TI2 NO_PRIORITY +#define ATI NO_PRIORITY /* RTC Ints */ +#define PRI NO_PRIORITY +#define CUI RTC_PRIORITY +#define ERI SCIF_PRIORITY /* SCIF Ints */ +#define RXI SCIF_PRIORITY +#define BRI SCIF_PRIORITY +#define TXI SCIF_PRIORITY +#define ITI TOP_PRIORITY /* WDT Ints */ + +/* + * Platform dependent structures: maps and parms block. + */ +struct resource io_resources[] = { + /* To be updated with external devices */ +}; + +struct resource kram_resources[] = { + { "Kernel code", 0, 0 }, /* These must be last in the array */ + { "Kernel data", 0, 0 } /* These must be last in the array */ +}; + +struct resource xram_resources[] = { + /* To be updated with external devices */ +}; + +struct resource rom_resources[] = { + /* To be updated with external devices */ +}; + +struct sh64_platform platform_parms = { + .readonly_rootfs = 1, + .initial_root_dev = 0x0100, + .loader_type = 1, + .io_res_p = io_resources, + .io_res_count = RES_COUNT(io_resources), + .kram_res_p = kram_resources, + .kram_res_count = RES_COUNT(kram_resources), + .xram_res_p = xram_resources, + .xram_res_count = RES_COUNT(xram_resources), + .rom_res_p = rom_resources, + .rom_res_count = RES_COUNT(rom_resources), +}; + +int platform_int_priority[NR_INTC_IRQS] = { + IR0, IR1, IR2, IR3, PCA, PCB, PCC, PCD, /* IRQ 0- 7 */ + RES, RES, RES, RES, SER, ERR, PW3, PW2, /* IRQ 8-15 */ + PW1, PW0, DM0, DM1, DM2, DM3, DAE, RES, /* IRQ 16-23 */ + RES, RES, RES, RES, RES, RES, RES, RES, /* IRQ 24-31 */ + TU0, TU1, TU2, TI2, ATI, PRI, CUI, ERI, /* IRQ 32-39 */ + RXI, BRI, TXI, RES, RES, RES, RES, RES, /* IRQ 40-47 */ + RES, RES, RES, RES, RES, RES, RES, RES, /* IRQ 48-55 */ + RES, RES, RES, RES, RES, RES, RES, ITI, /* IRQ 56-63 */ +}; + +void __init platform_setup(void) +{ + /* Harp platform leaves the decision to head.S, for now */ + platform_parms.fpu_flags = fpu_in_use; +} + +void __init platform_monitor(void) +{ + /* Nothing yet .. */ +} + +void __init platform_reserve(void) +{ + /* Nothing yet .. */ +} + +const char *get_system_type(void) +{ + return "ST50 Harp"; +} + diff -puN /dev/null arch/sh64/mach-romram/Makefile --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/mach-romram/Makefile 2004-06-28 13:30:30.704136104 -0700 @@ -0,0 +1,14 @@ +# +# Makefile for the SH-5 ROM/RAM specific parts of the kernel +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +O_TARGET := romram.o + +obj-y := setup.o + +include $(TOPDIR)/Rules.make + diff -puN /dev/null arch/sh64/mach-romram/setup.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/mach-romram/setup.c 2004-06-28 13:30:30.705135952 -0700 @@ -0,0 +1,142 @@ +/* + * 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. + * + * arch/sh64/mach-romram/setup.c + * + * SH-5 ROM/RAM Platform Support + * + * This file handles the architecture-dependent parts of initialization + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + * benedict.gaster@superh.com: 3rd May 2002 + * Added support for ramdisk, removing statically linked romfs at the same time. * + * + * lethal@linux-sh.org: 15th May 2003 + * Use the generic procfs cpuinfo interface, just return a valid board name. + * + * Sean.McGoogan@superh.com 17th Feb 2004 + * copied from arch/sh64/mach-harp/setup.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RES_COUNT(res) ((sizeof((res))/sizeof(struct resource))) + +/* + * Platform Dependent Interrupt Priorities. + */ + +/* Using defaults defined in irq.h */ +#define RES NO_PRIORITY /* Disabled */ +#define IR0 IRL0_PRIORITY /* IRLs */ +#define IR1 IRL1_PRIORITY +#define IR2 IRL2_PRIORITY +#define IR3 IRL3_PRIORITY +#define PCA INTA_PRIORITY /* PCI Ints */ +#define PCB INTB_PRIORITY +#define PCC INTC_PRIORITY +#define PCD INTD_PRIORITY +#define SER TOP_PRIORITY +#define ERR TOP_PRIORITY +#define PW0 TOP_PRIORITY +#define PW1 TOP_PRIORITY +#define PW2 TOP_PRIORITY +#define PW3 TOP_PRIORITY +#define DM0 NO_PRIORITY /* DMA Ints */ +#define DM1 NO_PRIORITY +#define DM2 NO_PRIORITY +#define DM3 NO_PRIORITY +#define DAE NO_PRIORITY +#define TU0 TIMER_PRIORITY /* TMU Ints */ +#define TU1 NO_PRIORITY +#define TU2 NO_PRIORITY +#define TI2 NO_PRIORITY +#define ATI NO_PRIORITY /* RTC Ints */ +#define PRI NO_PRIORITY +#define CUI RTC_PRIORITY +#define ERI SCIF_PRIORITY /* SCIF Ints */ +#define RXI SCIF_PRIORITY +#define BRI SCIF_PRIORITY +#define TXI SCIF_PRIORITY +#define ITI TOP_PRIORITY /* WDT Ints */ + +/* + * Platform dependent structures: maps and parms block. + */ +struct resource io_resources[] = { + /* To be updated with external devices */ +}; + +struct resource kram_resources[] = { + { "Kernel code", 0, 0 }, /* These must be last in the array */ + { "Kernel data", 0, 0 } /* These must be last in the array */ +}; + +struct resource xram_resources[] = { + /* To be updated with external devices */ +}; + +struct resource rom_resources[] = { + /* To be updated with external devices */ +}; + +struct sh64_platform platform_parms = { + .readonly_rootfs = 1, + .initial_root_dev = 0x0100, + .loader_type = 1, + .io_res_p = io_resources, + .io_res_count = RES_COUNT(io_resources), + .kram_res_p = kram_resources, + .kram_res_count = RES_COUNT(kram_resources), + .xram_res_p = xram_resources, + .xram_res_count = RES_COUNT(xram_resources), + .rom_res_p = rom_resources, + .rom_res_count = RES_COUNT(rom_resources), +}; + +int platform_int_priority[NR_INTC_IRQS] = { + IR0, IR1, IR2, IR3, PCA, PCB, PCC, PCD, /* IRQ 0- 7 */ + RES, RES, RES, RES, SER, ERR, PW3, PW2, /* IRQ 8-15 */ + PW1, PW0, DM0, DM1, DM2, DM3, DAE, RES, /* IRQ 16-23 */ + RES, RES, RES, RES, RES, RES, RES, RES, /* IRQ 24-31 */ + TU0, TU1, TU2, TI2, ATI, PRI, CUI, ERI, /* IRQ 32-39 */ + RXI, BRI, TXI, RES, RES, RES, RES, RES, /* IRQ 40-47 */ + RES, RES, RES, RES, RES, RES, RES, RES, /* IRQ 48-55 */ + RES, RES, RES, RES, RES, RES, RES, ITI, /* IRQ 56-63 */ +}; + +void __init platform_setup(void) +{ + /* ROM/RAM platform leaves the decision to head.S, for now */ + platform_parms.fpu_flags = fpu_in_use; +} + +void __init platform_monitor(void) +{ + /* Nothing yet .. */ +} + +void __init platform_reserve(void) +{ + /* Nothing yet .. */ +} + +const char *get_system_type(void) +{ + return "ROM/RAM"; +} + diff -puN /dev/null arch/sh64/mach-sim/Makefile --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/mach-sim/Makefile 2004-06-28 13:30:30.705135952 -0700 @@ -0,0 +1,14 @@ +# +# Makefile for the SH-5 Simulator specific parts of the kernel +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +O_TARGET := sim.o + +obj-y := setup.o + +include $(TOPDIR)/Rules.make + diff -puN /dev/null arch/sh64/mach-sim/setup.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/mach-sim/setup.c 2004-06-28 13:30:30.706135800 -0700 @@ -0,0 +1,164 @@ +/* + * 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. + * + * arch/sh64/mach-sim/setup.c + * + * ST50 Simulator Platform Support + * + * This file handles the architecture-dependent parts of initialization + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + * lethal@linux-sh.org: 15th May 2003 + * Use the generic procfs cpuinfo interface, just return a valid board name. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_BLK_DEV_INITRD +#include "../rootfs/rootfs.h" +#endif + +static __init void platform_monitor(void); +static __init void platform_setup(void); +static __init void platform_reserve(void); + + +#define PHYS_MEMORY CONFIG_MEMORY_SIZE_IN_MB*1024*1024 + +#if (PHYS_MEMORY < P1SEG_FOOTPRINT_RAM) +#error "Invalid kernel configuration. Physical memory below footprint requirements." +#endif + +#define RAM_DISK_START CONFIG_MEMORY_START+P1SEG_INITRD_BLOCK /* Top of 4MB */ +#ifdef PLATFORM_ROMFS_SIZE +#define RAM_DISK_SIZE (PAGE_ALIGN(PLATFORM_ROMFS_SIZE)) /* Variable Top */ +#if ((RAM_DISK_START + RAM_DISK_SIZE) > (CONFIG_MEMORY_START + PHYS_MEMORY)) +#error "Invalid kernel configuration. ROM RootFS exceeding physical memory." +#endif +#else +#define RAM_DISK_SIZE P1SEG_INITRD_BLOCK_SIZE /* Top of 4MB */ +#endif + +#define RES_COUNT(res) ((sizeof((res))/sizeof(struct resource))) + +/* + * Platform Dependent Interrupt Priorities. + */ + +/* Using defaults defined in irq.h */ +#define RES NO_PRIORITY /* Disabled */ +#define IR0 IRL0_PRIORITY /* IRLs */ +#define IR1 IRL1_PRIORITY +#define IR2 IRL2_PRIORITY +#define IR3 IRL3_PRIORITY +#define PCA INTA_PRIORITY /* PCI Ints */ +#define PCB INTB_PRIORITY +#define PCC INTC_PRIORITY +#define PCD INTD_PRIORITY +#define SER TOP_PRIORITY +#define ERR TOP_PRIORITY +#define PW0 TOP_PRIORITY +#define PW1 TOP_PRIORITY +#define PW2 TOP_PRIORITY +#define PW3 TOP_PRIORITY +#define DM0 NO_PRIORITY /* DMA Ints */ +#define DM1 NO_PRIORITY +#define DM2 NO_PRIORITY +#define DM3 NO_PRIORITY +#define DAE NO_PRIORITY +#define TU0 TIMER_PRIORITY /* TMU Ints */ +#define TU1 NO_PRIORITY +#define TU2 NO_PRIORITY +#define TI2 NO_PRIORITY +#define ATI NO_PRIORITY /* RTC Ints */ +#define PRI NO_PRIORITY +#define CUI RTC_PRIORITY +#define ERI SCIF_PRIORITY /* SCIF Ints */ +#define RXI SCIF_PRIORITY +#define BRI SCIF_PRIORITY +#define TXI SCIF_PRIORITY +#define ITI TOP_PRIORITY /* WDT Ints */ + +/* + * Platform dependent structures: maps and parms block. + */ +struct resource io_resources[] = { + /* Nothing yet .. */ +}; + +struct resource kram_resources[] = { + { "Kernel code", 0, 0 }, /* These must be last in the array */ + { "Kernel data", 0, 0 } /* These must be last in the array */ +}; + +struct resource xram_resources[] = { + /* Nothing yet .. */ +}; + +struct resource rom_resources[] = { + /* Nothing yet .. */ +}; + +struct sh64_platform platform_parms = { + .readonly_rootfs = 1, + .initial_root_dev = 0x0100, + .loader_type = 1, + .initrd_start = RAM_DISK_START, + .initrd_size = RAM_DISK_SIZE, + .io_res_p = io_resources, + .io_res_count = RES_COUNT(io_resources), + .kram_res_p = kram_resources, + .kram_res_count = RES_COUNT(kram_resources), + .xram_res_p = xram_resources, + .xram_res_count = RES_COUNT(xram_resources), + .rom_res_p = rom_resources, + .rom_res_count = RES_COUNT(rom_resources), +}; + +int platform_int_priority[NR_IRQS] = { + IR0, IR1, IR2, IR3, PCA, PCB, PCC, PCD, /* IRQ 0- 7 */ + RES, RES, RES, RES, SER, ERR, PW3, PW2, /* IRQ 8-15 */ + PW1, PW0, DM0, DM1, DM2, DM3, DAE, RES, /* IRQ 16-23 */ + RES, RES, RES, RES, RES, RES, RES, RES, /* IRQ 24-31 */ + TU0, TU1, TU2, TI2, ATI, PRI, CUI, ERI, /* IRQ 32-39 */ + RXI, BRI, TXI, RES, RES, RES, RES, RES, /* IRQ 40-47 */ + RES, RES, RES, RES, RES, RES, RES, RES, /* IRQ 48-55 */ + RES, RES, RES, RES, RES, RES, RES, ITI, /* IRQ 56-63 */ +}; + +void __init platform_setup(void) +{ + /* Simulator platform leaves the decision to head.S */ + platform_parms.fpu_flags = fpu_in_use; +} + +void __init platform_monitor(void) +{ + /* Nothing yet .. */ +} + +void __init platform_reserve(void) +{ + /* Nothing yet .. */ +} + +const char *get_system_type(void) +{ + return "SH-5 Simulator"; +} + diff -puN /dev/null arch/sh64/Makefile --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/Makefile 2004-06-28 13:30:30.707135648 -0700 @@ -0,0 +1,112 @@ +# +# 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) 2000, 2001 Paolo Alberelli +# Copyright (C) 2003, 2004 Paul Mundt +# +# This file is included by the global makefile so that you can add your own +# architecture-specific flags and dependencies. Remember to do have actions +# for "archclean" and "archdep" for cleaning up and making dependencies for +# this architecture +# +# Note that top level Makefile automagically builds dependencies for SUBDIRS +# but does not automagically clean SUBDIRS. Therefore "archclean" should clean +# up all, "archdep" does nothing on added SUBDIRS. +# +ifndef include_config +-include .config +endif + +cpu-y := -mb +cpu-$(CONFIG_LITTLE_ENDIAN) := -ml + +cpu-$(CONFIG_CPU_SH5) += -m5-32media-nofpu + +ifdef CONFIG_LITTLE_ENDIAN +LDFLAGS_vmlinux += --defsym 'jiffies=jiffies_64' +LDFLAGS += -EL -mshlelf32_linux +else +LDFLAGS_vmlinux += --defsym 'jiffies=jiffies_64+4' +LDFLAGS += -EB -mshelf32_linux +endif + +# No requirements for endianess support from AFLAGS, 'as' always run through gcc +AFLAGS += -m5 -isa=sh64 -traditional +CFLAGS += $(cpu-y) + +LDFLAGS_vmlinux += --defsym phys_stext=_stext-$(CONFIG_CACHED_MEMORY_OFFSET) \ + -e phys_stext + +OBJCOPYFLAGS := -O binary -R .note -R .comment -R .stab -R .stabstr -S + +ifdef LOADADDR +LINKFLAGS += -Ttext $(word 1,$(LOADADDR)) +endif + +machine-$(CONFIG_SH_CAYMAN) := cayman +machine-$(CONFIG_SH_SIMULATOR) := sim +machine-$(CONFIG_SH_HARP) := harp +machine-$(CONFIG_SH_ROMRAM) := romram + +head-y := arch/$(ARCH)/kernel/head.o arch/$(ARCH)/kernel/init_task.o + +core-y += $(addprefix arch/$(ARCH)/, kernel/ mm/ mach-$(machine-y)/) + +LIBGCC := $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) +libs-y += arch/$(ARCH)/lib/ $(LIBGCC) + +drivers-$(CONFIG_OPROFILE) += arch/sh64/oprofile/ + +boot := arch/$(ARCH)/boot + +zImage: vmlinux + $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ + +compressed: zImage + +archclean: + $(Q)$(MAKE) $(clean)=$(boot) + +prepare: include/asm-$(ARCH)/asm-offsets.h arch/$(ARCH)/lib/syscalltab.h + +include/asm-$(ARCH)/asm-offsets.h: arch/$(ARCH)/kernel/asm-offsets.s \ + include/asm include/linux/version.h + $(call filechk,gen-asm-offsets) + +define filechk_gen-syscalltab + (set -e; \ + echo "/*"; \ + echo " * DO NOT MODIFY."; \ + echo " *"; \ + echo " * This file was generated by arch/$(ARCH)/Makefile"; \ + echo " * Any changes will be reverted at build time."; \ + echo " */"; \ + echo ""; \ + echo "#ifndef __SYSCALLTAB_H"; \ + echo "#define __SYSCALLTAB_H"; \ + echo ""; \ + echo "#include "; \ + echo ""; \ + echo "struct syscall_info {"; \ + echo " const char *name;"; \ + echo "} syscall_info_table[] = {"; \ + sed -e '/^.*\.long /!d;s//\t{ "/;s/\(\([^/]*\)\/\)\{1\}.*/\2/; \ + s/[ \t]*$$//g;s/$$/" },/;s/\("\)sys_/\1/g'; \ + echo "};"; \ + echo ""; \ + echo "#define NUM_SYSCALL_INFO_ENTRIES ARRAY_SIZE(syscall_info_table)"; \ + echo ""; \ + echo "#endif /* __SYSCALLTAB_H */" ) +endef + +arch/$(ARCH)/lib/syscalltab.h: arch/sh64/kernel/syscalls.S + $(call filechk,gen-syscalltab) + +CLEAN_FILES += include/asm-$(ARCH)/asm-offsets.h arch/$(ARCH)/lib/syscalltab.h + +define archhelp + @echo ' zImage - Compressed kernel image (arch/sh64/boot/zImage)' +endef + diff -puN /dev/null arch/sh64/mm/cache.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/mm/cache.c 2004-06-28 13:30:30.713134736 -0700 @@ -0,0 +1,1055 @@ +/* + * 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. + * + * arch/sh64/mm/cache.c + * + * Original version Copyright (C) 2000, 2001 Paolo Alberelli + * Second version Copyright (C) benedict.gaster@superh.com 2002 + * Third version Copyright Richard.Curnow@superh.com 2003 + * Hacks to third version Copyright (C) 2003 Paul Mundt + */ + +/****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for flush_itlb_range */ + +#include + +/* This function is in entry.S */ +extern unsigned long switch_and_save_asid(unsigned long new_asid); + +/* Wired TLB entry for the D-cache */ +static unsigned long long dtlb_cache_slot; + +/** + * sh64_cache_init() + * + * This is pretty much just a straightforward clone of the SH + * detect_cpu_and_cache_system(). + * + * This function is responsible for setting up all of the cache + * info dynamically as well as taking care of CPU probing and + * setting up the relevant subtype data. + * + * FIXME: For the time being, we only really support the SH5-101 + * out of the box, and don't support dynamic probing for things + * like the SH5-103 or even cut2 of the SH5-101. Implement this + * later! + */ +int __init sh64_cache_init(void) +{ + /* + * First, setup some sane values for the I-cache. + */ + cpu_data->icache.ways = 4; + cpu_data->icache.sets = 256; + cpu_data->icache.linesz = L1_CACHE_BYTES; + + /* + * FIXME: This can probably be cleaned up a bit as well.. for example, + * do we really need the way shift _and_ the way_step_shift ?? Judging + * by the existing code, I would guess no.. is there any valid reason + * why we need to be tracking this around? + */ + cpu_data->icache.way_shift = 13; + cpu_data->icache.entry_shift = 5; + cpu_data->icache.set_shift = 4; + cpu_data->icache.way_step_shift = 16; + cpu_data->icache.asid_shift = 2; + + /* + * way offset = cache size / associativity, so just don't factor in + * associativity in the first place.. + */ + cpu_data->icache.way_ofs = cpu_data->icache.sets * + cpu_data->icache.linesz; + + cpu_data->icache.asid_mask = 0x3fc; + cpu_data->icache.idx_mask = 0x1fe0; + cpu_data->icache.epn_mask = 0xffffe000; + cpu_data->icache.flags = 0; + + /* + * Next, setup some sane values for the D-cache. + * + * On the SH5, these are pretty consistent with the I-cache settings, + * so we just copy over the existing definitions.. these can be fixed + * up later, especially if we add runtime CPU probing. + * + * Though in the meantime it saves us from having to duplicate all of + * the above definitions.. + */ + cpu_data->dcache = cpu_data->icache; + + /* + * Setup any cache-related flags here + */ +#if defined(CONFIG_DCACHE_WRITE_THROUGH) + set_bit(SH_CACHE_MODE_WT, &(cpu_data->dcache.flags)); +#elif defined(CONFIG_DCACHE_WRITE_BACK) + set_bit(SH_CACHE_MODE_WB, &(cpu_data->dcache.flags)); +#endif + + /* + * We also need to reserve a slot for the D-cache in the DTLB, so we + * do this now .. + */ + dtlb_cache_slot = sh64_get_wired_dtlb_entry(); + + return 0; +} + +/*##########################################################################*/ + +/* From here onwards, a rewrite of the implementation, + by Richard.Curnow@superh.com. + + The major changes in this compared to the old version are; + 1. use more selective purging through OCBP instead of using ALLOCO to purge + by natural replacement. This avoids purging out unrelated cache lines + that happen to be in the same set. + 2. exploit the APIs copy_user_page and clear_user_page better + 3. be more selective about I-cache purging, in particular use invalidate_all + more sparingly. + + */ + +/*########################################################################## + SUPPORT FUNCTIONS + ##########################################################################*/ + +/****************************************************************************/ +/* The following group of functions deal with mapping and unmapping a temporary + page into the DTLB slot that have been set aside for our exclusive use. */ +/* In order to accomplish this, we use the generic interface for adding and + removing a wired slot entry as defined in arch/sh64/mm/tlb.c */ +/****************************************************************************/ + +static unsigned long slot_own_flags; + +static inline void sh64_setup_dtlb_cache_slot(unsigned long eaddr, unsigned long asid, unsigned long paddr) +{ + local_irq_save(slot_own_flags); + sh64_setup_tlb_slot(dtlb_cache_slot, eaddr, asid, paddr); +} + +static inline void sh64_teardown_dtlb_cache_slot(void) +{ + sh64_teardown_tlb_slot(dtlb_cache_slot); + local_irq_restore(slot_own_flags); +} + +/****************************************************************************/ + +#ifndef CONFIG_ICACHE_DISABLED + +static void __inline__ sh64_icache_inv_all(void) +{ + unsigned long long addr, flag, data; + unsigned int flags; + + addr=ICCR0; + flag=ICCR0_ICI; + data=0; + + /* Make this a critical section for safety (probably not strictly necessary.) */ + local_irq_save(flags); + + /* Without %1 it gets unexplicably wrong */ + asm volatile("getcfg %3, 0, %0\n\t" + "or %0, %2, %0\n\t" + "putcfg %3, 0, %0\n\t" + "synci" + : "=&r" (data) + : "0" (data), "r" (flag), "r" (addr)); + + local_irq_restore(flags); +} + +static void sh64_icache_inv_kernel_range(unsigned long start, unsigned long end) +{ + /* Invalidate range of addresses [start,end] from the I-cache, where + * the addresses lie in the kernel superpage. */ + + unsigned long long ullend, addr, aligned_start; +#if (NEFF == 32) + aligned_start = (unsigned long long)(signed long long)(signed long) start; +#else +#error "NEFF != 32" +#endif + aligned_start &= L1_CACHE_ALIGN_MASK; + addr = aligned_start; +#if (NEFF == 32) + ullend = (unsigned long long) (signed long long) (signed long) end; +#else +#error "NEFF != 32" +#endif + while (addr <= ullend) { + asm __volatile__ ("icbi %0, 0" : : "r" (addr)); + addr += L1_CACHE_BYTES; + } +} + +static void sh64_icache_inv_user_page(struct vm_area_struct *vma, unsigned long eaddr) +{ + /* If we get called, we know that vma->vm_flags contains VM_EXEC. + Also, eaddr is page-aligned. */ + + unsigned long long addr, end_addr; + unsigned long flags = 0; + unsigned long running_asid, vma_asid; + addr = eaddr; + end_addr = addr + PAGE_SIZE; + + /* Check whether we can use the current ASID for the I-cache + invalidation. For example, if we're called via + access_process_vm->flush_cache_page->here, (e.g. when reading from + /proc), 'running_asid' will be that of the reader, not of the + victim. + + Also, note the risk that we might get pre-empted between the ASID + compare and blocking IRQs, and before we regain control, the + pid->ASID mapping changes. However, the whole cache will get + invalidated when the mapping is renewed, so the worst that can + happen is that the loop below ends up invalidating somebody else's + cache entries. + */ + + running_asid = get_asid(); + vma_asid = (vma->vm_mm->context & MMU_CONTEXT_ASID_MASK); + if (running_asid != vma_asid) { + local_irq_save(flags); + switch_and_save_asid(vma_asid); + } + while (addr < end_addr) { + /* Worth unrolling a little */ + asm __volatile__("icbi %0, 0" : : "r" (addr)); + asm __volatile__("icbi %0, 32" : : "r" (addr)); + asm __volatile__("icbi %0, 64" : : "r" (addr)); + asm __volatile__("icbi %0, 96" : : "r" (addr)); + addr += 128; + } + if (running_asid != vma_asid) { + switch_and_save_asid(running_asid); + local_irq_restore(flags); + } +} + +/****************************************************************************/ + +static void sh64_icache_inv_user_page_range(struct mm_struct *mm, + unsigned long start, unsigned long end) +{ + /* Used for invalidating big chunks of I-cache, i.e. assume the range + is whole pages. If 'start' or 'end' is not page aligned, the code + is conservative and invalidates to the ends of the enclosing pages. + This is functionally OK, just a performance loss. */ + + /* See the comments below in sh64_dcache_purge_user_range() regarding + the choice of algorithm. However, for the I-cache option (2) isn't + available because there are no physical tags so aliases can't be + resolved. The icbi instruction has to be used through the user + mapping. Because icbi is cheaper than ocbp on a cache hit, it + would be cheaper to use the selective code for a large range than is + possible with the D-cache. Just assume 64 for now as a working + figure. + */ + + int n_pages; + + if (!mm) return; + + n_pages = ((end - start) >> PAGE_SHIFT); + if (n_pages >= 64) { + sh64_icache_inv_all(); + } else { + unsigned long aligned_start; + unsigned long eaddr; + unsigned long after_last_page_start; + unsigned long mm_asid, current_asid; + unsigned long long flags = 0ULL; + + mm_asid = mm->context & MMU_CONTEXT_ASID_MASK; + current_asid = get_asid(); + + if (mm_asid != current_asid) { + /* Switch ASID and run the invalidate loop under cli */ + local_irq_save(flags); + switch_and_save_asid(mm_asid); + } + + aligned_start = start & PAGE_MASK; + after_last_page_start = PAGE_SIZE + ((end - 1) & PAGE_MASK); + + while (aligned_start < after_last_page_start) { + struct vm_area_struct *vma; + unsigned long vma_end; + vma = find_vma(mm, aligned_start); + if (!vma || (aligned_start <= vma->vm_end)) { + /* Avoid getting stuck in an error condition */ + aligned_start += PAGE_SIZE; + continue; + } + vma_end = vma->vm_end; + if (vma->vm_flags & VM_EXEC) { + /* Executable */ + eaddr = aligned_start; + while (eaddr < vma_end) { + sh64_icache_inv_user_page(vma, eaddr); + eaddr += PAGE_SIZE; + } + } + aligned_start = vma->vm_end; /* Skip to start of next region */ + } + if (mm_asid != current_asid) { + switch_and_save_asid(current_asid); + local_irq_restore(flags); + } + } +} + +static void sh64_icache_inv_user_small_range(struct mm_struct *mm, + unsigned long start, int len) +{ + + /* Invalidate a small range of user context I-cache, not necessarily + page (or even cache-line) aligned. */ + + unsigned long long eaddr = start; + unsigned long long eaddr_end = start + len; + unsigned long current_asid, mm_asid; + unsigned long long flags; + unsigned long long epage_start; + + /* Since this is used inside ptrace, the ASID in the mm context + typically won't match current_asid. We'll have to switch ASID to do + this. For safety, and given that the range will be small, do all + this under cli. + + Note, there is a hazard that the ASID in mm->context is no longer + actually associated with mm, i.e. if the mm->context has started a + new cycle since mm was last active. However, this is just a + performance issue: all that happens is that we invalidate lines + belonging to another mm, so the owning process has to refill them + when that mm goes live again. mm itself can't have any cache + entries because there will have been a flush_cache_all when the new + mm->context cycle started. */ + + /* Align to start of cache line. Otherwise, suppose len==8 and start + was at 32N+28 : the last 4 bytes wouldn't get invalidated. */ + eaddr = start & L1_CACHE_ALIGN_MASK; + eaddr_end = start + len; + + local_irq_save(flags); + mm_asid = mm->context & MMU_CONTEXT_ASID_MASK; + current_asid = switch_and_save_asid(mm_asid); + + epage_start = eaddr & PAGE_MASK; + + while (eaddr < eaddr_end) + { + asm __volatile__("icbi %0, 0" : : "r" (eaddr)); + eaddr += L1_CACHE_BYTES; + } + switch_and_save_asid(current_asid); + local_irq_restore(flags); +} + +static void sh64_icache_inv_current_user_range(unsigned long start, unsigned long end) +{ + /* The icbi instruction never raises ITLBMISS. i.e. if there's not a + cache hit on the virtual tag the instruction ends there, without a + TLB lookup. */ + + unsigned long long aligned_start; + unsigned long long ull_end; + unsigned long long addr; + + ull_end = end; + + /* Just invalidate over the range using the natural addresses. TLB + miss handling will be OK (TBC). Since it's for the current process, + either we're already in the right ASID context, or the ASIDs have + been recycled since we were last active in which case we might just + invalidate another processes I-cache entries : no worries, just a + performance drop for him. */ + aligned_start = start & L1_CACHE_ALIGN_MASK; + addr = aligned_start; + while (addr < ull_end) { + asm __volatile__ ("icbi %0, 0" : : "r" (addr)); + asm __volatile__ ("nop"); + asm __volatile__ ("nop"); + addr += L1_CACHE_BYTES; + } +} + +#endif /* !CONFIG_ICACHE_DISABLED */ + +/****************************************************************************/ + +#ifndef CONFIG_DCACHE_DISABLED + +/* Buffer used as the target of alloco instructions to purge data from cache + sets by natural eviction. -- RPC */ +#define DUMMY_ALLOCO_AREA_SIZE L1_CACHE_SIZE_BYTES + (1024 * 4) +static unsigned char dummy_alloco_area[DUMMY_ALLOCO_AREA_SIZE] __cacheline_aligned = { 0, }; + +/****************************************************************************/ + +static void __inline__ sh64_dcache_purge_sets(int sets_to_purge_base, int n_sets) +{ + /* Purge all ways in a particular block of sets, specified by the base + set number and number of sets. Can handle wrap-around, if that's + needed. */ + + int dummy_buffer_base_set; + unsigned long long eaddr, eaddr0, eaddr1; + int j; + int set_offset; + + dummy_buffer_base_set = ((int)&dummy_alloco_area & cpu_data->dcache.idx_mask) >> cpu_data->dcache.entry_shift; + set_offset = sets_to_purge_base - dummy_buffer_base_set; + + for (j=0; jdcache.sets - 1); + eaddr0 = (unsigned long long)dummy_alloco_area + (set_offset << cpu_data->dcache.entry_shift); + + /* Do one alloco which hits the required set per cache way. For + write-back mode, this will purge the #ways resident lines. There's + little point unrolling this loop because the allocos stall more if + they're too close together. */ + eaddr1 = eaddr0 + cpu_data->dcache.way_ofs * cpu_data->dcache.ways; + for (eaddr=eaddr0; eaddrdcache.way_ofs) { + asm __volatile__ ("alloco %0, 0" : : "r" (eaddr)); + } + + eaddr1 = eaddr0 + cpu_data->dcache.way_ofs * cpu_data->dcache.ways; + for (eaddr=eaddr0; eaddrdcache.way_ofs) { + /* Load from each address. Required because alloco is a NOP if + the cache is write-through. Write-through is a config option. */ + if (test_bit(SH_CACHE_MODE_WT, &(cpu_data->dcache.flags))) + *(volatile unsigned char *)(int)eaddr; + } + } + + /* Don't use OCBI to invalidate the lines. That costs cycles directly. + If the dummy block is just left resident, it will naturally get + evicted as required. */ + + return; +} + +/****************************************************************************/ + +static void sh64_dcache_purge_all(void) +{ + /* Purge the entire contents of the dcache. The most efficient way to + achieve this is to use alloco instructions on a region of unused + memory equal in size to the cache, thereby causing the current + contents to be discarded by natural eviction. The alternative, + namely reading every tag, setting up a mapping for the corresponding + page and doing an OCBP for the line, would be much more expensive. + */ + + sh64_dcache_purge_sets(0, cpu_data->dcache.sets); + + return; + +} + +/****************************************************************************/ + +static void sh64_dcache_purge_kernel_range(unsigned long start, unsigned long end) +{ + /* Purge the range of addresses [start,end] from the D-cache. The + addresses lie in the superpage mapping. There's no harm if we + overpurge at either end - just a small performance loss. */ + unsigned long long ullend, addr, aligned_start; +#if (NEFF == 32) + aligned_start = (unsigned long long)(signed long long)(signed long) start; +#else +#error "NEFF != 32" +#endif + aligned_start &= L1_CACHE_ALIGN_MASK; + addr = aligned_start; +#if (NEFF == 32) + ullend = (unsigned long long) (signed long long) (signed long) end; +#else +#error "NEFF != 32" +#endif + while (addr <= ullend) { + asm __volatile__ ("ocbp %0, 0" : : "r" (addr)); + addr += L1_CACHE_BYTES; + } + return; +} + +/* Assumes this address (+ (2**n_synbits) pages up from it) aren't used for + anything else in the kernel */ +#define MAGIC_PAGE0_START 0xffffffffec000000ULL + +static void sh64_dcache_purge_coloured_phy_page(unsigned long paddr, unsigned long eaddr) +{ + /* Purge the physical page 'paddr' from the cache. It's known that any + cache lines requiring attention have the same page colour as the the + address 'eaddr'. + + This relies on the fact that the D-cache matches on physical tags + when no virtual tag matches. So we create an alias for the original + page and purge through that. (Alternatively, we could have done + this by switching ASID to match the original mapping and purged + through that, but that involves ASID switching cost + probably a + TLBMISS + refill anyway.) + */ + + unsigned long long magic_page_start; + unsigned long long magic_eaddr, magic_eaddr_end; + + magic_page_start = MAGIC_PAGE0_START + (eaddr & CACHE_OC_SYN_MASK); + + /* As long as the kernel is not pre-emptible, this doesn't need to be + under cli/sti. */ + + sh64_setup_dtlb_cache_slot(magic_page_start, get_asid(), paddr); + + magic_eaddr = magic_page_start; + magic_eaddr_end = magic_eaddr + PAGE_SIZE; + while (magic_eaddr < magic_eaddr_end) { + /* Little point in unrolling this loop - the OCBPs are blocking + and won't go any quicker (i.e. the loop overhead is parallel + to part of the OCBP execution.) */ + asm __volatile__ ("ocbp %0, 0" : : "r" (magic_eaddr)); + magic_eaddr += L1_CACHE_BYTES; + } + + sh64_teardown_dtlb_cache_slot(); +} + +/****************************************************************************/ + +static void sh64_dcache_purge_phy_page(unsigned long paddr) +{ + /* Pure a page given its physical start address, by creating a + temporary 1 page mapping and purging across that. Even if we know + the virtual address (& vma or mm) of the page, the method here is + more elegant because it avoids issues of coping with page faults on + the purge instructions (i.e. no special-case code required in the + critical path in the TLB miss handling). */ + + unsigned long long eaddr_start, eaddr, eaddr_end; + int i; + + /* As long as the kernel is not pre-emptible, this doesn't need to be + under cli/sti. */ + + eaddr_start = MAGIC_PAGE0_START; + for (i=0; i < (1 << CACHE_OC_N_SYNBITS); i++) { + sh64_setup_dtlb_cache_slot(eaddr_start, get_asid(), paddr); + + eaddr = eaddr_start; + eaddr_end = eaddr + PAGE_SIZE; + while (eaddr < eaddr_end) { + asm __volatile__ ("ocbp %0, 0" : : "r" (eaddr)); + eaddr += L1_CACHE_BYTES; + } + + sh64_teardown_dtlb_cache_slot(); + eaddr_start += PAGE_SIZE; + } +} + +static void sh64_dcache_purge_virt_page(struct mm_struct *mm, unsigned long eaddr) +{ + unsigned long phys; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + pte_t entry; + + pgd = pgd_offset(mm, eaddr); + pmd = pmd_offset(pgd, eaddr); + + if (pmd_none(*pmd) || pmd_bad(*pmd)) + return; + + pte = pte_offset_kernel(pmd, eaddr); + entry = *pte; + + if (pte_none(entry) || !pte_present(entry)) + return; + + phys = pte_val(entry) & PAGE_MASK; + + sh64_dcache_purge_phy_page(phys); +} + +static void sh64_dcache_purge_user_page(struct mm_struct *mm, unsigned long eaddr) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + pte_t entry; + unsigned long paddr; + + /* NOTE : all the callers of this have mm->page_table_lock held, so the + following page table traversal is safe even on SMP/pre-emptible. */ + + if (!mm) return; /* No way to find physical address of page */ + pgd = pgd_offset(mm, eaddr); + if (pgd_bad(*pgd)) return; + + pmd = pmd_offset(pgd, eaddr); + if (pmd_none(*pmd) || pmd_bad(*pmd)) return; + + pte = pte_offset_kernel(pmd, eaddr); + entry = *pte; + if (pte_none(entry) || !pte_present(entry)) return; + + paddr = pte_val(entry) & PAGE_MASK; + + sh64_dcache_purge_coloured_phy_page(paddr, eaddr); + +} +/****************************************************************************/ + +static void sh64_dcache_purge_user_range(struct mm_struct *mm, + unsigned long start, unsigned long end) +{ + /* There are at least 5 choices for the implementation of this, with + pros (+), cons(-), comments(*): + + 1. ocbp each line in the range through the original user's ASID + + no lines spuriously evicted + - tlbmiss handling (must either handle faults on demand => extra + special-case code in tlbmiss critical path), or map the page in + advance (=> flush_tlb_range in advance to avoid multiple hits) + - ASID switching + - expensive for large ranges + + 2. temporarily map each page in the range to a special effective + address and ocbp through the temporary mapping; relies on the + fact that SH-5 OCB* always do TLB lookup and match on ptags (they + never look at the etags) + + no spurious evictions + - expensive for large ranges + * surely cheaper than (1) + + 3. walk all the lines in the cache, check the tags, if a match + occurs create a page mapping to ocbp the line through + + no spurious evictions + - tag inspection overhead + - (especially for small ranges) + - potential cost of setting up/tearing down page mapping for + every line that matches the range + * cost partly independent of range size + + 4. walk all the lines in the cache, check the tags, if a match + occurs use 4 * alloco to purge the line (+3 other probably + innocent victims) by natural eviction + + no tlb mapping overheads + - spurious evictions + - tag inspection overhead + + 5. implement like flush_cache_all + + no tag inspection overhead + - spurious evictions + - bad for small ranges + + (1) can be ruled out as more expensive than (2). (2) appears best + for small ranges. The choice between (3), (4) and (5) for large + ranges and the range size for the large/small boundary need + benchmarking to determine. + + For now use approach (2) for small ranges and (5) for large ones. + + */ + + int n_pages; + + n_pages = ((end - start) >> PAGE_SHIFT); + if (n_pages >= 64) { +#if 1 + sh64_dcache_purge_all(); +#else + unsigned long long set, way; + unsigned long mm_asid = mm->context & MMU_CONTEXT_ASID_MASK; + for (set = 0; set < cpu_data->dcache.sets; set++) { + unsigned long long set_base_config_addr = CACHE_OC_ADDRESS_ARRAY + (set << cpu_data->dcache.set_shift); + for (way = 0; way < cpu_data->dcache.ways; way++) { + unsigned long long config_addr = set_base_config_addr + (way << cpu_data->dcache.way_step_shift); + unsigned long long tag0; + unsigned long line_valid; + + asm __volatile__("getcfg %1, 0, %0" : "=r" (tag0) : "r" (config_addr)); + line_valid = tag0 & SH_CACHE_VALID; + if (line_valid) { + unsigned long cache_asid; + unsigned long epn; + + cache_asid = (tag0 & cpu_data->dcache.asid_mask) >> cpu_data->dcache.asid_shift; + /* The next line needs some + explanation. The virtual tags + encode bits [31:13] of the virtual + address, bit [12] of the 'tag' being + implied by the cache set index. */ + epn = (tag0 & cpu_data->dcache.epn_mask) | ((set & 0x80) << cpu_data->dcache.entry_shift); + + if ((cache_asid == mm_asid) && (start <= epn) && (epn < end)) { + /* TODO : could optimise this + call by batching multiple + adjacent sets together. */ + sh64_dcache_purge_sets(set, 1); + break; /* Don't waste time inspecting other ways for this set */ + } + } + } + } +#endif + } else { + /* 'Small' range */ + unsigned long aligned_start; + unsigned long eaddr; + unsigned long last_page_start; + + aligned_start = start & PAGE_MASK; + /* 'end' is 1 byte beyond the end of the range */ + last_page_start = (end - 1) & PAGE_MASK; + + eaddr = aligned_start; + while (eaddr <= last_page_start) { + sh64_dcache_purge_user_page(mm, eaddr); + eaddr += PAGE_SIZE; + } + } + return; +} + +static void sh64_dcache_wback_current_user_range(unsigned long start, unsigned long end) +{ + unsigned long long aligned_start; + unsigned long long ull_end; + unsigned long long addr; + + ull_end = end; + + /* Just wback over the range using the natural addresses. TLB miss + handling will be OK (TBC) : the range has just been written to by + the signal frame setup code, so the PTEs must exist. + + Note, if we have CONFIG_PREEMPT and get preempted inside this loop, + it doesn't matter, even if the pid->ASID mapping changes whilst + we're away. In that case the cache will have been flushed when the + mapping was renewed. So the writebacks below will be nugatory (and + we'll doubtless have to fault the TLB entry/ies in again with the + new ASID), but it's a rare case. + */ + aligned_start = start & L1_CACHE_ALIGN_MASK; + addr = aligned_start; + while (addr < ull_end) { + asm __volatile__ ("ocbwb %0, 0" : : "r" (addr)); + addr += L1_CACHE_BYTES; + } +} + +#endif /* !CONFIG_DCACHE_DISABLED */ + +/****************************************************************************/ + +/* These *MUST* lie in an area of virtual address space that's otherwise unused. */ +#define UNIQUE_EADDR_START 0xe0000000UL +#define UNIQUE_EADDR_END 0xe8000000UL + +static unsigned long sh64_make_unique_eaddr(unsigned long user_eaddr, unsigned long paddr) +{ + /* Given a physical address paddr, and a user virtual address + user_eaddr which will eventually be mapped to it, create a one-off + kernel-private eaddr mapped to the same paddr. This is used for + creating special destination pages for copy_user_page and + clear_user_page */ + + static unsigned long current_pointer = UNIQUE_EADDR_START; + unsigned long coloured_pointer; + + if (current_pointer == UNIQUE_EADDR_END) { + sh64_dcache_purge_all(); + current_pointer = UNIQUE_EADDR_START; + } + + coloured_pointer = (current_pointer & ~CACHE_OC_SYN_MASK) | (user_eaddr & CACHE_OC_SYN_MASK); + sh64_setup_dtlb_cache_slot(coloured_pointer, get_asid(), paddr); + + current_pointer += (PAGE_SIZE << CACHE_OC_N_SYNBITS); + + return coloured_pointer; +} + +/****************************************************************************/ + +static void sh64_copy_user_page_coloured(void *to, void *from, unsigned long address) +{ + void *coloured_to; + + /* Discard any existing cache entries of the wrong colour. These are + present quite often, if the kernel has recently used the page + internally, then given it up, then it's been allocated to the user. + */ + sh64_dcache_purge_coloured_phy_page(__pa(to), (unsigned long) to); + + coloured_to = (void *) sh64_make_unique_eaddr(address, __pa(to)); + sh64_page_copy(from, coloured_to); + + sh64_teardown_dtlb_cache_slot(); +} + +static void sh64_clear_user_page_coloured(void *to, unsigned long address) +{ + void *coloured_to; + + /* Discard any existing kernel-originated lines of the wrong colour (as + above) */ + sh64_dcache_purge_coloured_phy_page(__pa(to), (unsigned long) to); + + coloured_to = (void *) sh64_make_unique_eaddr(address, __pa(to)); + sh64_page_clear(coloured_to); + + sh64_teardown_dtlb_cache_slot(); +} + +/****************************************************************************/ + +/*########################################################################## + EXTERNALLY CALLABLE API. + ##########################################################################*/ + +/* These functions are described in Documentation/cachetlb.txt. + Each one of these functions varies in behaviour depending on whether the + I-cache and/or D-cache are configured out. + + Note that the Linux term 'flush' corresponds to what is termed 'purge' in + the sh/sh64 jargon for the D-cache, i.e. write back dirty data then + invalidate the cache lines, and 'invalidate' for the I-cache. + */ + +#undef FLUSH_TRACE + +void flush_cache_all(void) +{ + /* Invalidate the entire contents of both caches, after writing back to + memory any dirty data from the D-cache. */ + sh64_dcache_purge_all(); + sh64_icache_inv_all(); +} + +/****************************************************************************/ + +void flush_cache_mm(struct mm_struct *mm) +{ + /* Invalidate an entire user-address space from both caches, after + writing back dirty data (e.g. for shared mmap etc). */ + + /* This could be coded selectively by inspecting all the tags then + doing 4*alloco on any set containing a match (as for + flush_cache_range), but fork/exit/execve (where this is called from) + are expensive anyway. */ + + /* Have to do a purge here, despite the comments re I-cache below. + There could be odd-coloured dirty data associated with the mm still + in the cache - if this gets written out through natural eviction + after the kernel has reused the page there will be chaos. + */ + + sh64_dcache_purge_all(); + + /* The mm being torn down won't ever be active again, so any Icache + lines tagged with its ASID won't be visible for the rest of the + lifetime of this ASID cycle. Before the ASID gets reused, there + will be a flush_cache_all. Hence we don't need to touch the + I-cache. This is similar to the lack of action needed in + flush_tlb_mm - see fault.c. */ +} + +/****************************************************************************/ + +void flush_cache_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end) +{ + struct mm_struct *mm = vma->vm_mm; + + /* Invalidate (from both caches) the range [start,end) of virtual + addresses from the user address space specified by mm, after writing + back any dirty data. + + Note(1), 'end' is 1 byte beyond the end of the range to flush. + + Note(2), this is called with mm->page_table_lock held.*/ + + sh64_dcache_purge_user_range(mm, start, end); + sh64_icache_inv_user_page_range(mm, start, end); +} + +/****************************************************************************/ + +void flush_cache_page(struct vm_area_struct *vma, unsigned long eaddr) +{ + /* Invalidate any entries in either cache for the vma within the user + address space vma->vm_mm for the page starting at virtual address + 'eaddr'. This seems to be used primarily in breaking COW. Note, + the I-cache must be searched too in case the page in question is + both writable and being executed from (e.g. stack trampolines.) + + Note(1), this is called with mm->page_table_lock held. + */ + + sh64_dcache_purge_virt_page(vma->vm_mm, eaddr); + + if (vma->vm_flags & VM_EXEC) { + sh64_icache_inv_user_page(vma, eaddr); + } +} + +/****************************************************************************/ + +#ifndef CONFIG_DCACHE_DISABLED + +void copy_user_page(void *to, void *from, unsigned long address, struct page *page) +{ + /* 'from' and 'to' are kernel virtual addresses (within the superpage + mapping of the physical RAM). 'address' is the user virtual address + where the copy 'to' will be mapped after. This allows a custom + mapping to be used to ensure that the new copy is placed in the + right cache sets for the user to see it without having to bounce it + out via memory. Note however : the call to flush_page_to_ram in + (generic)/mm/memory.c:(break_cow) undoes all this good work in that one + very important case! + + TBD : can we guarantee that on every call, any cache entries for + 'from' are in the same colour sets as 'address' also? i.e. is this + always used just to deal with COW? (I suspect not). */ + + /* There are two possibilities here for when the page 'from' was last accessed: + * by the kernel : this is OK, no purge required. + * by the/a user (e.g. for break_COW) : need to purge. + + If the potential user mapping at 'address' is the same colour as + 'from' there is no need to purge any cache lines from the 'from' + page mapped into cache sets of colour 'address'. (The copy will be + accessing the page through 'from'). + */ + + if (((address ^ (unsigned long) from) & CACHE_OC_SYN_MASK) != 0) { + sh64_dcache_purge_coloured_phy_page(__pa(from), address); + } + + if (((address ^ (unsigned long) to) & CACHE_OC_SYN_MASK) == 0) { + /* No synonym problem on destination */ + sh64_page_copy(from, to); + } else { + sh64_copy_user_page_coloured(to, from, address); + } + + /* Note, don't need to flush 'from' page from the cache again - it's + done anyway by the generic code */ +} + +void clear_user_page(void *to, unsigned long address, struct page *page) +{ + /* 'to' is a kernel virtual address (within the superpage + mapping of the physical RAM). 'address' is the user virtual address + where the 'to' page will be mapped after. This allows a custom + mapping to be used to ensure that the new copy is placed in the + right cache sets for the user to see it without having to bounce it + out via memory. + */ + + if (((address ^ (unsigned long) to) & CACHE_OC_SYN_MASK) == 0) { + /* No synonym problem on destination */ + sh64_page_clear(to); + } else { + sh64_clear_user_page_coloured(to, address); + } +} + +#endif /* !CONFIG_DCACHE_DISABLED */ + +/****************************************************************************/ + +void flush_dcache_page(struct page *page) +{ + sh64_dcache_purge_phy_page(page_to_phys(page)); + wmb(); +} + +/****************************************************************************/ + +void flush_icache_range(unsigned long start, unsigned long end) +{ + /* Flush the range [start,end] of kernel virtual adddress space from + the I-cache. The corresponding range must be purged from the + D-cache also because the SH-5 doesn't have cache snooping between + the caches. The addresses will be visible through the superpage + mapping, therefore it's guaranteed that there no cache entries for + the range in cache sets of the wrong colour. + + Primarily used for cohering the I-cache after a module has + been loaded. */ + + /* We also make sure to purge the same range from the D-cache since + flush_page_to_ram() won't be doing this for us! */ + + sh64_dcache_purge_kernel_range(start, end); + wmb(); + sh64_icache_inv_kernel_range(start, end); +} + +/****************************************************************************/ + +void flush_icache_user_range(struct vm_area_struct *vma, + struct page *page, unsigned long addr, int len) +{ + /* Flush the range of user (defined by vma->vm_mm) address space + starting at 'addr' for 'len' bytes from the cache. The range does + not straddle a page boundary, the unique physical page containing + the range is 'page'. This seems to be used mainly for invalidating + an address range following a poke into the program text through the + ptrace() call from another process (e.g. for BRK instruction + insertion). */ + + sh64_dcache_purge_coloured_phy_page(page_to_phys(page), addr); + mb(); + + if (vma->vm_flags & VM_EXEC) { + sh64_icache_inv_user_small_range(vma->vm_mm, addr, len); + } +} + +/*########################################################################## + ARCH/SH64 PRIVATE CALLABLE API. + ##########################################################################*/ + +void flush_cache_sigtramp(unsigned long start, unsigned long end) +{ + /* For the address range [start,end), write back the data from the + D-cache and invalidate the corresponding region of the I-cache for + the current process. Used to flush signal trampolines on the stack + to make them executable. */ + + sh64_dcache_wback_current_user_range(start, end); + wmb(); + sh64_icache_inv_current_user_range(start, end); +} + diff -puN /dev/null arch/sh64/mm/extable.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/mm/extable.c 2004-06-28 13:30:30.714134584 -0700 @@ -0,0 +1,80 @@ +/* + * 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. + * + * arch/sh64/mm/extable.c + * + * Copyright (C) 2003 Richard Curnow + * Copyright (C) 2003, 2004 Paul Mundt + * + * Cloned from the 2.5 SH version.. + */ +#include +#include +#include +#include + +extern unsigned long copy_user_memcpy, copy_user_memcpy_end, __copy_user_fixup; + +static const struct exception_table_entry __copy_user_fixup_ex = { + .fixup = (unsigned long)&__copy_user_fixup, +}; + +/* Some functions that may trap due to a bad user-mode address have too many loads + and stores in them to make it at all practical to label each one and put them all in + the main exception table. + + In particular, the fast memcpy routine is like this. It's fix-up is just to fall back + to a slow byte-at-a-time copy, which is handled the conventional way. So it's functionally + OK to just handle any trap occurring in the fast memcpy with that fixup. */ +static const struct exception_table_entry *check_exception_ranges(unsigned long addr) +{ + if ((addr >= (unsigned long)©_user_memcpy) && + (addr <= (unsigned long)©_user_memcpy_end)) + return &__copy_user_fixup_ex; + + return NULL; +} + +/* Simple binary search */ +const struct exception_table_entry * +search_extable(const struct exception_table_entry *first, + const struct exception_table_entry *last, + unsigned long value) +{ + const struct exception_table_entry *mid; + + mid = check_exception_ranges(value); + if (mid) + return mid; + + while (first <= last) { + long diff; + + mid = (last - first) / 2 + first; + diff = mid->insn - value; + if (diff == 0) + return mid; + else if (diff < 0) + first = mid+1; + else + last = mid-1; + } + + return NULL; +} + +int fixup_exception(struct pt_regs *regs) +{ + const struct exception_table_entry *fixup; + + fixup = search_exception_tables(regs->pc); + if (fixup) { + regs->pc = fixup->fixup; + return 1; + } + + return 0; +} + diff -puN /dev/null arch/sh64/mm/fault.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/mm/fault.c 2004-06-28 13:30:30.716134280 -0700 @@ -0,0 +1,591 @@ +/* + * 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. + * + * arch/sh64/mm/fault.c + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003 Richard Curnow (/proc/tlb, bug fixes) + * Copyright (C) 2003 Paul Mundt + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include /* required by inline asm statements */ + +#if defined(CONFIG_SH64_PROC_TLB) +#include +#include +/* Count numbers of tlb refills in each region */ +static unsigned long long calls_to_update_mmu_cache = 0ULL; +static unsigned long long calls_to_flush_tlb_page = 0ULL; +static unsigned long long calls_to_flush_tlb_range = 0ULL; +static unsigned long long calls_to_flush_tlb_mm = 0ULL; +static unsigned long long calls_to_flush_tlb_all = 0ULL; +unsigned long long calls_to_do_slow_page_fault = 0ULL; +unsigned long long calls_to_do_fast_page_fault = 0ULL; + +/* Count size of ranges for flush_tlb_range */ +static unsigned long long flush_tlb_range_1 = 0ULL; +static unsigned long long flush_tlb_range_2 = 0ULL; +static unsigned long long flush_tlb_range_3_4 = 0ULL; +static unsigned long long flush_tlb_range_5_7 = 0ULL; +static unsigned long long flush_tlb_range_8_11 = 0ULL; +static unsigned long long flush_tlb_range_12_15 = 0ULL; +static unsigned long long flush_tlb_range_16_up = 0ULL; + +static unsigned long long page_not_present = 0ULL; + +#endif + +extern void die(const char *,struct pt_regs *,long); + +#define PFLAG(val,flag) (( (val) & (flag) ) ? #flag : "" ) +#define PPROT(flag) PFLAG(pgprot_val(prot),flag) + +static inline void print_prots(pgprot_t prot) +{ + printk("prot is 0x%08lx\n",pgprot_val(prot)); + + printk("%s %s %s %s %s\n",PPROT(_PAGE_SHARED),PPROT(_PAGE_READ), + PPROT(_PAGE_EXECUTE),PPROT(_PAGE_WRITE),PPROT(_PAGE_USER)); +} + +static inline void print_vma(struct vm_area_struct *vma) +{ + printk("vma start 0x%08lx\n", vma->vm_start); + printk("vma end 0x%08lx\n", vma->vm_end); + + print_prots(vma->vm_page_prot); + printk("vm_flags 0x%08lx\n", vma->vm_flags); +} + +static inline void print_task(struct task_struct *tsk) +{ + printk("Task pid %d\n", tsk->pid); +} + +static pte_t *lookup_pte(struct mm_struct *mm, unsigned long address) +{ + pgd_t *dir; + pmd_t *pmd; + pte_t *pte; + pte_t entry; + + dir = pgd_offset(mm, address); + if (pgd_none(*dir)) { + return NULL; + } + + pmd = pmd_offset(dir, address); + if (pmd_none(*pmd)) { + return NULL; + } + + pte = pte_offset_kernel(pmd, address); + entry = *pte; + + if (pte_none(entry)) { + return NULL; + } + if (!pte_present(entry)) { + return NULL; + } + + return pte; +} + +/* + * This routine handles page faults. It determines the address, + * and the problem, and then passes it off to one of the appropriate + * routines. + */ +asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess, + unsigned long textaccess, unsigned long address) +{ + struct task_struct *tsk; + struct mm_struct *mm; + struct vm_area_struct * vma; + const struct exception_table_entry *fixup; + pte_t *pte; + +#if defined(CONFIG_SH64_PROC_TLB) + ++calls_to_do_slow_page_fault; +#endif + + /* SIM + * Note this is now called with interrupts still disabled + * This is to cope with being called for a missing IO port + * address with interupts disabled. This should be fixed as + * soon as we have a better 'fast path' miss handler. + * + * Plus take care how you try and debug this stuff. + * For example, writing debug data to a port which you + * have just faulted on is not going to work. + */ + + tsk = current; + mm = tsk->mm; + + /* Not an IO address, so reenable interrupts */ + sti(); + + /* + * If we're in an interrupt or have no user + * context, we must not take the fault.. + */ + if (in_interrupt() || !mm) + goto no_context; + + /* TLB misses upon some cache flushes get done under cli() */ + down_read(&mm->mmap_sem); + + vma = find_vma(mm, address); + + if (!vma) { +#ifdef DEBUG_FAULT + print_task(tsk); + printk("%s:%d fault, address is 0x%08x PC %016Lx textaccess %d writeaccess %d\n", + __FUNCTION__,__LINE__, + address,regs->pc,textaccess,writeaccess); + show_regs(regs); +#endif + goto bad_area; + } + if (vma->vm_start <= address) { + goto good_area; + } + + if (!(vma->vm_flags & VM_GROWSDOWN)) { +#ifdef DEBUG_FAULT + print_task(tsk); + printk("%s:%d fault, address is 0x%08x PC %016Lx textaccess %d writeaccess %d\n", + __FUNCTION__,__LINE__, + address,regs->pc,textaccess,writeaccess); + show_regs(regs); + + print_vma(vma); +#endif + goto bad_area; + } + if (expand_stack(vma, address)) { +#ifdef DEBUG_FAULT + print_task(tsk); + printk("%s:%d fault, address is 0x%08x PC %016Lx textaccess %d writeaccess %d\n", + __FUNCTION__,__LINE__, + address,regs->pc,textaccess,writeaccess); + show_regs(regs); +#endif + goto bad_area; + } +/* + * Ok, we have a good vm_area for this memory access, so + * we can handle it.. + */ +good_area: + if (writeaccess) { + if (!(vma->vm_flags & VM_WRITE)) + goto bad_area; + } else { + if (!(vma->vm_flags & (VM_READ | VM_EXEC))) + goto bad_area; + } + + if (textaccess) { + if (!(vma->vm_flags & VM_EXEC)) + goto bad_area; + } + + /* + * If for any reason at all we couldn't handle the fault, + * make sure we exit gracefully rather than endlessly redo + * the fault. + */ +survive: + switch (handle_mm_fault(mm, vma, address, writeaccess)) { + case 1: + tsk->min_flt++; + break; + case 2: + tsk->maj_flt++; + break; + case 0: + goto do_sigbus; + default: + goto out_of_memory; + } + /* If we get here, the page fault has been handled. Do the TLB refill + now from the newly-setup PTE, to avoid having to fault again right + away on the same instruction. */ + pte = lookup_pte (mm, address); + if (!pte) { + /* From empirical evidence, we can get here, due to + !pte_present(pte). (e.g. if a swap-in occurs, and the page + is swapped back out again before the process that wanted it + gets rescheduled?) */ + goto no_pte; + } + + __do_tlb_refill(address, textaccess, pte); + +no_pte: + + up_read(&mm->mmap_sem); + return; + +/* + * Something tried to access memory that isn't in our memory map.. + * Fix it, but check if it's kernel or user first.. + */ +bad_area: +#ifdef DEBUG_FAULT + printk("fault:bad area\n"); +#endif + up_read(&mm->mmap_sem); + + if (user_mode(regs)) { + printk("user mode bad_area address=%08lx pid=%d (%s) pc=%08lx opcode=%08lx\n", + address, current->pid, current->comm, + (unsigned long) regs->pc, + *(unsigned long *)(u32)(regs->pc & ~3)); + show_regs(regs); + if (tsk->pid == 1) { + panic("INIT had user mode bad_area\n"); + } + tsk->thread.address = address; + tsk->thread.error_code = writeaccess; + force_sig(SIGSEGV, tsk); + return; + } + +no_context: +#ifdef DEBUG_FAULT + printk("fault:No context\n"); +#endif + /* Are we prepared to handle this kernel fault? */ + fixup = search_exception_tables(regs->pc); + if (fixup) { + regs->pc = fixup->fixup; + return; + } + +/* + * Oops. The kernel tried to access some bad page. We'll have to + * terminate things with extreme prejudice. + * + */ + if (address < PAGE_SIZE) + printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); + else + printk(KERN_ALERT "Unable to handle kernel paging request"); + printk(" at virtual address %08lx\n", address); + printk(KERN_ALERT "pc = %08Lx%08Lx\n", regs->pc >> 32, regs->pc & 0xffffffff); + die("Oops", regs, writeaccess); + do_exit(SIGKILL); + +/* + * We ran out of memory, or some other thing happened to us that made + * us unable to handle the page fault gracefully. + */ +out_of_memory: + if (current->pid == 1) { + panic("INIT out of memory\n"); + yield(); + goto survive; + } + printk("fault:Out of memory\n"); + up_read(&mm->mmap_sem); + if (current->pid == 1) { + yield(); + down_read(&mm->mmap_sem); + goto survive; + } + printk("VM: killing process %s\n", tsk->comm); + if (user_mode(regs)) + do_exit(SIGKILL); + goto no_context; + +do_sigbus: + printk("fault:Do sigbus\n"); + up_read(&mm->mmap_sem); + + /* + * Send a sigbus, regardless of whether we were in kernel + * or user mode. + */ + tsk->thread.address = address; + tsk->thread.error_code = writeaccess; + tsk->thread.trap_no = 14; + force_sig(SIGBUS, tsk); + + /* Kernel mode? Handle exceptions or die */ + if (!user_mode(regs)) + goto no_context; +} + + +void flush_tlb_all(void); + +void update_mmu_cache(struct vm_area_struct * vma, + unsigned long address, pte_t pte) +{ +#if defined(CONFIG_SH64_PROC_TLB) + ++calls_to_update_mmu_cache; +#endif + + /* + * This appears to get called once for every pte entry that gets + * established => I don't think it's efficient to try refilling the + * TLBs with the pages - some may not get accessed even. Also, for + * executable pages, it is impossible to determine reliably here which + * TLB they should be mapped into (or both even). + * + * So, just do nothing here and handle faults on demand. In the + * TLBMISS handling case, the refill is now done anyway after the pte + * has been fixed up, so that deals with most useful cases. + */ +} + +static void __flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +{ + unsigned long long match, pteh=0, lpage; + unsigned long tlb; + struct mm_struct *mm; + + mm = vma->vm_mm; + + if (mm->context == NO_CONTEXT) + return; + + /* + * Sign-extend based on neff. + */ + lpage = (page & NEFF_SIGN) ? (page | NEFF_MASK) : page; + match = ((mm->context & MMU_CONTEXT_ASID_MASK) << PTEH_ASID_SHIFT) | PTEH_VALID; + match |= lpage; + + /* Do ITLB : don't bother for pages in non-exectutable VMAs */ + if (vma->vm_flags & VM_EXEC) { + for_each_itlb_entry(tlb) { + asm volatile ("getcfg %1, 0, %0" + : "=r" (pteh) + : "r" (tlb) ); + + if (pteh == match) { + __flush_tlb_slot(tlb); + break; + } + + } + } + + /* Do DTLB : any page could potentially be in here. */ + for_each_dtlb_entry(tlb) { + asm volatile ("getcfg %1, 0, %0" + : "=r" (pteh) + : "r" (tlb) ); + + if (pteh == match) { + __flush_tlb_slot(tlb); + break; + } + + } +} + +void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +{ + unsigned long flags; + +#if defined(CONFIG_SH64_PROC_TLB) + ++calls_to_flush_tlb_page; +#endif + + if (vma->vm_mm) { + page &= PAGE_MASK; + local_irq_save(flags); + __flush_tlb_page(vma, page); + local_irq_restore(flags); + } +} + +void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end) +{ + unsigned long flags; + unsigned long long match, pteh=0, pteh_epn, pteh_low; + unsigned long tlb; + struct mm_struct *mm; + + mm = vma->vm_mm; + +#if defined(CONFIG_SH64_PROC_TLB) + ++calls_to_flush_tlb_range; + + { + unsigned long size = (end - 1) - start; + size >>= 12; /* divide by PAGE_SIZE */ + size++; /* end=start+4096 => 1 page */ + switch (size) { + case 1 : flush_tlb_range_1++; break; + case 2 : flush_tlb_range_2++; break; + case 3 ... 4 : flush_tlb_range_3_4++; break; + case 5 ... 7 : flush_tlb_range_5_7++; break; + case 8 ... 11 : flush_tlb_range_8_11++; break; + case 12 ... 15 : flush_tlb_range_12_15++; break; + default : flush_tlb_range_16_up++; break; + } + } +#endif + + if (mm->context == NO_CONTEXT) + return; + + local_irq_save(flags); + + start &= PAGE_MASK; + end &= PAGE_MASK; + + match = ((mm->context & MMU_CONTEXT_ASID_MASK) << PTEH_ASID_SHIFT) | PTEH_VALID; + + /* Flush ITLB */ + for_each_itlb_entry(tlb) { + asm volatile ("getcfg %1, 0, %0" + : "=r" (pteh) + : "r" (tlb) ); + + pteh_epn = pteh & PAGE_MASK; + pteh_low = pteh & ~PAGE_MASK; + + if (pteh_low == match && pteh_epn >= start && pteh_epn <= end) + __flush_tlb_slot(tlb); + } + + /* Flush DTLB */ + for_each_dtlb_entry(tlb) { + asm volatile ("getcfg %1, 0, %0" + : "=r" (pteh) + : "r" (tlb) ); + + pteh_epn = pteh & PAGE_MASK; + pteh_low = pteh & ~PAGE_MASK; + + if (pteh_low == match && pteh_epn >= start && pteh_epn <= end) + __flush_tlb_slot(tlb); + } + + local_irq_restore(flags); +} + +void flush_tlb_mm(struct mm_struct *mm) +{ + unsigned long flags; + +#if defined(CONFIG_SH64_PROC_TLB) + ++calls_to_flush_tlb_mm; +#endif + + if (mm->context == NO_CONTEXT) + return; + + local_irq_save(flags); + + mm->context=NO_CONTEXT; + if(mm==current->mm) + activate_context(mm); + + local_irq_restore(flags); + +} + +void flush_tlb_all(void) +{ + /* Invalidate all, including shared pages, excluding fixed TLBs */ + + unsigned long flags, tlb; + +#if defined(CONFIG_SH64_PROC_TLB) + ++calls_to_flush_tlb_all; +#endif + + local_irq_save(flags); + + /* Flush each ITLB entry */ + for_each_itlb_entry(tlb) { + __flush_tlb_slot(tlb); + } + + /* Flush each DTLB entry */ + for_each_dtlb_entry(tlb) { + __flush_tlb_slot(tlb); + } + + local_irq_restore(flags); +} + +void flush_tlb_kernel_range(unsigned long start, unsigned long end) +{ + /* FIXME: Optimize this later.. */ + flush_tlb_all(); +} + +#if defined(CONFIG_SH64_PROC_TLB) +/* Procfs interface to read the performance information */ + +static int +tlb_proc_info(char *buf, char **start, off_t fpos, int length, int *eof, void *data) +{ + int len=0; + len += sprintf(buf+len, "do_fast_page_fault called %12lld times\n", calls_to_do_fast_page_fault); + len += sprintf(buf+len, "do_slow_page_fault called %12lld times\n", calls_to_do_slow_page_fault); + len += sprintf(buf+len, "update_mmu_cache called %12lld times\n", calls_to_update_mmu_cache); + len += sprintf(buf+len, "flush_tlb_page called %12lld times\n", calls_to_flush_tlb_page); + len += sprintf(buf+len, "flush_tlb_range called %12lld times\n", calls_to_flush_tlb_range); + len += sprintf(buf+len, "flush_tlb_mm called %12lld times\n", calls_to_flush_tlb_mm); + len += sprintf(buf+len, "flush_tlb_all called %12lld times\n", calls_to_flush_tlb_all); + len += sprintf(buf+len, "flush_tlb_range_sizes\n" + " 1 : %12lld\n" + " 2 : %12lld\n" + " 3 - 4 : %12lld\n" + " 5 - 7 : %12lld\n" + " 8 - 11 : %12lld\n" + "12 - 15 : %12lld\n" + "16+ : %12lld\n", + flush_tlb_range_1, flush_tlb_range_2, flush_tlb_range_3_4, + flush_tlb_range_5_7, flush_tlb_range_8_11, flush_tlb_range_12_15, + flush_tlb_range_16_up); + len += sprintf(buf+len, "page not present %12lld times\n", page_not_present); + *eof = 1; + return len; +} + +static int __init register_proc_tlb(void) +{ + create_proc_read_entry("tlb", 0, NULL, tlb_proc_info, NULL); + return 0; +} + +__initcall(register_proc_tlb); + +#endif diff -puN /dev/null arch/sh64/mm/hugetlbpage.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/mm/hugetlbpage.c 2004-06-28 13:30:30.717134128 -0700 @@ -0,0 +1,264 @@ +/* + * arch/sh64/mm/hugetlbpage.c + * + * SuperH HugeTLB page support. + * + * Cloned from sparc64 by Paul Mundt. + * + * Copyright (C) 2002, 2003 David S. Miller (davem@redhat.com) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte = NULL; + + pgd = pgd_offset(mm, addr); + if (pgd) { + pmd = pmd_alloc(mm, pgd, addr); + if (pmd) + pte = pte_alloc_map(mm, pmd, addr); + } + return pte; +} + +static pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte = NULL; + + pgd = pgd_offset(mm, addr); + if (pgd) { + pmd = pmd_offset(pgd, addr); + if (pmd) + pte = pte_offset_map(pmd, addr); + } + return pte; +} + +#define mk_pte_huge(entry) do { pte_val(entry) |= _PAGE_SZHUGE; } while (0) + +static void set_huge_pte(struct mm_struct *mm, struct vm_area_struct *vma, + struct page *page, pte_t * page_table, int write_access) +{ + unsigned long i; + pte_t entry; + + mm->rss += (HPAGE_SIZE / PAGE_SIZE); + + if (write_access) + entry = pte_mkwrite(pte_mkdirty(mk_pte(page, + vma->vm_page_prot))); + else + entry = pte_wrprotect(mk_pte(page, vma->vm_page_prot)); + entry = pte_mkyoung(entry); + mk_pte_huge(entry); + + for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) { + set_pte(page_table, entry); + page_table++; + + pte_val(entry) += PAGE_SIZE; + } +} + +/* + * This function checks for proper alignment of input addr and len parameters. + */ +int is_aligned_hugepage_range(unsigned long addr, unsigned long len) +{ + if (len & ~HPAGE_MASK) + return -EINVAL; + if (addr & ~HPAGE_MASK) + return -EINVAL; + return 0; +} + +int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src, + struct vm_area_struct *vma) +{ + pte_t *src_pte, *dst_pte, entry; + struct page *ptepage; + unsigned long addr = vma->vm_start; + unsigned long end = vma->vm_end; + int i; + + while (addr < end) { + dst_pte = huge_pte_alloc(dst, addr); + if (!dst_pte) + goto nomem; + src_pte = huge_pte_offset(src, addr); + BUG_ON(!src_pte || pte_none(*src_pte)); + entry = *src_pte; + ptepage = pte_page(entry); + get_page(ptepage); + for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) { + set_pte(dst_pte, entry); + pte_val(entry) += PAGE_SIZE; + dst_pte++; + } + dst->rss += (HPAGE_SIZE / PAGE_SIZE); + addr += HPAGE_SIZE; + } + return 0; + +nomem: + return -ENOMEM; +} + +int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, + struct page **pages, struct vm_area_struct **vmas, + unsigned long *position, int *length, int i) +{ + unsigned long vaddr = *position; + int remainder = *length; + + WARN_ON(!is_vm_hugetlb_page(vma)); + + while (vaddr < vma->vm_end && remainder) { + if (pages) { + pte_t *pte; + struct page *page; + + pte = huge_pte_offset(mm, vaddr); + + /* hugetlb should be locked, and hence, prefaulted */ + BUG_ON(!pte || pte_none(*pte)); + + page = pte_page(*pte); + + WARN_ON(!PageCompound(page)); + + get_page(page); + pages[i] = page; + } + + if (vmas) + vmas[i] = vma; + + vaddr += PAGE_SIZE; + --remainder; + ++i; + } + + *length = remainder; + *position = vaddr; + + return i; +} + +struct page *follow_huge_addr(struct mm_struct *mm, + unsigned long address, int write) +{ + return ERR_PTR(-EINVAL); +} + +int pmd_huge(pmd_t pmd) +{ + return 0; +} + +struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address, + pmd_t *pmd, int write) +{ + return NULL; +} + +void unmap_hugepage_range(struct vm_area_struct *vma, + unsigned long start, unsigned long end) +{ + struct mm_struct *mm = vma->vm_mm; + unsigned long address; + pte_t *pte; + struct page *page; + int i; + + BUG_ON(start & (HPAGE_SIZE - 1)); + BUG_ON(end & (HPAGE_SIZE - 1)); + + for (address = start; address < end; address += HPAGE_SIZE) { + pte = huge_pte_offset(mm, address); + BUG_ON(!pte); + if (pte_none(*pte)) + continue; + page = pte_page(*pte); + put_page(page); + for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) { + pte_clear(pte); + pte++; + } + } + mm->rss -= (end - start) >> PAGE_SHIFT; + flush_tlb_range(vma, start, end); +} + +int hugetlb_prefault(struct address_space *mapping, struct vm_area_struct *vma) +{ + struct mm_struct *mm = current->mm; + unsigned long addr; + int ret = 0; + + BUG_ON(vma->vm_start & ~HPAGE_MASK); + BUG_ON(vma->vm_end & ~HPAGE_MASK); + + spin_lock(&mm->page_table_lock); + for (addr = vma->vm_start; addr < vma->vm_end; addr += HPAGE_SIZE) { + unsigned long idx; + pte_t *pte = huge_pte_alloc(mm, addr); + struct page *page; + + if (!pte) { + ret = -ENOMEM; + goto out; + } + if (!pte_none(*pte)) + continue; + + idx = ((addr - vma->vm_start) >> HPAGE_SHIFT) + + (vma->vm_pgoff >> (HPAGE_SHIFT - PAGE_SHIFT)); + page = find_get_page(mapping, idx); + if (!page) { + /* charge the fs quota first */ + if (hugetlb_get_quota(mapping)) { + ret = -ENOMEM; + goto out; + } + page = alloc_huge_page(); + if (!page) { + hugetlb_put_quota(mapping); + ret = -ENOMEM; + goto out; + } + ret = add_to_page_cache(page, mapping, idx, GFP_ATOMIC); + if (! ret) { + unlock_page(page); + } else { + hugetlb_put_quota(mapping); + free_huge_page(page); + goto out; + } + } + set_huge_pte(mm, vma, page, pte, vma->vm_flags & VM_WRITE); + } +out: + spin_unlock(&mm->page_table_lock); + return ret; +} diff -puN /dev/null arch/sh64/mm/init.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/mm/init.c 2004-06-28 13:30:30.719133824 -0700 @@ -0,0 +1,199 @@ +/* + * 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. + * + * arch/sh64/mm/init.c + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003, 2004 Paul Mundt + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef CONFIG_BLK_DEV_INITRD +#include +#endif + +DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); + +/* + * Cache of MMU context last used. + */ +unsigned long mmu_context_cache; +pgd_t * mmu_pdtp_cache; +int after_bootmem = 0; + +/* + * BAD_PAGE is the page that is used for page faults when linux + * is out-of-memory. Older versions of linux just did a + * do_exit(), but using this instead means there is less risk + * for a process dying in kernel mode, possibly leaving an inode + * unused etc.. + * + * BAD_PAGETABLE is the accompanying page-table: it is initialized + * to point to BAD_PAGE entries. + * + * ZERO_PAGE is a special page that is used for zero-initialized + * data and COW. + */ + +extern unsigned char empty_zero_page[PAGE_SIZE]; +extern unsigned char empty_bad_page[PAGE_SIZE]; +extern pte_t empty_bad_pte_table[PTRS_PER_PTE]; +extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; + +extern char _text, _etext, _edata, __bss_start, _end; +extern char __init_begin, __init_end; + +/* It'd be good if these lines were in the standard header file. */ +#define START_PFN (NODE_DATA(0)->bdata->node_boot_start >> PAGE_SHIFT) +#define MAX_LOW_PFN (NODE_DATA(0)->bdata->node_low_pfn) + + +void show_mem(void) +{ + int i, total = 0, reserved = 0; + int shared = 0, cached = 0; + + printk("Mem-info:\n"); + show_free_areas(); + printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); + i = max_mapnr; + while (i-- > 0) { + total++; + if (PageReserved(mem_map+i)) + reserved++; + else if (PageSwapCache(mem_map+i)) + cached++; + else if (page_count(mem_map+i)) + shared += page_count(mem_map+i) - 1; + } + printk("%d pages of RAM\n",total); + printk("%d reserved pages\n",reserved); + printk("%d pages shared\n",shared); + printk("%d pages swap cached\n",cached); + printk("%ld pages in page table cache\n",pgtable_cache_size); +} + +/* + * paging_init() sets up the page tables. + * + * head.S already did a lot to set up address translation for the kernel. + * Here we comes with: + * . MMU enabled + * . ASID set (SR) + * . some 512MB regions being mapped of which the most relevant here is: + * . CACHED segment (ASID 0 [irrelevant], shared AND NOT user) + * . possible variable length regions being mapped as: + * . UNCACHED segment (ASID 0 [irrelevant], shared AND NOT user) + * . All of the memory regions are placed, independently from the platform + * on high addresses, above 0x80000000. + * . swapper_pg_dir is already cleared out by the .space directive + * in any case swapper does not require a real page directory since + * it's all kernel contained. + * + * Those pesky NULL-reference errors in the kernel are then + * dealt with by not mapping address 0x00000000 at all. + * + */ +void __init paging_init(void) +{ + unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0}; + + pgd_init((unsigned long)swapper_pg_dir); + pgd_init((unsigned long)swapper_pg_dir + + sizeof(pgd_t) * USER_PTRS_PER_PGD); + + mmu_context_cache = MMU_CONTEXT_FIRST_VERSION; + + /* + * All memory is good as ZONE_NORMAL (fall-through) and ZONE_DMA. + */ + zones_size[ZONE_DMA] = MAX_LOW_PFN - START_PFN; + + free_area_init_node(0, NODE_DATA(0), 0, zones_size, __MEMORY_START >> PAGE_SHIFT, 0); + + /* XXX: MRB-remove - this doesn't seem sane, should this be done somewhere else ?*/ + mem_map = NODE_DATA(0)->node_mem_map; +} + +void __init mem_init(void) +{ + int codesize, reservedpages, datasize, initsize; + int tmp; + + max_mapnr = num_physpages = MAX_LOW_PFN - START_PFN; + high_memory = (void *)__va(MAX_LOW_PFN * PAGE_SIZE); + + /* + * Clear the zero-page. + * This is not required but we might want to re-use + * this very page to pass boot parameters, one day. + */ + memset(empty_zero_page, 0, PAGE_SIZE); + + /* this will put all low memory onto the freelists */ + totalram_pages += free_all_bootmem_node(NODE_DATA(0)); + reservedpages = 0; + for (tmp = 0; tmp < num_physpages; tmp++) + /* + * Only count reserved RAM pages + */ + if (PageReserved(mem_map+tmp)) + reservedpages++; + + after_bootmem = 1; + + codesize = (unsigned long) &_etext - (unsigned long) &_text; + datasize = (unsigned long) &_edata - (unsigned long) &_etext; + initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; + + printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init)\n", + (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), + max_mapnr << (PAGE_SHIFT-10), + codesize >> 10, + reservedpages << (PAGE_SHIFT-10), + datasize >> 10, + initsize >> 10); +} + +void free_initmem(void) +{ + unsigned long addr; + + addr = (unsigned long)(&__init_begin); + for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) { + ClearPageReserved(virt_to_page(addr)); + set_page_count(virt_to_page(addr), 1); + free_page(addr); + totalram_pages++; + } + printk ("Freeing unused kernel memory: %ldk freed\n", (&__init_end - &__init_begin) >> 10); +} + +#ifdef CONFIG_BLK_DEV_INITRD +void free_initrd_mem(unsigned long start, unsigned long end) +{ + unsigned long p; + for (p = start; p < end; p += PAGE_SIZE) { + ClearPageReserved(virt_to_page(p)); + set_page_count(virt_to_page(p), 1); + free_page(p); + totalram_pages++; + } + printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); +} +#endif + diff -puN /dev/null arch/sh64/mm/ioremap.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/mm/ioremap.c 2004-06-28 13:30:30.721133520 -0700 @@ -0,0 +1,469 @@ +/* + * 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. + * + * arch/sh64/mm/ioremap.c + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003, 2004 Paul Mundt + * + * Mostly derived from arch/sh/mm/ioremap.c which, in turn is mostly + * derived from arch/i386/mm/ioremap.c . + * + * (C) Copyright 1995 1996 Linus Torvalds + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void shmedia_mapioaddr(unsigned long, unsigned long); +static unsigned long shmedia_ioremap(struct resource *, u32, int); + +static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size, + unsigned long phys_addr, unsigned long flags) +{ + unsigned long end; + unsigned long pfn; + pgprot_t pgprot = __pgprot(_PAGE_PRESENT | _PAGE_READ | + _PAGE_WRITE | _PAGE_DIRTY | + _PAGE_ACCESSED | _PAGE_SHARED | flags); + + address &= ~PMD_MASK; + end = address + size; + if (end > PMD_SIZE) + end = PMD_SIZE; + if (address >= end) + BUG(); + + pfn = phys_addr >> PAGE_SHIFT; + + pr_debug(" %s: pte %p address %lx size %lx phys_addr %lx\n", + __FUNCTION__,pte,address,size,phys_addr); + + do { + if (!pte_none(*pte)) { + printk("remap_area_pte: page already exists\n"); + BUG(); + } + + set_pte(pte, pfn_pte(pfn, pgprot)); + address += PAGE_SIZE; + pfn++; + pte++; + } while (address && (address < end)); +} + +static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size, + unsigned long phys_addr, unsigned long flags) +{ + unsigned long end; + + address &= ~PGDIR_MASK; + end = address + size; + + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + + phys_addr -= address; + + if (address >= end) + BUG(); + + do { + pte_t * pte = pte_alloc_kernel(&init_mm, pmd, address); + if (!pte) + return -ENOMEM; + remap_area_pte(pte, address, end - address, address + phys_addr, flags); + address = (address + PMD_SIZE) & PMD_MASK; + pmd++; + } while (address && (address < end)); + return 0; +} + +static int remap_area_pages(unsigned long address, unsigned long phys_addr, + unsigned long size, unsigned long flags) +{ + int error; + pgd_t * dir; + unsigned long end = address + size; + + phys_addr -= address; + dir = pgd_offset_k(address); + flush_cache_all(); + if (address >= end) + BUG(); + spin_lock(&init_mm.page_table_lock); + do { + pmd_t *pmd = pmd_alloc(&init_mm, dir, address); + error = -ENOMEM; + if (!pmd) + break; + if (remap_area_pmd(pmd, address, end - address, + phys_addr + address, flags)) { + break; + } + error = 0; + address = (address + PGDIR_SIZE) & PGDIR_MASK; + dir++; + } while (address && (address < end)); + spin_unlock(&init_mm.page_table_lock); + flush_tlb_all(); + return 0; +} + +/* + * Generic mapping function (not visible outside): + */ + +/* + * Remap an arbitrary physical address space into the kernel virtual + * address space. Needed when the kernel wants to access high addresses + * directly. + * + * NOTE! We need to allow non-page-aligned mappings too: we will obviously + * have to convert them into an offset in a page-aligned mapping, but the + * caller shouldn't need to know that small detail. + */ +void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags) +{ + void * addr; + struct vm_struct * area; + unsigned long offset, last_addr; + + /* Don't allow wraparound or zero size */ + last_addr = phys_addr + size - 1; + if (!size || last_addr < phys_addr) + return NULL; + + /* + * Mappings have to be page-aligned + */ + offset = phys_addr & ~PAGE_MASK; + phys_addr &= PAGE_MASK; + size = PAGE_ALIGN(last_addr + 1) - phys_addr; + + /* + * Ok, go for it.. + */ + area = get_vm_area(size, VM_IOREMAP); + pr_debug("Get vm_area returns %p addr %p\n",area,area->addr); + if (!area) + return NULL; + area->phys_addr = phys_addr; + addr = area->addr; + if (remap_area_pages((unsigned long)addr, phys_addr, size, flags)) { + vunmap(addr); + return NULL; + } + return (void *) (offset + (char *)addr); +} + +void iounmap(void *addr) +{ + struct vm_struct *area; + + vfree((void *) (PAGE_MASK & (unsigned long) addr)); + area = remove_vm_area((void *) (PAGE_MASK & (unsigned long) addr)); + if (!area) { + printk(KERN_ERR "iounmap: bad address %p\n", addr); + return; + } + + kfree(area); +} + +static struct resource shmedia_iomap = { + .name = "shmedia_iomap", + .start = IOBASE_VADDR, + .end = IOBASE_END - 1, +}; + +static void shmedia_mapioaddr(unsigned long pa, unsigned long va); +static void shmedia_unmapioaddr(unsigned long vaddr); +static unsigned long shmedia_ioremap(struct resource *res, u32 pa, int sz); + +/* + * We have the same problem as the SPARC, so lets have the same comment: + * Our mini-allocator... + * Boy this is gross! We need it because we must map I/O for + * timers and interrupt controller before the kmalloc is available. + */ + +#define XNMLN 15 +#define XNRES 10 + +struct xresource { + struct resource xres; /* Must be first */ + int xflag; /* 1 == used */ + char xname[XNMLN+1]; +}; + +static struct xresource xresv[XNRES]; + +static struct xresource *xres_alloc(void) +{ + struct xresource *xrp; + int n; + + xrp = xresv; + for (n = 0; n < XNRES; n++) { + if (xrp->xflag == 0) { + xrp->xflag = 1; + return xrp; + } + xrp++; + } + return NULL; +} + +static void xres_free(struct xresource *xrp) +{ + xrp->xflag = 0; +} + +static struct resource *shmedia_find_resource(struct resource *root, + unsigned long vaddr) +{ + struct resource *res; + + for (res = root->child; res; res = res->sibling) + if (res->start <= vaddr && res->end >= vaddr) + return res; + + return NULL; +} + +static unsigned long shmedia_alloc_io(unsigned long phys, unsigned long size, + const char *name) +{ + static int printed_full = 0; + struct xresource *xres; + struct resource *res; + char *tack; + int tlen; + + if (name == NULL) name = "???"; + + if ((xres = xres_alloc()) != 0) { + tack = xres->xname; + res = &xres->xres; + } else { + if (!printed_full) { + printk("%s: done with statics, switching to kmalloc\n", + __FUNCTION__); + printed_full = 1; + } + tlen = strlen(name); + tack = kmalloc(sizeof (struct resource) + tlen + 1, GFP_KERNEL); + if (!tack) + return -ENOMEM; + memset(tack, 0, sizeof(struct resource)); + res = (struct resource *) tack; + tack += sizeof (struct resource); + } + + strncpy(tack, name, XNMLN); + tack[XNMLN] = 0; + res->name = tack; + + return shmedia_ioremap(res, phys, size); +} + +static unsigned long shmedia_ioremap(struct resource *res, u32 pa, int sz) +{ + unsigned long offset = ((unsigned long) pa) & (~PAGE_MASK); + unsigned long round_sz = (offset + sz + PAGE_SIZE-1) & PAGE_MASK; + unsigned long va; + unsigned int psz; + + if (allocate_resource(&shmedia_iomap, res, round_sz, + shmedia_iomap.start, shmedia_iomap.end, + PAGE_SIZE, NULL, NULL) != 0) { + panic("alloc_io_res(%s): cannot occupy\n", + (res->name != NULL)? res->name: "???"); + } + + va = res->start; + pa &= PAGE_MASK; + + psz = (res->end - res->start + (PAGE_SIZE - 1)) / PAGE_SIZE; + + /* log at boot time ... */ + printk("mapioaddr: %6s [%2d page%s] va 0x%08lx pa 0x%08x\n", + ((res->name != NULL) ? res->name : "???"), + psz, psz == 1 ? " " : "s", va, pa); + + for (psz = res->end - res->start + 1; psz != 0; psz -= PAGE_SIZE) { + shmedia_mapioaddr(pa, va); + va += PAGE_SIZE; + pa += PAGE_SIZE; + } + + res->start += offset; + res->end = res->start + sz - 1; /* not strictly necessary.. */ + + return res->start; +} + +static void shmedia_free_io(struct resource *res) +{ + unsigned long len = res->end - res->start + 1; + + BUG_ON((len & (PAGE_SIZE - 1)) != 0); + + while (len) { + len -= PAGE_SIZE; + shmedia_unmapioaddr(res->start + len); + } + + release_resource(res); +} + +static void *sh64_get_page(void) +{ + extern int after_bootmem; + void *page; + + if (after_bootmem) { + page = (void *)get_zeroed_page(GFP_ATOMIC); + } else { + page = alloc_bootmem_pages(PAGE_SIZE); + } + + if (!page || ((unsigned long)page & ~PAGE_MASK)) + panic("sh64_get_page: Out of memory already?\n"); + + return page; +} + +static void shmedia_mapioaddr(unsigned long pa, unsigned long va) +{ + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep, pte; + pgprot_t prot; + unsigned long flags = 1; /* 1 = CB0-1 device */ + + pr_debug("shmedia_mapiopage pa %08lx va %08lx\n", pa, va); + + pgdp = pgd_offset_k(va); + if (pgd_none(*pgdp) || !pgd_present(*pgdp)) { + pmdp = (pmd_t *)sh64_get_page(); + set_pgd(pgdp, __pgd((unsigned long)pmdp | _KERNPG_TABLE)); + } + + pmdp = pmd_offset(pgdp, va); + if (pmd_none(*pmdp) || !pmd_present(*pmdp) ) { + ptep = (pte_t *)sh64_get_page(); + set_pmd(pmdp, __pmd((unsigned long)ptep + _PAGE_TABLE)); + } + + prot = __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | + _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_SHARED | flags); + + pte = pfn_pte(pa >> PAGE_SHIFT, prot); + ptep = pte_offset_kernel(pmdp, va); + + if (!pte_none(*ptep) && + pte_val(*ptep) != pte_val(pte)) + pte_ERROR(*ptep); + + set_pte(ptep, pte); + + flush_tlb_kernel_range(va, PAGE_SIZE); +} + +static void shmedia_unmapioaddr(unsigned long vaddr) +{ + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + + pgdp = pgd_offset_k(vaddr); + pmdp = pmd_offset(pgdp, vaddr); + + if (pmd_none(*pmdp) || pmd_bad(*pmdp)) + return; + + ptep = pte_offset_kernel(pmdp, vaddr); + + if (pte_none(*ptep) || !pte_present(*ptep)) + return; + + clear_page((void *)ptep); + pte_clear(ptep); +} + +unsigned long onchip_remap(unsigned long phys, unsigned long size, const char *name) +{ + if (size < PAGE_SIZE) + size = PAGE_SIZE; + + return shmedia_alloc_io(phys, size, name); +} + +void onchip_unmap(unsigned long vaddr) +{ + struct resource *res; + unsigned int psz; + + res = shmedia_find_resource(&shmedia_iomap, vaddr); + if (!res) { + printk(KERN_ERR "%s: Failed to free 0x%08lx\n", + __FUNCTION__, vaddr); + return; + } + + psz = (res->end - res->start + (PAGE_SIZE - 1)) / PAGE_SIZE; + + printk(KERN_DEBUG "unmapioaddr: %6s [%2d page%s] freed\n", + res->name, psz, psz == 1 ? " " : "s"); + + shmedia_free_io(res); + + if ((char *)res >= (char *)xresv && + (char *)res < (char *)&xresv[XNRES]) { + xres_free((struct xresource *)res); + } else { + kfree(res); + } +} + +#ifdef CONFIG_PROC_FS +static int +ioremap_proc_info(char *buf, char **start, off_t fpos, int length, int *eof, + void *data) +{ + char *p = buf, *e = buf + length; + struct resource *r; + const char *nm; + + for (r = ((struct resource *)data)->child; r != NULL; r = r->sibling) { + if (p + 32 >= e) /* Better than nothing */ + break; + if ((nm = r->name) == 0) nm = "???"; + p += sprintf(p, "%08lx-%08lx: %s\n", r->start, r->end, nm); + } + + return p-buf; +} +#endif /* CONFIG_PROC_FS */ + +static int __init register_proc_onchip(void) +{ +#ifdef CONFIG_PROC_FS + create_proc_read_entry("io_map",0,0, ioremap_proc_info, &shmedia_iomap); +#endif + return 0; +} + +__initcall(register_proc_onchip); diff -puN /dev/null arch/sh64/mm/Makefile --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/mm/Makefile 2004-06-28 13:30:30.721133520 -0700 @@ -0,0 +1,44 @@ +# +# 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) 2000, 2001 Paolo Alberelli +# Copyright (C) 2003, 2004 Paul Mundt +# +# Makefile for the sh64-specific parts of the Linux memory manager. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +obj-y := init.o fault.o ioremap.o extable.o cache.o tlbmiss.o tlb.o + +obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o + +# Special flags for tlbmiss.o. This puts restrictions on the number of +# caller-save registers that the compiler can target when building this file. +# This is required because the code is called from a context in entry.S where +# very few registers have been saved in the exception handler (for speed +# reasons). +# The caller save registers that have been saved and which can be used are +# r2,r3,r4,r5 : argument passing +# r15, r18 : SP and LINK +# tr0-4 : allow all caller-save TR's. The compiler seems to be able to make +# use of them, so it's probably beneficial to performance to save them +# and have them available for it. +# +# The resources not listed below are callee save, i.e. the compiler is free to +# use any of them and will spill them to the stack itself. + +CFLAGS_tlbmiss.o += -ffixed-r7 \ + -ffixed-r8 -ffixed-r9 -ffixed-r10 -ffixed-r11 -ffixed-r12 \ + -ffixed-r13 -ffixed-r14 -ffixed-r16 -ffixed-r17 -ffixed-r19 \ + -ffixed-r20 -ffixed-r21 -ffixed-r22 -ffixed-r23 \ + -ffixed-r24 -ffixed-r25 -ffixed-r26 -ffixed-r27 \ + -ffixed-r36 -ffixed-r37 -ffixed-r38 -ffixed-r39 -ffixed-r40 \ + -ffixed-r41 -ffixed-r42 -ffixed-r43 \ + -ffixed-r60 -ffixed-r61 -ffixed-r62 \ + -fomit-frame-pointer + diff -puN /dev/null arch/sh64/mm/tlb.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/mm/tlb.c 2004-06-28 13:30:30.722133368 -0700 @@ -0,0 +1,166 @@ +/* + * arch/sh64/mm/tlb.c + * + * Copyright (C) 2003 Paul Mundt + * Copyright (C) 2003 Richard Curnow + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + */ +#include +#include +#include +#include +#include + +/** + * sh64_tlb_init + * + * Perform initial setup for the DTLB and ITLB. + */ +int __init sh64_tlb_init(void) +{ + /* Assign some sane DTLB defaults */ + cpu_data->dtlb.entries = 64; + cpu_data->dtlb.step = 0x10; + + cpu_data->dtlb.first = DTLB_FIXED | cpu_data->dtlb.step; + cpu_data->dtlb.next = cpu_data->dtlb.first; + + cpu_data->dtlb.last = DTLB_FIXED | + ((cpu_data->dtlb.entries - 1) * + cpu_data->dtlb.step); + + /* And again for the ITLB */ + cpu_data->itlb.entries = 64; + cpu_data->itlb.step = 0x10; + + cpu_data->itlb.first = ITLB_FIXED | cpu_data->itlb.step; + cpu_data->itlb.next = cpu_data->itlb.first; + cpu_data->itlb.last = ITLB_FIXED | + ((cpu_data->itlb.entries - 1) * + cpu_data->itlb.step); + + return 0; +} + +/** + * sh64_next_free_dtlb_entry + * + * Find the next available DTLB entry + */ +unsigned long long sh64_next_free_dtlb_entry(void) +{ + return cpu_data->dtlb.next; +} + +/** + * sh64_get_wired_dtlb_entry + * + * Allocate a wired (locked-in) entry in the DTLB + */ +unsigned long long sh64_get_wired_dtlb_entry(void) +{ + unsigned long long entry = sh64_next_free_dtlb_entry(); + + cpu_data->dtlb.first += cpu_data->dtlb.step; + cpu_data->dtlb.next += cpu_data->dtlb.step; + + return entry; +} + +/** + * sh64_put_wired_dtlb_entry + * + * @entry: Address of TLB slot. + * + * Free a wired (locked-in) entry in the DTLB. + * + * Works like a stack, last one to allocate must be first one to free. + */ +int sh64_put_wired_dtlb_entry(unsigned long long entry) +{ + __flush_tlb_slot(entry); + + /* + * We don't do any particularly useful tracking of wired entries, + * so this approach works like a stack .. last one to be allocated + * has to be the first one to be freed. + * + * We could potentially load wired entries into a list and work on + * rebalancing the list periodically (which also entails moving the + * contents of a TLB entry) .. though I have a feeling that this is + * more trouble than it's worth. + */ + + /* + * Entry must be valid .. we don't want any ITLB addresses! + */ + if (entry <= DTLB_FIXED) + return -EINVAL; + + /* + * Next, check if we're within range to be freed. (ie, must be the + * entry beneath the first 'free' entry! + */ + if (entry < (cpu_data->dtlb.first - cpu_data->dtlb.step)) + return -EINVAL; + + /* If we are, then bring this entry back into the list */ + cpu_data->dtlb.first -= cpu_data->dtlb.step; + cpu_data->dtlb.next = entry; + + return 0; +} + +/** + * sh64_setup_tlb_slot + * + * @config_addr: Address of TLB slot. + * @eaddr: Virtual address. + * @asid: Address Space Identifier. + * @paddr: Physical address. + * + * Load up a virtual<->physical translation for @eaddr<->@paddr in the + * pre-allocated TLB slot @config_addr (see sh64_get_wired_dtlb_entry). + */ +inline void sh64_setup_tlb_slot(unsigned long long config_addr, + unsigned long eaddr, + unsigned long asid, + unsigned long paddr) +{ + unsigned long long pteh, ptel; + + /* Sign extension */ +#if (NEFF == 32) + pteh = (unsigned long long)(signed long long)(signed long) eaddr; +#else +#error "Can't sign extend more than 32 bits yet" +#endif + pteh &= PAGE_MASK; + pteh |= (asid << PTEH_ASID_SHIFT) | PTEH_VALID; +#if (NEFF == 32) + ptel = (unsigned long long)(signed long long)(signed long) paddr; +#else +#error "Can't sign extend more than 32 bits yet" +#endif + ptel &= PAGE_MASK; + ptel |= (_PAGE_CACHABLE | _PAGE_READ | _PAGE_WRITE); + + asm volatile("putcfg %0, 1, %1\n\t" + "putcfg %0, 0, %2\n" + : : "r" (config_addr), "r" (ptel), "r" (pteh)); +} + +/** + * sh64_teardown_tlb_slot + * + * @config_addr: Address of TLB slot. + * + * Teardown any existing mapping in the TLB slot @config_addr. + */ +inline void sh64_teardown_tlb_slot(unsigned long long config_addr) + __attribute__ ((alias("__flush_tlb_slot"))); + diff -puN /dev/null arch/sh64/mm/tlbmiss.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/mm/tlbmiss.c 2004-06-28 13:30:30.724133064 -0700 @@ -0,0 +1,282 @@ +/* + * 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. + * + * arch/sh64/mm/tlbmiss.c + * + * Original code from fault.c + * Copyright (C) 2000, 2001 Paolo Alberelli + * + * Fast PTE->TLB refill path + * Copyright (C) 2003 Richard.Curnow@superh.com + * + * IMPORTANT NOTES : + * The do_fast_page_fault function is called from a context in entry.S where very few registers + * have been saved. In particular, the code in this file must be compiled not to use ANY + * caller-save regiseters that are not part of the restricted save set. Also, it means that + * code in this file must not make calls to functions elsewhere in the kernel, or else the + * excepting context will see corruption in its caller-save registers. Plus, the entry.S save + * area is non-reentrant, so this code has to run with SR.BL==1, i.e. no interrupts taken inside + * it and panic on any exception. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include /* required by inline asm statements */ + +/* Callable from fault.c, so not static */ +inline void __do_tlb_refill(unsigned long address, + unsigned long long is_text_not_data, pte_t *pte) +{ + unsigned long long ptel; + unsigned long long pteh=0; + struct tlb_info *tlbp; + unsigned long long next; + + /* Get PTEL first */ + ptel = pte_val(*pte); + + /* + * Set PTEH register + */ + pteh = address & MMU_VPN_MASK; + + /* Sign extend based on neff. */ +#if (NEFF == 32) + /* Faster sign extension */ + pteh = (unsigned long long)(signed long long)(signed long)pteh; +#else + /* General case */ + pteh = (pteh & NEFF_SIGN) ? (pteh | NEFF_MASK) : pteh; +#endif + + /* Set the ASID. */ + pteh |= get_asid() << PTEH_ASID_SHIFT; + pteh |= PTEH_VALID; + + /* Set PTEL register, set_pte has performed the sign extension */ + ptel &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */ + ptel |= _PAGE_FLAGS_HARDWARE_DEFAULT; /* add default flags */ + + tlbp = is_text_not_data ? &(cpu_data->itlb) : &(cpu_data->dtlb); + next = tlbp->next; + __flush_tlb_slot(next); + asm volatile ("putcfg %0,1,%2\n\n\t" + "putcfg %0,0,%1\n" + : : "r" (next), "r" (pteh), "r" (ptel) ); + + next += TLB_STEP; + if (next > tlbp->last) next = tlbp->first; + tlbp->next = next; + +} + +static int handle_vmalloc_fault(struct mm_struct *mm, unsigned long protection_flags, + unsigned long long textaccess, + unsigned long address) +{ + pgd_t *dir; + pmd_t *pmd; + static pte_t *pte; + pte_t entry; + + dir = pgd_offset_k(address); + pmd = pmd_offset(dir, address); + + if (pmd_none(*pmd)) { + return 0; + } + + if (pmd_bad(*pmd)) { + pmd_clear(pmd); + return 0; + } + + pte = pte_offset_kernel(pmd, address); + entry = *pte; + + if (pte_none(entry) || !pte_present(entry)) { + return 0; + } + + if ((pte_val(entry) & protection_flags) != protection_flags) { + return 0; + } + + __do_tlb_refill(address, textaccess, pte); + + return 1; +} + +static int handle_tlbmiss(struct mm_struct *mm, unsigned long long protection_flags, + unsigned long long textaccess, + unsigned long address) +{ + pgd_t *dir; + pmd_t *pmd; + pte_t *pte; + pte_t entry; + + /* NB. The PGD currently only contains a single entry - there is no + page table tree stored for the top half of the address space since + virtual pages in that region should never be mapped in user mode. + (In kernel mode, the only things in that region are the 512Mb super + page (locked in), and vmalloc (modules) + I/O device pages (handled + by handle_vmalloc_fault), so no PGD for the upper half is required + by kernel mode either). + + See how mm->pgd is allocated and initialised in pgd_alloc to see why + the next test is necessary. - RPC */ + if (address >= (unsigned long) TASK_SIZE) { + /* upper half - never has page table entries. */ + return 0; + } + dir = pgd_offset(mm, address); + if (pgd_none(*dir)) { + return 0; + } + if (!pgd_present(*dir)) { + return 0; + } + + pmd = pmd_offset(dir, address); + if (pmd_none(*pmd)) { + return 0; + } + if (!pmd_present(*pmd)) { + return 0; + } + pte = pte_offset_kernel(pmd, address); + entry = *pte; + if (pte_none(entry)) { + return 0; + } + if (!pte_present(entry)) { + return 0; + } + + /* If the page doesn't have sufficient protection bits set to service the + kind of fault being handled, there's not much point doing the TLB refill. + Punt the fault to the general handler. */ + if ((pte_val(entry) & protection_flags) != protection_flags) { + return 0; + } + + __do_tlb_refill(address, textaccess, pte); + + return 1; +} + +/* Put all this information into one structure so that everything is just arithmetic + relative to a single base address. This reduces the number of movi/shori pairs needed + just to load addresses of static data. */ +struct expevt_lookup { + unsigned short protection_flags[8]; + unsigned char is_text_access[8]; + unsigned char is_write_access[8]; +}; + +#define PRU (1<<9) +#define PRW (1<<8) +#define PRX (1<<7) +#define PRR (1<<6) + +#define DIRTY (_PAGE_DIRTY | _PAGE_ACCESSED) +#define YOUNG (_PAGE_ACCESSED) + +/* Sized as 8 rather than 4 to allow checking the PTE's PRU bit against whether + the fault happened in user mode or privileged mode. */ +static struct expevt_lookup expevt_lookup_table = { + .protection_flags = {PRX, PRX, 0, 0, PRR, PRR, PRW, PRW}, + .is_text_access = {1, 1, 0, 0, 0, 0, 0, 0} +}; + +/* + This routine handles page faults that can be serviced just by refilling a + TLB entry from an existing page table entry. (This case represents a very + large majority of page faults.) Return 1 if the fault was successfully + handled. Return 0 if the fault could not be handled. (This leads into the + general fault handling in fault.c which deals with mapping file-backed + pages, stack growth, segmentation faults, swapping etc etc) + */ +asmlinkage int do_fast_page_fault(unsigned long long ssr_md, unsigned long long expevt, + unsigned long address) +{ + struct task_struct *tsk; + struct mm_struct *mm; + unsigned long long textaccess; + unsigned long long protection_flags; + unsigned long long index; + unsigned long long expevt4; + + /* The next few lines implement a way of hashing EXPEVT into a small array index + which can be used to lookup parameters specific to the type of TLBMISS being + handled. Note: + ITLBMISS has EXPEVT==0xa40 + RTLBMISS has EXPEVT==0x040 + WTLBMISS has EXPEVT==0x060 + */ + + expevt4 = (expevt >> 4); + /* TODO : xor ssr_md into this expression too. Then we can check that PRU is set + when it needs to be. */ + index = expevt4 ^ (expevt4 >> 5); + index &= 7; + protection_flags = expevt_lookup_table.protection_flags[index]; + textaccess = expevt_lookup_table.is_text_access[index]; + +#ifdef CONFIG_SH64_PROC_TLB + ++calls_to_do_fast_page_fault; +#endif + + /* SIM + * Note this is now called with interrupts still disabled + * This is to cope with being called for a missing IO port + * address with interupts disabled. This should be fixed as + * soon as we have a better 'fast path' miss handler. + * + * Plus take care how you try and debug this stuff. + * For example, writing debug data to a port which you + * have just faulted on is not going to work. + */ + + tsk = current; + mm = tsk->mm; + + if ((address >= VMALLOC_START && address < VMALLOC_END) || + (address >= IOBASE_VADDR && address < IOBASE_END)) { + if (ssr_md) { + /* Process-contexts can never have this address range mapped */ + if (handle_vmalloc_fault(mm, protection_flags, textaccess, address)) { + return 1; + } + } + } else if (!in_interrupt() && mm) { + if (handle_tlbmiss(mm, protection_flags, textaccess, address)) { + return 1; + } + } + + return 0; +} + diff -puN /dev/null arch/sh64/oprofile/Kconfig --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/oprofile/Kconfig 2004-06-28 13:30:30.724133064 -0700 @@ -0,0 +1,23 @@ + +menu "Profiling support" + depends on EXPERIMENTAL + +config PROFILING + bool "Profiling support (EXPERIMENTAL)" + help + Say Y here to enable the extended profiling support mechanisms used + by profilers such as OProfile. + + +config OPROFILE + tristate "OProfile system profiling (EXPERIMENTAL)" + depends on PROFILING + help + OProfile is a profiling system capable of profiling the + whole system, include the kernel, kernel modules, libraries, + and applications. + + If unsure, say N. + +endmenu + diff -puN /dev/null arch/sh64/oprofile/Makefile --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/oprofile/Makefile 2004-06-28 13:30:30.724133064 -0700 @@ -0,0 +1,12 @@ +obj-$(CONFIG_OPROFILE) += oprofile.o + +DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \ + oprof.o cpu_buffer.o buffer_sync.o \ + event_buffer.o oprofile_files.o \ + oprofilefs.o oprofile_stats.o \ + timer_int.o ) + +profdrvr-y := op_model_null.o + +oprofile-y := $(DRIVER_OBJS) $(profdrvr-y) + diff -puN /dev/null arch/sh64/oprofile/op_model_null.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/arch/sh64/oprofile/op_model_null.c 2004-06-28 13:30:30.725132912 -0700 @@ -0,0 +1,23 @@ +/* + * arch/sh/oprofile/op_model_null.c + * + * Copyright (C) 2003 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include +#include + +int __init oprofile_arch_init(struct oprofile_operations **ops) +{ + return -ENODEV; +} + +void oprofile_arch_exit(void) +{ +} + diff -puN drivers/char/keyboard.c~sh64-merge drivers/char/keyboard.c --- 25/drivers/char/keyboard.c~sh64-merge 2004-06-28 13:30:30.609150544 -0700 +++ 25-akpm/drivers/char/keyboard.c 2004-06-28 13:30:30.726132760 -0700 @@ -939,7 +939,7 @@ void kbd_refresh_leds(struct input_handl tasklet_enable(&keyboard_tasklet); } -#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) || defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64) || defined(CONFIG_PARISC) || defined(CONFIG_SH_MPC1211) +#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) || defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64) || defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) #define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\ ((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001)) diff -puN drivers/input/serio/i8042-io.h~sh64-merge drivers/input/serio/i8042-io.h --- 25/drivers/input/serio/i8042-io.h~sh64-merge 2004-06-28 13:30:30.611150240 -0700 +++ 25-akpm/drivers/input/serio/i8042-io.h 2004-06-28 13:30:30.727132608 -0700 @@ -28,6 +28,8 @@ #elif defined(__arm__) /* defined in include/asm-arm/arch-xxx/irqs.h */ #include +#elif defined(CONFIG_SUPERH64) +#include #else # define I8042_KBD_IRQ 1 # define I8042_AUX_IRQ 12 diff -puN /dev/null include/asm-sh64/a.out.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/a.out.h 2004-06-28 13:30:30.727132608 -0700 @@ -0,0 +1,37 @@ +#ifndef __ASM_SH64_A_OUT_H +#define __ASM_SH64_A_OUT_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. + * + * include/asm-sh64/a.out.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + */ + +struct exec +{ + unsigned long a_info; /* Use macros N_MAGIC, etc for access */ + unsigned a_text; /* length of text, in bytes */ + unsigned a_data; /* length of data, in bytes */ + unsigned a_bss; /* length of uninitialized data area for file, in bytes */ + unsigned a_syms; /* length of symbol table data in file, in bytes */ + unsigned a_entry; /* start address */ + unsigned a_trsize; /* length of relocation info for text, in bytes */ + unsigned a_drsize; /* length of relocation info for data, in bytes */ +}; + +#define N_TRSIZE(a) ((a).a_trsize) +#define N_DRSIZE(a) ((a).a_drsize) +#define N_SYMSIZE(a) ((a).a_syms) + +#ifdef __KERNEL__ + +#define STACK_TOP TASK_SIZE + +#endif + +#endif /* __ASM_SH64_A_OUT_H */ diff -puN /dev/null include/asm-sh64/atomic.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/atomic.h 2004-06-28 13:30:30.728132456 -0700 @@ -0,0 +1,126 @@ +#ifndef __ASM_SH64_ATOMIC_H +#define __ASM_SH64_ATOMIC_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. + * + * include/asm-sh64/atomic.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003 Paul Mundt + * + */ + +/* + * Atomic operations that C can't guarantee us. Useful for + * resource counting etc.. + * + */ + +typedef struct { volatile int counter; } atomic_t; + +#define ATOMIC_INIT(i) ( (atomic_t) { (i) } ) + +#define atomic_read(v) ((v)->counter) +#define atomic_set(v,i) ((v)->counter = (i)) + +#include + +/* + * To get proper branch prediction for the main line, we must branch + * forward to code at the end of this object's .text section, then + * branch back to restart the operation. + */ + +static __inline__ void atomic_add(int i, atomic_t * v) +{ + unsigned long flags; + + local_irq_save(flags); + *(long *)v += i; + local_irq_restore(flags); +} + +static __inline__ void atomic_sub(int i, atomic_t *v) +{ + unsigned long flags; + + local_irq_save(flags); + *(long *)v -= i; + local_irq_restore(flags); +} + +static __inline__ int atomic_add_return(int i, atomic_t * v) +{ + unsigned long temp, flags; + + local_irq_save(flags); + temp = *(long *)v; + temp += i; + *(long *)v = temp; + local_irq_restore(flags); + + return temp; +} + +#define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) + +static __inline__ int atomic_sub_return(int i, atomic_t * v) +{ + unsigned long temp, flags; + + local_irq_save(flags); + temp = *(long *)v; + temp -= i; + *(long *)v = temp; + local_irq_restore(flags); + + return temp; +} + +#define atomic_dec_return(v) atomic_sub_return(1,(v)) +#define atomic_inc_return(v) atomic_add_return(1,(v)) + +/* + * atomic_inc_and_test - increment and test + * @v: pointer of type atomic_t + * + * Atomically increments @v by 1 + * and returns true if the result is zero, or false for all + * other cases. + */ +#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0) + +#define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0) +#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0) + +#define atomic_inc(v) atomic_add(1,(v)) +#define atomic_dec(v) atomic_sub(1,(v)) + +static __inline__ void atomic_clear_mask(unsigned int mask, atomic_t *v) +{ + unsigned long flags; + + local_irq_save(flags); + *(long *)v &= ~mask; + local_irq_restore(flags); +} + +static __inline__ void atomic_set_mask(unsigned int mask, atomic_t *v) +{ + unsigned long flags; + + local_irq_save(flags); + *(long *)v |= mask; + local_irq_restore(flags); +} + +/* Atomic operations are already serializing on SH */ +#define smp_mb__before_atomic_dec() barrier() +#define smp_mb__after_atomic_dec() barrier() +#define smp_mb__before_atomic_inc() barrier() +#define smp_mb__after_atomic_inc() barrier() + +#endif /* __ASM_SH64_ATOMIC_H */ diff -puN /dev/null include/asm-sh64/bitops.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/bitops.h 2004-06-28 13:30:30.730132152 -0700 @@ -0,0 +1,518 @@ +#ifndef __ASM_SH64_BITOPS_H +#define __ASM_SH64_BITOPS_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. + * + * include/asm-sh64/bitops.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003 Paul Mundt + */ + +#ifdef __KERNEL__ +#include +#include +/* For __swab32 */ +#include + +static __inline__ void set_bit(int nr, volatile void * addr) +{ + int mask; + volatile unsigned int *a = addr; + unsigned long flags; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + local_irq_save(flags); + *a |= mask; + local_irq_restore(flags); +} + +static inline void __set_bit(int nr, void *addr) +{ + int mask; + unsigned int *a = addr; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + *a |= mask; +} + +/* + * clear_bit() doesn't provide any barrier for the compiler. + */ +#define smp_mb__before_clear_bit() barrier() +#define smp_mb__after_clear_bit() barrier() +static __inline__ void clear_bit(int nr, void * addr) +{ + int mask; + unsigned int *a = addr; + unsigned long flags; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + local_irq_save(flags); + *a &= ~mask; + local_irq_restore(flags); +} + +static inline void __clear_bit(int nr, void *addr) +{ + int mask; + unsigned int *a = addr; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + *a &= ~mask; +} + +static __inline__ void change_bit(int nr, volatile void * addr) +{ + int mask; + volatile unsigned int *a = addr; + unsigned long flags; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + local_irq_save(flags); + *a ^= mask; + local_irq_restore(flags); +} + +static __inline__ void __change_bit(int nr, volatile void * addr) +{ + int mask; + volatile unsigned int *a = addr; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + *a ^= mask; +} + +static __inline__ int test_and_set_bit(int nr, volatile void * addr) +{ + int mask, retval; + volatile unsigned int *a = addr; + unsigned long flags; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + local_irq_save(flags); + retval = (mask & *a) != 0; + *a |= mask; + local_irq_restore(flags); + + return retval; +} + +static __inline__ int __test_and_set_bit(int nr, volatile void * addr) +{ + int mask, retval; + volatile unsigned int *a = addr; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + retval = (mask & *a) != 0; + *a |= mask; + + return retval; +} + +static __inline__ int test_and_clear_bit(int nr, volatile void * addr) +{ + int mask, retval; + volatile unsigned int *a = addr; + unsigned long flags; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + local_irq_save(flags); + retval = (mask & *a) != 0; + *a &= ~mask; + local_irq_restore(flags); + + return retval; +} + +static __inline__ int __test_and_clear_bit(int nr, volatile void * addr) +{ + int mask, retval; + volatile unsigned int *a = addr; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + retval = (mask & *a) != 0; + *a &= ~mask; + + return retval; +} + +static __inline__ int test_and_change_bit(int nr, volatile void * addr) +{ + int mask, retval; + volatile unsigned int *a = addr; + unsigned long flags; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + local_irq_save(flags); + retval = (mask & *a) != 0; + *a ^= mask; + local_irq_restore(flags); + + return retval; +} + +static __inline__ int __test_and_change_bit(int nr, volatile void * addr) +{ + int mask, retval; + volatile unsigned int *a = addr; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + retval = (mask & *a) != 0; + *a ^= mask; + + return retval; +} + +static __inline__ int test_bit(int nr, const volatile void *addr) +{ + return 1UL & (((const volatile unsigned int *) addr)[nr >> 5] >> (nr & 31)); +} + +static __inline__ unsigned long ffz(unsigned long word) +{ + unsigned long result, __d2, __d3; + + __asm__("gettr tr0, %2\n\t" + "pta $+32, tr0\n\t" + "andi %1, 1, %3\n\t" + "beq %3, r63, tr0\n\t" + "pta $+4, tr0\n" + "0:\n\t" + "shlri.l %1, 1, %1\n\t" + "addi %0, 1, %0\n\t" + "andi %1, 1, %3\n\t" + "beqi %3, 1, tr0\n" + "1:\n\t" + "ptabs %2, tr0\n\t" + : "=r" (result), "=r" (word), "=r" (__d2), "=r" (__d3) + : "0" (0L), "1" (word)); + + return result; +} + +/** + * __ffs - find first bit in word + * @word: The word to search + * + * Undefined if no bit exists, so code should check against 0 first. + */ +static inline unsigned long __ffs(unsigned long word) +{ + int r = 0; + + if (!word) + return 0; + if (!(word & 0xffff)) { + word >>= 16; + r += 16; + } + if (!(word & 0xff)) { + word >>= 8; + r += 8; + } + if (!(word & 0xf)) { + word >>= 4; + r += 4; + } + if (!(word & 3)) { + word >>= 2; + r += 2; + } + if (!(word & 1)) { + word >>= 1; + r += 1; + } + return r; +} + +/** + * find_next_bit - find the next set bit in a memory region + * @addr: The address to base the search on + * @offset: The bitnumber to start searching at + * @size: The maximum size to search + */ +static inline unsigned long find_next_bit(unsigned long *addr, + unsigned long size, unsigned long offset) +{ + unsigned int *p = ((unsigned int *) addr) + (offset >> 5); + unsigned int result = offset & ~31UL; + unsigned int tmp; + + if (offset >= size) + return size; + size -= result; + offset &= 31UL; + if (offset) { + tmp = *p++; + tmp &= ~0UL << offset; + if (size < 32) + goto found_first; + if (tmp) + goto found_middle; + size -= 32; + result += 32; + } + while (size >= 32) { + if ((tmp = *p++) != 0) + goto found_middle; + result += 32; + size -= 32; + } + if (!size) + return result; + tmp = *p; + +found_first: + tmp &= ~0UL >> (32 - size); + if (tmp == 0UL) /* Are any bits set? */ + return result + size; /* Nope. */ +found_middle: + return result + __ffs(tmp); +} + +/** + * find_first_bit - find the first set bit in a memory region + * @addr: The address to start the search at + * @size: The maximum size to search + * + * Returns the bit-number of the first set bit, not the number of the byte + * containing a bit. + */ +#define find_first_bit(addr, size) \ + find_next_bit((addr), (size), 0) + + +static inline int find_next_zero_bit(void *addr, int size, int offset) +{ + unsigned long *p = ((unsigned long *) addr) + (offset >> 5); + unsigned long result = offset & ~31UL; + unsigned long tmp; + + if (offset >= size) + return size; + size -= result; + offset &= 31UL; + if (offset) { + tmp = *(p++); + tmp |= ~0UL >> (32-offset); + if (size < 32) + goto found_first; + if (~tmp) + goto found_middle; + size -= 32; + result += 32; + } + while (size & ~31UL) { + if (~(tmp = *(p++))) + goto found_middle; + result += 32; + size -= 32; + } + if (!size) + return result; + tmp = *p; + +found_first: + tmp |= ~0UL << size; +found_middle: + return result + ffz(tmp); +} + +#define find_first_zero_bit(addr, size) \ + find_next_zero_bit((addr), (size), 0) + +/* + * hweightN: returns the hamming weight (i.e. the number + * of bits set) of a N-bit word + */ + +#define hweight32(x) generic_hweight32(x) +#define hweight16(x) generic_hweight16(x) +#define hweight8(x) generic_hweight8(x) + +/* + * Every architecture must define this function. It's the fastest + * way of searching a 140-bit bitmap where the first 100 bits are + * unlikely to be set. It's guaranteed that at least one of the 140 + * bits is cleared. + */ + +static inline int sched_find_first_bit(unsigned long *b) +{ + if (unlikely(b[0])) + return __ffs(b[0]); + if (unlikely(b[1])) + return __ffs(b[1]) + 32; + if (unlikely(b[2])) + return __ffs(b[2]) + 64; + if (b[3]) + return __ffs(b[3]) + 96; + return __ffs(b[4]) + 128; +} + +/* + * ffs: find first bit set. This is defined the same way as + * the libc and compiler builtin ffs routines, therefore + * differs in spirit from the above ffz (man ffs). + */ + +#define ffs(x) generic_ffs(x) + +/* + * hweightN: returns the hamming weight (i.e. the number + * of bits set) of a N-bit word + */ + +#define hweight32(x) generic_hweight32(x) +#define hweight16(x) generic_hweight16(x) +#define hweight8(x) generic_hweight8(x) + +#ifdef __LITTLE_ENDIAN__ +#define ext2_set_bit(nr, addr) test_and_set_bit((nr), (addr)) +#define ext2_clear_bit(nr, addr) test_and_clear_bit((nr), (addr)) +#define ext2_test_bit(nr, addr) test_bit((nr), (addr)) +#define ext2_find_first_zero_bit(addr, size) find_first_zero_bit((addr), (size)) +#define ext2_find_next_zero_bit(addr, size, offset) \ + find_next_zero_bit((addr), (size), (offset)) +#else +static __inline__ int ext2_set_bit(int nr, volatile void * addr) +{ + int mask, retval; + unsigned long flags; + volatile unsigned char *ADDR = (unsigned char *) addr; + + ADDR += nr >> 3; + mask = 1 << (nr & 0x07); + local_irq_save(flags); + retval = (mask & *ADDR) != 0; + *ADDR |= mask; + local_irq_restore(flags); + return retval; +} + +static __inline__ int ext2_clear_bit(int nr, volatile void * addr) +{ + int mask, retval; + unsigned long flags; + volatile unsigned char *ADDR = (unsigned char *) addr; + + ADDR += nr >> 3; + mask = 1 << (nr & 0x07); + local_irq_save(flags); + retval = (mask & *ADDR) != 0; + *ADDR &= ~mask; + local_irq_restore(flags); + return retval; +} + +static __inline__ int ext2_test_bit(int nr, const volatile void * addr) +{ + int mask; + const volatile unsigned char *ADDR = (const unsigned char *) addr; + + ADDR += nr >> 3; + mask = 1 << (nr & 0x07); + return ((mask & *ADDR) != 0); +} + +#define ext2_find_first_zero_bit(addr, size) \ + ext2_find_next_zero_bit((addr), (size), 0) + +static __inline__ unsigned long ext2_find_next_zero_bit(void *addr, unsigned long size, unsigned long offset) +{ + unsigned long *p = ((unsigned long *) addr) + (offset >> 5); + unsigned long result = offset & ~31UL; + unsigned long tmp; + + if (offset >= size) + return size; + size -= result; + offset &= 31UL; + if(offset) { + /* We hold the little endian value in tmp, but then the + * shift is illegal. So we could keep a big endian value + * in tmp, like this: + * + * tmp = __swab32(*(p++)); + * tmp |= ~0UL >> (32-offset); + * + * but this would decrease preformance, so we change the + * shift: + */ + tmp = *(p++); + tmp |= __swab32(~0UL >> (32-offset)); + if(size < 32) + goto found_first; + if(~tmp) + goto found_middle; + size -= 32; + result += 32; + } + while(size & ~31UL) { + if(~(tmp = *(p++))) + goto found_middle; + result += 32; + size -= 32; + } + if(!size) + return result; + tmp = *p; + +found_first: + /* tmp is little endian, so we would have to swab the shift, + * see above. But then we have to swab tmp below for ffz, so + * we might as well do this here. + */ + return result + ffz(__swab32(tmp) | (~0UL << size)); +found_middle: + return result + ffz(__swab32(tmp)); +} +#endif + +#define ext2_set_bit_atomic(lock, nr, addr) \ + ({ \ + int ret; \ + spin_lock(lock); \ + ret = ext2_set_bit((nr), (addr)); \ + spin_unlock(lock); \ + ret; \ + }) + +#define ext2_clear_bit_atomic(lock, nr, addr) \ + ({ \ + int ret; \ + spin_lock(lock); \ + ret = ext2_clear_bit((nr), (addr)); \ + spin_unlock(lock); \ + ret; \ + }) + +/* Bitmap functions for the minix filesystem. */ +#define minix_test_and_set_bit(nr,addr) test_and_set_bit(nr,addr) +#define minix_set_bit(nr,addr) set_bit(nr,addr) +#define minix_test_and_clear_bit(nr,addr) test_and_clear_bit(nr,addr) +#define minix_test_bit(nr,addr) test_bit(nr,addr) +#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size) + +#define ffs(x) generic_ffs(x) +#define fls(x) generic_fls(x) + +#endif /* __KERNEL__ */ + +#endif /* __ASM_SH64_BITOPS_H */ diff -puN /dev/null include/asm-sh64/bug.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/bug.h 2004-06-28 13:30:30.730132152 -0700 @@ -0,0 +1,7 @@ +#ifndef __ASM_SH64_BUG_H +#define __ASM_SH64_BUG_H + +#include + +#endif /* __ASM_SH64_BUG_H */ + diff -puN /dev/null include/asm-sh64/bugs.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/bugs.h 2004-06-28 13:30:30.730132152 -0700 @@ -0,0 +1,38 @@ +#ifndef __ASM_SH64_BUGS_H +#define __ASM_SH64_BUGS_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. + * + * include/asm-sh64/bugs.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003 Paul Mundt + * + */ + +/* + * This is included by init/main.c to check for architecture-dependent bugs. + * + * Needs: + * void check_bugs(void); + */ + +/* + * I don't know of any Super-H bugs yet. + */ + +#include + +static void __init check_bugs(void) +{ + extern char *get_cpu_subtype(void); + extern unsigned long loops_per_jiffy; + + cpu_data->loops_per_jiffy = loops_per_jiffy; + + printk("CPU: %s\n", get_cpu_subtype()); +} +#endif /* __ASM_SH64_BUGS_H */ diff -puN /dev/null include/asm-sh64/byteorder.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/byteorder.h 2004-06-28 13:30:30.731132000 -0700 @@ -0,0 +1,49 @@ +#ifndef __ASM_SH64_BYTEORDER_H +#define __ASM_SH64_BYTEORDER_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. + * + * include/asm-sh64/byteorder.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + */ + +#include + +static __inline__ __const__ __u32 ___arch__swab32(__u32 x) +{ + __asm__("byterev %0, %0\n\t" + "shari %0, 32, %0" + : "=r" (x) + : "0" (x)); + return x; +} + +static __inline__ __const__ __u16 ___arch__swab16(__u16 x) +{ + __asm__("byterev %0, %0\n\t" + "shari %0, 48, %0" + : "=r" (x) + : "0" (x)); + return x; +} + +#define __arch__swab32(x) ___arch__swab32(x) +#define __arch__swab16(x) ___arch__swab16(x) + +#if !defined(__STRICT_ANSI__) || defined(__KERNEL__) +# define __BYTEORDER_HAS_U64__ +# define __SWAB_64_THRU_32__ +#endif + +#ifdef __LITTLE_ENDIAN__ +#include +#else +#include +#endif + +#endif /* __ASM_SH64_BYTEORDER_H */ diff -puN /dev/null include/asm-sh64/cacheflush.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/cacheflush.h 2004-06-28 13:30:30.731132000 -0700 @@ -0,0 +1,44 @@ +#ifndef __ASM_SH64_CACHEFLUSH_H +#define __ASM_SH64_CACHEFLUSH_H + +#ifndef __ASSEMBLY__ + +#include + +struct vm_area_struct; +struct page; +struct mm_struct; + +extern void flush_cache_all(void); +extern void flush_cache_mm(struct mm_struct *mm); +extern void flush_cache_sigtramp(unsigned long start, unsigned long end); +extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end); +extern void flush_cache_page(struct vm_area_struct *vma, unsigned long addr); +extern void flush_dcache_page(struct page *pg); +extern void flush_icache_range(unsigned long start, unsigned long end); +extern void flush_icache_user_range(struct vm_area_struct *vma, + struct page *page, unsigned long addr, + int len); + +#define flush_dcache_mmap_lock(mapping) do { } while (0) +#define flush_dcache_mmap_unlock(mapping) do { } while (0) + +#define flush_cache_vmap(start, end) flush_cache_all() +#define flush_cache_vunmap(start, end) flush_cache_all() + +#define flush_icache_page(vma, page) do { } while (0) + +#define copy_to_user_page(vma, page, vaddr, dst, src, len) \ +do { memcpy(dst, src, len); \ + flush_icache_user_range(vma, page, vaddr, len); \ +} while (0) + +#define copy_from_user_page(vma, page, vaddr, dst, src, len) \ + memcpy(dst, src, len) + + +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_SH64_CACHEFLUSH_H */ + diff -puN /dev/null include/asm-sh64/cache.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/cache.h 2004-06-28 13:30:30.732131848 -0700 @@ -0,0 +1,141 @@ +#ifndef __ASM_SH64_CACHE_H +#define __ASM_SH64_CACHE_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. + * + * include/asm-sh64/cache.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003, 2004 Paul Mundt + * + */ +#include + +#define L1_CACHE_SHIFT 5 +/* bytes per L1 cache line */ +#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) +#define L1_CACHE_ALIGN_MASK (~(L1_CACHE_BYTES - 1)) +#define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES - 1)) & L1_CACHE_ALIGN_MASK) +#define L1_CACHE_SIZE_BYTES (L1_CACHE_BYTES << 10) +/* Largest L1 which this arch supports */ +#define L1_CACHE_SHIFT_MAX 5 + +#ifdef MODULE +#define __cacheline_aligned __attribute__((__aligned__(L1_CACHE_BYTES))) +#else +#define __cacheline_aligned \ + __attribute__((__aligned__(L1_CACHE_BYTES), \ + __section__(".data.cacheline_aligned"))) +#endif + +/* + * Control Registers. + */ +#define ICCR_BASE 0x01600000 /* Instruction Cache Control Register */ +#define ICCR_REG0 0 /* Register 0 offset */ +#define ICCR_REG1 1 /* Register 1 offset */ +#define ICCR0 ICCR_BASE+ICCR_REG0 +#define ICCR1 ICCR_BASE+ICCR_REG1 + +#define ICCR0_OFF 0x0 /* Set ICACHE off */ +#define ICCR0_ON 0x1 /* Set ICACHE on */ +#define ICCR0_ICI 0x2 /* Invalidate all in IC */ + +#define ICCR1_NOLOCK 0x0 /* Set No Locking */ + +#define OCCR_BASE 0x01E00000 /* Operand Cache Control Register */ +#define OCCR_REG0 0 /* Register 0 offset */ +#define OCCR_REG1 1 /* Register 1 offset */ +#define OCCR0 OCCR_BASE+OCCR_REG0 +#define OCCR1 OCCR_BASE+OCCR_REG1 + +#define OCCR0_OFF 0x0 /* Set OCACHE off */ +#define OCCR0_ON 0x1 /* Set OCACHE on */ +#define OCCR0_OCI 0x2 /* Invalidate all in OC */ +#define OCCR0_WT 0x4 /* Set OCACHE in WT Mode */ +#define OCCR0_WB 0x0 /* Set OCACHE in WB Mode */ + +#define OCCR1_NOLOCK 0x0 /* Set No Locking */ + + +/* + * SH-5 + * A bit of description here, for neff=32. + * + * |<--- tag (19 bits) --->| + * +-----------------------------+-----------------+------+----------+------+ + * | | | ways |set index |offset| + * +-----------------------------+-----------------+------+----------+------+ + * ^ 2 bits 8 bits 5 bits + * +- Bit 31 + * + * Cacheline size is based on offset: 5 bits = 32 bytes per line + * A cache line is identified by a tag + set but OCACHETAG/ICACHETAG + * have a broader space for registers. These are outlined by + * CACHE_?C_*_STEP below. + * + */ + +/* Valid and Dirty bits */ +#define SH_CACHE_VALID (1LL<<0) +#define SH_CACHE_UPDATED (1LL<<57) + +/* Cache flags */ +#define SH_CACHE_MODE_WT (1LL<<0) +#define SH_CACHE_MODE_WB (1LL<<1) + +#ifndef __ASSEMBLY__ + +/* + * Cache information structure. + * + * Defined for both I and D cache, per-processor. + */ +struct cache_info { + unsigned int ways; + unsigned int sets; + unsigned int linesz; + + unsigned int way_shift; + unsigned int entry_shift; + unsigned int set_shift; + unsigned int way_step_shift; + unsigned int asid_shift; + + unsigned int way_ofs; + + unsigned int asid_mask; + unsigned int idx_mask; + unsigned int epn_mask; + + unsigned long flags; +}; + +#endif /* __ASSEMBLY__ */ + +/* Instruction cache */ +#define CACHE_IC_ADDRESS_ARRAY 0x01000000 + +/* Operand Cache */ +#define CACHE_OC_ADDRESS_ARRAY 0x01800000 + +/* These declarations relate to cache 'synonyms' in the operand cache. A + 'synonym' occurs where effective address bits overlap between those used for + indexing the cache sets and those passed to the MMU for translation. In the + case of SH5-101 & SH5-103, only bit 12 is affected for 4k pages. */ + +#define CACHE_OC_N_SYNBITS 1 /* Number of synonym bits */ +#define CACHE_OC_SYN_SHIFT 12 +/* Mask to select synonym bit(s) */ +#define CACHE_OC_SYN_MASK (((1UL< + +/* + * computes the checksum of a memory block at buff, length len, + * and adds in "sum" (32-bit) + * + * returns a 32-bit number suitable for feeding into itself + * or csum_tcpudp_magic + * + * this function must be called with even lengths, except + * for the last fragment, which may be odd + * + * it's best to have buff aligned on a 32-bit boundary + */ +asmlinkage unsigned int csum_partial(const unsigned char *buff, int len, + unsigned int sum); + +/* + * Note: when you get a NULL pointer exception here this means someone + * passed in an incorrect kernel address to one of these functions. + * + * If you use these functions directly please don't forget the + * verify_area(). + */ + + +unsigned int csum_partial_copy_nocheck(const char *src, char *dst, int len, + unsigned int sum); + +unsigned int csum_partial_copy_from_user(const char *src, char *dst, + int len, int sum, int *err_ptr); + +/* + * These are the old (and unsafe) way of doing checksums, a warning message will be + * printed if they are used and an exeption occurs. + * + * these functions should go away after some time. + */ + +#define csum_partial_copy_fromuser csum_partial_copy + +unsigned int csum_partial_copy(const char *src, char *dst, int len, + unsigned int sum); + +static inline unsigned short csum_fold(unsigned int sum) +{ + sum = (sum & 0xffff) + (sum >> 16); + sum = (sum & 0xffff) + (sum >> 16); + return ~(sum); +} + +unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl); + +unsigned long csum_tcpudp_nofold(unsigned long saddr, unsigned long daddr, + unsigned short len, unsigned short proto, + unsigned int sum); + +/* + * computes the checksum of the TCP/UDP pseudo-header + * returns a 16-bit checksum, already complemented + */ +static inline unsigned short int csum_tcpudp_magic(unsigned long saddr, + unsigned long daddr, + unsigned short len, + unsigned short proto, + unsigned int sum) +{ + return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum)); +} + +/* + * this routine is used for miscellaneous IP-like checksums, mainly + * in icmp.c + */ +static inline unsigned short ip_compute_csum(unsigned char * buff, int len) +{ + return csum_fold(csum_partial(buff, len, 0)); +} + +#endif /* __ASM_SH64_CHECKSUM_H */ + diff -puN /dev/null include/asm-sh64/cpumask.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/cpumask.h 2004-06-28 13:30:30.733131696 -0700 @@ -0,0 +1,6 @@ +#ifndef __ASM_SH64_CPUMASK_H +#define __ASM_SH64_CPUMASK_H + +#include + +#endif /* __ASM_SH64_CPUMASK_H */ diff -puN /dev/null include/asm-sh64/current.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/current.h 2004-06-28 13:30:30.733131696 -0700 @@ -0,0 +1,28 @@ +#ifndef __ASM_SH64_CURRENT_H +#define __ASM_SH64_CURRENT_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. + * + * include/asm-sh64/current.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003 Paul Mundt + * + */ + +#include + +struct task_struct; + +static __inline__ struct task_struct * get_current(void) +{ + return current_thread_info()->task; +} + +#define current get_current() + +#endif /* __ASM_SH64_CURRENT_H */ + diff -puN /dev/null include/asm-sh64/delay.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/delay.h 2004-06-28 13:30:30.734131544 -0700 @@ -0,0 +1,11 @@ +#ifndef __ASM_SH64_DELAY_H +#define __ASM_SH64_DELAY_H + +extern void __delay(int loops); +extern void __udelay(unsigned long long usecs, unsigned long lpj); +extern void __ndelay(unsigned long long nsecs, unsigned long lpj); +extern void udelay(unsigned long usecs); +extern void ndelay(unsigned long nsecs); + +#endif /* __ASM_SH64_DELAY_H */ + diff -puN /dev/null include/asm-sh64/div64.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/div64.h 2004-06-28 13:30:30.734131544 -0700 @@ -0,0 +1,6 @@ +#ifndef __ASM_SH64_DIV64_H +#define __ASM_SH64_DIV64_H + +#include + +#endif /* __ASM_SH64_DIV64_H */ diff -puN /dev/null include/asm-sh64/dma.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/dma.h 2004-06-28 13:30:30.734131544 -0700 @@ -0,0 +1,41 @@ +#ifndef __ASM_SH64_DMA_H +#define __ASM_SH64_DMA_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. + * + * include/asm-sh64/dma.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003 Paul Mundt + * + */ + +#include +#include +#include + +#define MAX_DMA_CHANNELS 4 + +/* + * SH5 can DMA in any memory area. + * + * The static definition is dodgy because it should limit + * the highest DMA-able address based on the actual + * Physical memory available. This is actually performed + * at run time in defining the memory allowed to DMA_ZONE. + */ +#define MAX_DMA_ADDRESS ~(NPHYS_MASK) + +#define DMA_MODE_READ 0 +#define DMA_MODE_WRITE 1 + +#ifdef CONFIG_PCI +extern int isa_dma_bridge_buggy; +#else +#define isa_dma_bridge_buggy (0) +#endif + +#endif /* __ASM_SH64_DMA_H */ diff -puN /dev/null include/asm-sh64/dma-mapping.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/dma-mapping.h 2004-06-28 13:30:30.735131392 -0700 @@ -0,0 +1,163 @@ +#ifndef __ASM_SH_DMA_MAPPING_H +#define __ASM_SH_DMA_MAPPING_H + +#include +#include +#include +#include +#include + +struct pci_dev; +extern void *consistent_alloc(struct pci_dev *hwdev, size_t size, + dma_addr_t *dma_handle); +extern void consistent_free(struct pci_dev *hwdev, size_t size, + void *vaddr, dma_addr_t dma_handle); + +#define dma_supported(dev, mask) (1) + +static inline int dma_set_mask(struct device *dev, u64 mask) +{ + if (!dev->dma_mask || !dma_supported(dev, mask)) + return -EIO; + + *dev->dma_mask = mask; + + return 0; +} + +static inline void *dma_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *dma_handle, int flag) +{ + return consistent_alloc(NULL, size, dma_handle); +} + +static inline void dma_free_coherent(struct device *dev, size_t size, + void *vaddr, dma_addr_t dma_handle) +{ + consistent_free(NULL, size, vaddr, dma_handle); +} + +static inline void dma_cache_sync(void *vaddr, size_t size, + enum dma_data_direction dir) +{ + dma_cache_wback_inv((unsigned long)vaddr, size); +} + +static inline dma_addr_t dma_map_single(struct device *dev, + void *ptr, size_t size, + enum dma_data_direction dir) +{ +#if defined(CONFIG_PCI) && !defined(CONFIG_SH_PCIDMA_NONCOHERENT) + if (dev->bus == &pci_bus_type) + return virt_to_bus(ptr); +#endif + dma_cache_sync(ptr, size, dir); + + return virt_to_bus(ptr); +} + +#define dma_unmap_single(dev, addr, size, dir) do { } while (0) + +static inline int dma_map_sg(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction dir) +{ + int i; + + for (i = 0; i < nents; i++) { +#if !defined(CONFIG_PCI) || defined(CONFIG_SH_PCIDMA_NONCOHERENT) + dma_cache_sync(page_address(sg[i].page) + sg[i].offset, + sg[i].length, dir); +#endif + sg[i].dma_address = page_to_phys(sg[i].page) + sg[i].offset; + } + + return nents; +} + +#define dma_unmap_sg(dev, sg, nents, dir) do { } while (0) + +static inline dma_addr_t dma_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, + enum dma_data_direction dir) +{ + return dma_map_single(dev, page_address(page) + offset, size, dir); +} + +static inline void dma_unmap_page(struct device *dev, dma_addr_t dma_address, + size_t size, enum dma_data_direction dir) +{ + dma_unmap_single(dev, dma_address, size, dir); +} + +static inline void dma_sync_single(struct device *dev, dma_addr_t dma_handle, + size_t size, enum dma_data_direction dir) +{ +#if defined(CONFIG_PCI) && !defined(CONFIG_SH_PCIDMA_NONCOHERENT) + if (dev->bus == &pci_bus_type) + return; +#endif + dma_cache_sync(bus_to_virt(dma_handle), size, dir); +} + +static inline void dma_sync_single_range(struct device *dev, + dma_addr_t dma_handle, + unsigned long offset, size_t size, + enum dma_data_direction dir) +{ +#if defined(CONFIG_PCI) && !defined(CONFIG_SH_PCIDMA_NONCOHERENT) + if (dev->bus == &pci_bus_type) + return; +#endif + dma_cache_sync(bus_to_virt(dma_handle) + offset, size, dir); +} + +static inline void dma_sync_sg(struct device *dev, struct scatterlist *sg, + int nelems, enum dma_data_direction dir) +{ + int i; + + for (i = 0; i < nelems; i++) { +#if !defined(CONFIG_PCI) || defined(CONFIG_SH_PCIDMA_NONCOHERENT) + dma_cache_sync(page_address(sg[i].page) + sg[i].offset, + sg[i].length, dir); +#endif + sg[i].dma_address = page_to_phys(sg[i].page) + sg[i].offset; + } +} + +static inline void dma_sync_single_for_cpu(struct device *dev, + dma_addr_t dma_handle, size_t size, + enum dma_data_direction dir) + __attribute__ ((alias("dma_sync_single"))); + +static inline void dma_sync_single_for_device(struct device *dev, + dma_addr_t dma_handle, size_t size, + enum dma_data_direction dir) + __attribute__ ((alias("dma_sync_single"))); + +static inline void dma_sync_sg_for_cpu(struct device *dev, + struct scatterlist *sg, int nelems, + enum dma_data_direction dir) + __attribute__ ((alias("dma_sync_sg"))); + +static inline void dma_sync_sg_for_device(struct device *dev, + struct scatterlist *sg, int nelems, + enum dma_data_direction dir) + __attribute__ ((alias("dma_sync_sg"))); + +static inline int dma_get_cache_alignment(void) +{ + /* + * Each processor family will define its own L1_CACHE_SHIFT, + * L1_CACHE_BYTES wraps to this, so this is always safe. + */ + return L1_CACHE_BYTES; +} + +static inline int dma_mapping_error(dma_addr_t dma_addr) +{ + return dma_addr == 0; +} + +#endif /* __ASM_SH_DMA_MAPPING_H */ + diff -puN /dev/null include/asm-sh64/elf.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/elf.h 2004-06-28 13:30:30.736131240 -0700 @@ -0,0 +1,101 @@ +#ifndef __ASM_SH64_ELF_H +#define __ASM_SH64_ELF_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. + * + * include/asm-sh64/elf.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + */ + +/* + * ELF register definitions.. + */ + +#include +#include +#include + +typedef unsigned long elf_greg_t; + +#define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t)) +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +typedef struct user_fpu_struct elf_fpregset_t; + +/* + * This is used to ensure we don't load something for the wrong architecture. + */ +#define elf_check_arch(x) ( (x)->e_machine == EM_SH ) + +/* + * These are used to set parameters in the core dumps. + */ +#define ELF_CLASS ELFCLASS32 +#ifdef __LITTLE_ENDIAN__ +#define ELF_DATA ELFDATA2LSB +#else +#define ELF_DATA ELFDATA2MSB +#endif +#define ELF_ARCH EM_SH + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +/* This is the location that an ET_DYN program is loaded if exec'ed. Typical + use of this is to invoke "./ld.so someprog" to test out a new version of + the loader. We need to make sure that it is out of the way of the program + that it will "exec", and that there is sufficient room for the brk. */ + +#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3) + + +#define ELF_CORE_COPY_REGS(_dest,_regs) \ + memcpy((char *) &_dest, (char *) _regs, \ + sizeof(struct pt_regs)); + +/* This yields a mask that user programs can use to figure out what + instruction set this CPU supports. This could be done in user space, + but it's not easy, and we've already done it here. */ + +#define ELF_HWCAP (0) + +/* This yields a string that ld.so will use to load implementation + specific libraries for optimization. This is more specific in + intent than poking at uname or /proc/cpuinfo. + + For the moment, we have only optimizations for the Intel generations, + but that could change... */ + +#define ELF_PLATFORM (NULL) + +#define ELF_PLAT_INIT(_r, load_addr) \ + do { _r->regs[0]=0; _r->regs[1]=0; _r->regs[2]=0; _r->regs[3]=0; \ + _r->regs[4]=0; _r->regs[5]=0; _r->regs[6]=0; _r->regs[7]=0; \ + _r->regs[8]=0; _r->regs[9]=0; _r->regs[10]=0; _r->regs[11]=0; \ + _r->regs[12]=0; _r->regs[13]=0; _r->regs[14]=0; _r->regs[15]=0; \ + _r->regs[16]=0; _r->regs[17]=0; _r->regs[18]=0; _r->regs[19]=0; \ + _r->regs[20]=0; _r->regs[21]=0; _r->regs[22]=0; _r->regs[23]=0; \ + _r->regs[24]=0; _r->regs[25]=0; _r->regs[26]=0; _r->regs[27]=0; \ + _r->regs[28]=0; _r->regs[29]=0; _r->regs[30]=0; _r->regs[31]=0; \ + _r->regs[32]=0; _r->regs[33]=0; _r->regs[34]=0; _r->regs[35]=0; \ + _r->regs[36]=0; _r->regs[37]=0; _r->regs[38]=0; _r->regs[39]=0; \ + _r->regs[40]=0; _r->regs[41]=0; _r->regs[42]=0; _r->regs[43]=0; \ + _r->regs[44]=0; _r->regs[45]=0; _r->regs[46]=0; _r->regs[47]=0; \ + _r->regs[48]=0; _r->regs[49]=0; _r->regs[50]=0; _r->regs[51]=0; \ + _r->regs[52]=0; _r->regs[53]=0; _r->regs[54]=0; _r->regs[55]=0; \ + _r->regs[56]=0; _r->regs[57]=0; _r->regs[58]=0; _r->regs[59]=0; \ + _r->regs[60]=0; _r->regs[61]=0; _r->regs[62]=0; \ + _r->tregs[0]=0; _r->tregs[1]=0; _r->tregs[2]=0; _r->tregs[3]=0; \ + _r->tregs[4]=0; _r->tregs[5]=0; _r->tregs[6]=0; _r->tregs[7]=0; \ + _r->sr = SR_FD | SR_MMU; } while (0) + +#ifdef __KERNEL__ +#define SET_PERSONALITY(ex, ibcs2) set_personality(PER_LINUX_32BIT) +#endif + +#endif /* __ASM_SH64_ELF_H */ diff -puN /dev/null include/asm-sh64/errno.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/errno.h 2004-06-28 13:30:30.736131240 -0700 @@ -0,0 +1,6 @@ +#ifndef __ASM_SH64_ERRNO_H +#define __ASM_SH64_ERRNO_H + +#include + +#endif /* __ASM_SH64_ERRNO_H */ diff -puN /dev/null include/asm-sh64/fcntl.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/fcntl.h 2004-06-28 13:30:30.736131240 -0700 @@ -0,0 +1,7 @@ +#ifndef __ASM_SH64_FCNTL_H +#define __ASM_SH64_FCNTL_H + +#include + +#endif /* __ASM_SH64_FCNTL_H */ + diff -puN /dev/null include/asm-sh64/hardirq.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/hardirq.h 2004-06-28 13:30:30.737131088 -0700 @@ -0,0 +1,7 @@ +#ifndef __ASM_SH64_HARDIRQ_H +#define __ASM_SH64_HARDIRQ_H + +#include + +#endif /* __ASM_SH64_HARDIRQ_H */ + diff -puN /dev/null include/asm-sh64/hardware.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/hardware.h 2004-06-28 13:30:30.737131088 -0700 @@ -0,0 +1,45 @@ +#ifndef __ASM_SH64_HARDWARE_H +#define __ASM_SH64_HARDWARE_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. + * + * include/asm-sh64/hardware.h + * + * Copyright (C) 2002 Stuart Menefy + * Copyright (C) 2003 Paul Mundt + * + * Defitions of the locations of registers in the physical address space. + */ + +#define PHYS_PERIPHERAL_BLOCK 0x09000000 +#define PHYS_DMAC_BLOCK 0x0e000000 +#define PHYS_PCI_BLOCK 0x60000000 + +#ifndef __ASSEMBLY__ +#include +#include + +struct vcr_info { + u8 perr_flags; /* P-port Error flags */ + u8 merr_flags; /* Module Error flags */ + u16 mod_vers; /* Module Version */ + u16 mod_id; /* Module ID */ + u8 bot_mb; /* Bottom Memory block */ + u8 top_mb; /* Top Memory block */ +}; + +static inline struct vcr_info sh64_get_vcr_info(unsigned long base) +{ + unsigned long long tmp; + + tmp = sh64_in64(base); + + return *((struct vcr_info *)&tmp); +} + +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_SH64_HARDWARE_H */ diff -puN /dev/null include/asm-sh64/hdreg.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/hdreg.h 2004-06-28 13:30:30.737131088 -0700 @@ -0,0 +1,6 @@ +#ifndef __ASM_SH64_HDREG_H +#define __ASM_SH64_HDREG_H + +#include + +#endif /* __ASM_SH64_HDREG_H */ diff -puN /dev/null include/asm-sh64/hw_irq.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/hw_irq.h 2004-06-28 13:30:30.738130936 -0700 @@ -0,0 +1,16 @@ +#ifndef __ASM_SH64_HW_IRQ_H +#define __ASM_SH64_HW_IRQ_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. + * + * include/asm-sh64/hw_irq.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + */ +static __inline__ void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) { /* Nothing to do */ } + +#endif /* __ASM_SH64_HW_IRQ_H */ diff -puN /dev/null include/asm-sh64/ide.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/ide.h 2004-06-28 13:30:30.738130936 -0700 @@ -0,0 +1,30 @@ +/* + * linux/include/asm-sh64/ide.h + * + * Copyright (C) 1994-1996 Linus Torvalds & authors + * + * sh64 version by Richard Curnow & Paul Mundt + */ + +/* + * This file contains the sh64 architecture specific IDE code. + */ + +#ifndef __ASM_SH64_IDE_H +#define __ASM_SH64_IDE_H + +#ifdef __KERNEL__ + +#include + +#ifndef MAX_HWIFS +#define MAX_HWIFS CONFIG_IDE_MAX_HWIFS +#endif + +#define ide_default_io_ctl(base) (0) + +#include + +#endif /* __KERNEL__ */ + +#endif /* __ASM_SH64_IDE_H */ diff -puN /dev/null include/asm-sh64/ioctl.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/ioctl.h 2004-06-28 13:30:30.739130784 -0700 @@ -0,0 +1,83 @@ +#ifndef __ASM_SH64_IOCTL_H +#define __ASM_SH64_IOCTL_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. + * + * include/asm-sh64/ioctl.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + * linux/ioctl.h for Linux by H.H. Bergman. + * + */ + +/* ioctl command encoding: 32 bits total, command in lower 16 bits, + * size of the parameter structure in the lower 14 bits of the + * upper 16 bits. + * Encoding the size of the parameter structure in the ioctl request + * is useful for catching programs compiled with old versions + * and to avoid overwriting user space outside the user buffer area. + * The highest 2 bits are reserved for indicating the ``access mode''. + * NOTE: This limits the max parameter size to 16kB -1 ! + */ + +/* + * The following is for compatibility across the various Linux + * platforms. The i386 ioctl numbering scheme doesn't really enforce + * a type field. De facto, however, the top 8 bits of the lower 16 + * bits are indeed used as a type field, so we might just as well make + * this explicit here. Please be sure to use the decoding macros + * below from now on. + */ +#define _IOC_NRBITS 8 +#define _IOC_TYPEBITS 8 +#define _IOC_SIZEBITS 14 +#define _IOC_DIRBITS 2 + +#define _IOC_NRMASK ((1 << _IOC_NRBITS)-1) +#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS)-1) +#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS)-1) +#define _IOC_DIRMASK ((1 << _IOC_DIRBITS)-1) + +#define _IOC_NRSHIFT 0 +#define _IOC_TYPESHIFT (_IOC_NRSHIFT+_IOC_NRBITS) +#define _IOC_SIZESHIFT (_IOC_TYPESHIFT+_IOC_TYPEBITS) +#define _IOC_DIRSHIFT (_IOC_SIZESHIFT+_IOC_SIZEBITS) + +/* + * Direction bits. + */ +#define _IOC_NONE 0U +#define _IOC_WRITE 1U +#define _IOC_READ 2U + +#define _IOC(dir,type,nr,size) \ + (((dir) << _IOC_DIRSHIFT) | \ + ((type) << _IOC_TYPESHIFT) | \ + ((nr) << _IOC_NRSHIFT) | \ + ((size) << _IOC_SIZESHIFT)) + +/* used to create numbers */ +#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0) +#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size)) +#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size)) +#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size)) + +/* used to decode ioctl numbers.. */ +#define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK) +#define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK) +#define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK) +#define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK) + +/* ...and for the drivers/sound files... */ + +#define IOC_IN (_IOC_WRITE << _IOC_DIRSHIFT) +#define IOC_OUT (_IOC_READ << _IOC_DIRSHIFT) +#define IOC_INOUT ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT) +#define IOCSIZE_MASK (_IOC_SIZEMASK << _IOC_SIZESHIFT) +#define IOCSIZE_SHIFT (_IOC_SIZESHIFT) + +#endif /* __ASM_SH64_IOCTL_H */ diff -puN /dev/null include/asm-sh64/ioctls.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/ioctls.h 2004-06-28 13:30:30.739130784 -0700 @@ -0,0 +1,111 @@ +#ifndef __ASM_SH64_IOCTLS_H +#define __ASM_SH64_IOCTLS_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. + * + * include/asm-sh64/ioctls.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + */ + +#include + +#define FIOCLEX _IO('f', 1) +#define FIONCLEX _IO('f', 2) +#define FIOASYNC _IOW('f', 125, int) +#define FIONBIO _IOW('f', 126, int) +#define FIONREAD _IOR('f', 127, int) +#define TIOCINQ FIONREAD +#define FIOQSIZE _IOR('f', 128, loff_t) + +#define TCGETS 0x5401 +#define TCSETS 0x5402 +#define TCSETSW 0x5403 +#define TCSETSF 0x5404 + +#define TCGETA _IOR('t', 23, struct termio) +#define TCSETA _IOW('t', 24, struct termio) +#define TCSETAW _IOW('t', 25, struct termio) +#define TCSETAF _IOW('t', 28, struct termio) + +#define TCSBRK _IO('t', 29) +#define TCXONC _IO('t', 30) +#define TCFLSH _IO('t', 31) + +#define TIOCSWINSZ _IOW('t', 103, struct winsize) +#define TIOCGWINSZ _IOR('t', 104, struct winsize) +#define TIOCSTART _IO('t', 110) /* start output, like ^Q */ +#define TIOCSTOP _IO('t', 111) /* stop output, like ^S */ +#define TIOCOUTQ _IOR('t', 115, int) /* output queue size */ + +#define TIOCSPGRP _IOW('t', 118, int) +#define TIOCGPGRP _IOR('t', 119, int) + +#define TIOCEXCL _IO('T', 12) /* 0x540C */ +#define TIOCNXCL _IO('T', 13) /* 0x540D */ +#define TIOCSCTTY _IO('T', 14) /* 0x540E */ + +#define TIOCSTI _IOW('T', 18, char) /* 0x5412 */ +#define TIOCMGET _IOR('T', 21, unsigned int) /* 0x5415 */ +#define TIOCMBIS _IOW('T', 22, unsigned int) /* 0x5416 */ +#define TIOCMBIC _IOW('T', 23, unsigned int) /* 0x5417 */ +#define TIOCMSET _IOW('T', 24, unsigned int) /* 0x5418 */ +# define TIOCM_LE 0x001 +# define TIOCM_DTR 0x002 +# define TIOCM_RTS 0x004 +# define TIOCM_ST 0x008 +# define TIOCM_SR 0x010 +# define TIOCM_CTS 0x020 +# define TIOCM_CAR 0x040 +# define TIOCM_RNG 0x080 +# define TIOCM_DSR 0x100 +# define TIOCM_CD TIOCM_CAR +# define TIOCM_RI TIOCM_RNG + +#define TIOCGSOFTCAR _IOR('T', 25, unsigned int) /* 0x5419 */ +#define TIOCSSOFTCAR _IOW('T', 26, unsigned int) /* 0x541A */ +#define TIOCLINUX _IOW('T', 28, char) /* 0x541C */ +#define TIOCCONS _IO('T', 29) /* 0x541D */ +#define TIOCGSERIAL _IOR('T', 30, struct serial_struct) /* 0x541E */ +#define TIOCSSERIAL _IOW('T', 31, struct serial_struct) /* 0x541F */ +#define TIOCPKT _IOW('T', 32, int) /* 0x5420 */ +# define TIOCPKT_DATA 0 +# define TIOCPKT_FLUSHREAD 1 +# define TIOCPKT_FLUSHWRITE 2 +# define TIOCPKT_STOP 4 +# define TIOCPKT_START 8 +# define TIOCPKT_NOSTOP 16 +# define TIOCPKT_DOSTOP 32 + + +#define TIOCNOTTY _IO('T', 34) /* 0x5422 */ +#define TIOCSETD _IOW('T', 35, int) /* 0x5423 */ +#define TIOCGETD _IOR('T', 36, int) /* 0x5424 */ +#define TCSBRKP _IOW('T', 37, int) /* 0x5425 */ /* Needed for POSIX tcsendbreak() */ +#define TIOCTTYGSTRUCT _IOR('T', 38, struct tty_struct) /* 0x5426 */ /* For debugging only */ +#define TIOCSBRK _IO('T', 39) /* 0x5427 */ /* BSD compatibility */ +#define TIOCCBRK _IO('T', 40) /* 0x5428 */ /* BSD compatibility */ +#define TIOCGSID _IOR('T', 41, pid_t) /* 0x5429 */ /* Return the session ID of FD */ +#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ + +#define TIOCSERCONFIG _IO('T', 83) /* 0x5453 */ +#define TIOCSERGWILD _IOR('T', 84, int) /* 0x5454 */ +#define TIOCSERSWILD _IOW('T', 85, int) /* 0x5455 */ +#define TIOCGLCKTRMIOS 0x5456 +#define TIOCSLCKTRMIOS 0x5457 +#define TIOCSERGSTRUCT _IOR('T', 88, struct async_struct) /* 0x5458 */ /* For debugging only */ +#define TIOCSERGETLSR _IOR('T', 89, unsigned int) /* 0x5459 */ /* Get line status register */ + /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ +# define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ +#define TIOCSERGETMULTI _IOR('T', 90, struct serial_multiport_struct) /* 0x545A */ /* Get multiport config */ +#define TIOCSERSETMULTI _IOW('T', 91, struct serial_multiport_struct) /* 0x545B */ /* Set multiport config */ + +#define TIOCMIWAIT _IO('T', 92) /* 0x545C */ /* wait for a change on serial input line(s) */ +#define TIOCGICOUNT _IOR('T', 93, struct async_icount) /* 0x545D */ /* read serial port inline interrupt counts */ + +#endif /* __ASM_SH64_IOCTLS_H */ diff -puN /dev/null include/asm-sh64/io.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/io.h 2004-06-28 13:30:30.741130480 -0700 @@ -0,0 +1,217 @@ +#ifndef __ASM_SH64_IO_H +#define __ASM_SH64_IO_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. + * + * include/asm-sh64/io.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003 Paul Mundt + * + */ + +/* + * Convention: + * read{b,w,l}/write{b,w,l} are for PCI, + * while in{b,w,l}/out{b,w,l} are for ISA + * These may (will) be platform specific function. + * + * In addition, we have + * ctrl_in{b,w,l}/ctrl_out{b,w,l} for SuperH specific I/O. + * which are processor specific. Address should be the result of + * onchip_remap(); + */ + +#include +#include +#include + +#define virt_to_bus virt_to_phys +#define bus_to_virt phys_to_virt +#define page_to_bus page_to_phys + +/* + * Nothing overly special here.. instead of doing the same thing + * over and over again, we just define a set of sh64_in/out functions + * with an implicit size. The traditional read{b,w,l}/write{b,w,l} + * mess is wrapped to this, as are the SH-specific ctrl_in/out routines. + */ +static inline unsigned char sh64_in8(unsigned long addr) +{ + return *(volatile unsigned char *)addr; +} + +static inline unsigned short sh64_in16(unsigned long addr) +{ + return *(volatile unsigned short *)addr; +} + +static inline unsigned long sh64_in32(unsigned long addr) +{ + return *(volatile unsigned long *)addr; +} + +static inline unsigned long long sh64_in64(unsigned long addr) +{ + return *(volatile unsigned long long *)addr; +} + +static inline void sh64_out8(unsigned char b, unsigned long addr) +{ + *(volatile unsigned char *)addr = b; + wmb(); +} + +static inline void sh64_out16(unsigned short b, unsigned long addr) +{ + *(volatile unsigned short *)addr = b; + wmb(); +} + +static inline void sh64_out32(unsigned long b, unsigned long addr) +{ + *(volatile unsigned long *)addr = b; + wmb(); +} + +static inline void sh64_out64(unsigned long long b, unsigned long addr) +{ + *(volatile unsigned long long *)addr = b; + wmb(); +} + +#define readb(addr) sh64_in8(addr) +#define readw(addr) sh64_in16(addr) +#define readl(addr) sh64_in32(addr) + +#define writeb(b, addr) sh64_out8(b, addr) +#define writew(b, addr) sh64_out16(b, addr) +#define writel(b, addr) sh64_out32(b, addr) + +#define ctrl_inb(addr) sh64_in8(addr) +#define ctrl_inw(addr) sh64_in16(addr) +#define ctrl_inl(addr) sh64_in32(addr) + +#define ctrl_outb(b, addr) sh64_out8(b, addr) +#define ctrl_outw(b, addr) sh64_out16(b, addr) +#define ctrl_outl(b, addr) sh64_out32(b, addr) + +unsigned long inb(unsigned long port); +unsigned long inw(unsigned long port); +unsigned long inl(unsigned long port); +void outb(unsigned long value, unsigned long port); +void outw(unsigned long value, unsigned long port); +void outl(unsigned long value, unsigned long port); + +#ifdef __KERNEL__ + +#ifdef CONFIG_SH_CAYMAN +extern unsigned long smsc_superio_virt; +#endif +#ifdef CONFIG_PCI +extern unsigned long pciio_virt; +#endif + +#define IO_SPACE_LIMIT 0xffffffff + +/* + * Change virtual addresses to physical addresses and vv. + * These are trivial on the 1:1 Linux/SuperH mapping + */ +extern __inline__ unsigned long virt_to_phys(volatile void * address) +{ + return __pa(address); +} + +extern __inline__ void * phys_to_virt(unsigned long address) +{ + return __va(address); +} + +extern void * __ioremap(unsigned long phys_addr, unsigned long size, + unsigned long flags); + +extern __inline__ void * ioremap(unsigned long phys_addr, unsigned long size) +{ + return __ioremap(phys_addr, size, 1); +} + +extern __inline__ void * ioremap_nocache (unsigned long phys_addr, unsigned long size) +{ + return __ioremap(phys_addr, size, 0); +} + +extern void iounmap(void *addr); + +unsigned long onchip_remap(unsigned long addr, unsigned long size, const char* name); +extern void onchip_unmap(unsigned long vaddr); + +static __inline__ int check_signature(unsigned long io_addr, + const unsigned char *signature, int length) +{ + int retval = 0; + do { + if (readb(io_addr) != *signature) + goto out; + io_addr++; + signature++; + length--; + } while (length); + retval = 1; +out: + return retval; +} + +/* + * The caches on some architectures aren't dma-coherent and have need to + * handle this in software. There are three types of operations that + * can be applied to dma buffers. + * + * - dma_cache_wback_inv(start, size) makes caches and RAM coherent by + * writing the content of the caches back to memory, if necessary. + * The function also invalidates the affected part of the caches as + * necessary before DMA transfers from outside to memory. + * - dma_cache_inv(start, size) invalidates the affected parts of the + * caches. Dirty lines of the caches may be written back or simply + * be discarded. This operation is necessary before dma operations + * to the memory. + * - dma_cache_wback(start, size) writes back any dirty lines but does + * not invalidate the cache. This can be used before DMA reads from + * memory, + */ + +static __inline__ void dma_cache_wback_inv (unsigned long start, unsigned long size) +{ + unsigned long s = start & L1_CACHE_ALIGN_MASK; + unsigned long e = (start + size) & L1_CACHE_ALIGN_MASK; + + for (; s <= e; s += L1_CACHE_BYTES) + asm volatile ("ocbp %0, 0" : : "r" (s)); +} + +static __inline__ void dma_cache_inv (unsigned long start, unsigned long size) +{ + // Note that caller has to be careful with overzealous + // invalidation should there be partial cache lines at the extremities + // of the specified range + unsigned long s = start & L1_CACHE_ALIGN_MASK; + unsigned long e = (start + size) & L1_CACHE_ALIGN_MASK; + + for (; s <= e; s += L1_CACHE_BYTES) + asm volatile ("ocbi %0, 0" : : "r" (s)); +} + +static __inline__ void dma_cache_wback (unsigned long start, unsigned long size) +{ + unsigned long s = start & L1_CACHE_ALIGN_MASK; + unsigned long e = (start + size) & L1_CACHE_ALIGN_MASK; + + for (; s <= e; s += L1_CACHE_BYTES) + asm volatile ("ocbwb %0, 0" : : "r" (s)); +} + +#endif /* __KERNEL__ */ +#endif /* __ASM_SH64_IO_H */ diff -puN /dev/null include/asm-sh64/ipcbuf.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/ipcbuf.h 2004-06-28 13:30:30.741130480 -0700 @@ -0,0 +1,40 @@ +#ifndef __ASM_SH64_IPCBUF_H__ +#define __ASM_SH64_IPCBUF_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. + * + * include/asm-sh64/ipcbuf.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + */ + +/* + * The ipc64_perm structure for i386 architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 32-bit mode_t and seq + * - 2 miscellaneous 32-bit values + */ + +struct ipc64_perm +{ + __kernel_key_t key; + __kernel_uid32_t uid; + __kernel_gid32_t gid; + __kernel_uid32_t cuid; + __kernel_gid32_t cgid; + __kernel_mode_t mode; + unsigned short __pad1; + unsigned short seq; + unsigned short __pad2; + unsigned long __unused1; + unsigned long __unused2; +}; + +#endif /* __ASM_SH64_IPCBUF_H__ */ diff -puN /dev/null include/asm-sh64/ipc.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/ipc.h 2004-06-28 13:30:30.741130480 -0700 @@ -0,0 +1,6 @@ +#ifndef __ASM_SH64_IPC_H +#define __ASM_SH64_IPC_H + +#include + +#endif /* __ASM_SH64_IPC_H */ diff -puN /dev/null include/asm-sh64/irq.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/irq.h 2004-06-28 13:30:30.742130328 -0700 @@ -0,0 +1,148 @@ +#ifndef __ASM_SH64_IRQ_H +#define __ASM_SH64_IRQ_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. + * + * include/asm-sh64/irq.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + */ + +#include + +/* + * Encoded IRQs are not considered worth to be supported. + * Main reason is that there's no per-encoded-interrupt + * enable/disable mechanism (as there was in SH3/4). + * An all enabled/all disabled is worth only if there's + * a cascaded IC to disable/enable/ack on. Until such + * IC is available there's no such support. + * + * Presumably Encoded IRQs may use extra IRQs beyond 64, + * below. Some logic must be added to cope with IRQ_IRL? + * in an exclusive way. + * + * Priorities are set at Platform level, when IRQ_IRL0-3 + * are set to 0 Encoding is allowed. Otherwise it's not + * allowed. + */ + +/* Independent IRQs */ +#define IRQ_IRL0 0 +#define IRQ_IRL1 1 +#define IRQ_IRL2 2 +#define IRQ_IRL3 3 + +#define IRQ_INTA 4 +#define IRQ_INTB 5 +#define IRQ_INTC 6 +#define IRQ_INTD 7 + +#define IRQ_SERR 12 +#define IRQ_ERR 13 +#define IRQ_PWR3 14 +#define IRQ_PWR2 15 +#define IRQ_PWR1 16 +#define IRQ_PWR0 17 + +#define IRQ_DMTE0 18 +#define IRQ_DMTE1 19 +#define IRQ_DMTE2 20 +#define IRQ_DMTE3 21 +#define IRQ_DAERR 22 + +#define IRQ_TUNI0 32 +#define IRQ_TUNI1 33 +#define IRQ_TUNI2 34 +#define IRQ_TICPI2 35 + +#define IRQ_ATI 36 +#define IRQ_PRI 37 +#define IRQ_CUI 38 + +#define IRQ_ERI 39 +#define IRQ_RXI 40 +#define IRQ_BRI 41 +#define IRQ_TXI 42 + +#define IRQ_ITI 63 + +#define NR_INTC_IRQS 64 + +#ifdef CONFIG_SH_CAYMAN +#define NR_EXT_IRQS 32 +#define START_EXT_IRQS 64 + +/* PCI bus 2 uses encoded external interrupts on the Cayman board */ +#define IRQ_P2INTA (START_EXT_IRQS + (3*8) + 0) +#define IRQ_P2INTB (START_EXT_IRQS + (3*8) + 1) +#define IRQ_P2INTC (START_EXT_IRQS + (3*8) + 2) +#define IRQ_P2INTD (START_EXT_IRQS + (3*8) + 3) + +#define START_EXT_IRQS 64 + +#define I8042_KBD_IRQ (START_EXT_IRQS + 2) +#define I8042_AUX_IRQ (START_EXT_IRQS + 6) + +#else +#define NR_EXT_IRQS 0 +#endif + +#define NR_IRQS (NR_INTC_IRQS+NR_EXT_IRQS) + + +/* Default IRQs, fixed */ +#define TIMER_IRQ IRQ_TUNI0 +#define RTC_IRQ IRQ_CUI + +/* Default Priorities, Platform may choose differently */ +#define NO_PRIORITY 0 /* Disabled */ +#define TIMER_PRIORITY 2 +#define RTC_PRIORITY TIMER_PRIORITY +#define SCIF_PRIORITY 3 +#define INTD_PRIORITY 3 +#define IRL3_PRIORITY 4 +#define INTC_PRIORITY 6 +#define IRL2_PRIORITY 7 +#define INTB_PRIORITY 9 +#define IRL1_PRIORITY 10 +#define INTA_PRIORITY 12 +#define IRL0_PRIORITY 13 +#define TOP_PRIORITY 15 + +extern void disable_irq(unsigned int); +extern void disable_irq_nosync(unsigned int); +extern void enable_irq(unsigned int); + +extern int intc_evt_to_irq[(0xE20/0x20)+1]; +int intc_irq_describe(char* p, int irq); + +#define irq_canonicalize(irq) (irq) + +#ifdef CONFIG_SH_CAYMAN +int cayman_irq_demux(int evt); +int cayman_irq_describe(char* p, int irq); +#define irq_demux(x) cayman_irq_demux(x) +#define irq_describe(p, x) cayman_irq_describe(p, x) +#else +#define irq_demux(x) (intc_evt_to_irq[x]) +#define irq_describe(p, x) intc_irq_describe(p, x) +#endif + +/* + * Function for "on chip support modules". + */ + +/* + * SH-5 supports Priority based interrupts only. + * Interrupt priorities are defined at platform level. + */ +#define set_ipr_data(a, b, c, d) +#define make_ipr_irq(a) +#define make_imask_irq(a) + +#endif /* __ASM_SH64_IRQ_H */ diff -puN /dev/null include/asm-sh64/keyboard.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/keyboard.h 2004-06-28 13:30:30.743130176 -0700 @@ -0,0 +1,74 @@ +/* + * linux/include/asm-shmedia/keyboard.h + * + * Copied from i386 version: + * Created 3 Nov 1996 by Geert Uytterhoeven + */ + +/* + * This file contains the i386 architecture specific keyboard definitions + */ + +#ifndef __ASM_SH64_KEYBOARD_H +#define __ASM_SH64_KEYBOARD_H + +#ifdef __KERNEL__ + +#include +#include +#include + +#ifdef CONFIG_SH_CAYMAN +#define KEYBOARD_IRQ (START_EXT_IRQS + 2) /* SMSC SuperIO IRQ 1 */ +#endif +#define DISABLE_KBD_DURING_INTERRUPTS 0 + +extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); +extern int pckbd_getkeycode(unsigned int scancode); +extern int pckbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode); +extern char pckbd_unexpected_up(unsigned char keycode); +extern void pckbd_leds(unsigned char leds); +extern void pckbd_init_hw(void); +extern unsigned char pckbd_sysrq_xlate[128]; + +#define kbd_setkeycode pckbd_setkeycode +#define kbd_getkeycode pckbd_getkeycode +#define kbd_translate pckbd_translate +#define kbd_unexpected_up pckbd_unexpected_up +#define kbd_leds pckbd_leds +#define kbd_init_hw pckbd_init_hw +#define kbd_sysrq_xlate pckbd_sysrq_xlate + +#define SYSRQ_KEY 0x54 + +/* resource allocation */ +#define kbd_request_region() +#define kbd_request_irq(handler) request_irq(KEYBOARD_IRQ, handler, 0, \ + "keyboard", NULL) + +/* How to access the keyboard macros on this platform. */ +#define kbd_read_input() inb(KBD_DATA_REG) +#define kbd_read_status() inb(KBD_STATUS_REG) +#define kbd_write_output(val) outb(val, KBD_DATA_REG) +#define kbd_write_command(val) outb(val, KBD_CNTL_REG) + +/* Some stoneage hardware needs delays after some operations. */ +#define kbd_pause() do { } while(0) + +/* + * Machine specific bits for the PS/2 driver + */ + +#ifdef CONFIG_SH_CAYMAN +#define AUX_IRQ (START_EXT_IRQS + 6) /* SMSC SuperIO IRQ12 */ +#endif + +#define aux_request_irq(hand, dev_id) \ + request_irq(AUX_IRQ, hand, SA_SHIRQ, "PS/2 Mouse", dev_id) + +#define aux_free_irq(dev_id) free_irq(AUX_IRQ, dev_id) + +#endif /* __KERNEL__ */ +#endif /* __ASM_SH64_KEYBOARD_H */ + diff -puN /dev/null include/asm-sh64/kmap_types.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/kmap_types.h 2004-06-28 13:30:30.743130176 -0700 @@ -0,0 +1,7 @@ +#ifndef __ASM_SH64_KMAP_TYPES_H +#define __ASM_SH64_KMAP_TYPES_H + +#include + +#endif /* __ASM_SH64_KMAP_TYPES_H */ + diff -puN /dev/null include/asm-sh64/linkage.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/linkage.h 2004-06-28 13:30:30.743130176 -0700 @@ -0,0 +1,7 @@ +#ifndef __ASM_SH64_LINKAGE_H +#define __ASM_SH64_LINKAGE_H + +#include + +#endif /* __ASM_SH64_LINKAGE_H */ + diff -puN /dev/null include/asm-sh64/local.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/local.h 2004-06-28 13:30:30.743130176 -0700 @@ -0,0 +1,7 @@ +#ifndef __ASM_SH64_LOCAL_H +#define __ASM_SH64_LOCAL_H + +#include + +#endif /* __ASM_SH64_LOCAL_H */ + diff -puN /dev/null include/asm-sh64/mc146818rtc.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/mc146818rtc.h 2004-06-28 13:30:30.743130176 -0700 @@ -0,0 +1,7 @@ +/* + * linux/include/asm-sh64/mc146818rtc.h + * +*/ + +/* For now, an empty place-holder to get IDE to compile. */ + diff -puN /dev/null include/asm-sh64/mman.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/mman.h 2004-06-28 13:30:30.744130024 -0700 @@ -0,0 +1,6 @@ +#ifndef __ASM_SH64_MMAN_H +#define __ASM_SH64_MMAN_H + +#include + +#endif /* __ASM_SH64_MMAN_H */ diff -puN /dev/null include/asm-sh64/mmu_context.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/mmu_context.h 2004-06-28 13:30:30.745129872 -0700 @@ -0,0 +1,209 @@ +#ifndef __ASM_SH64_MMU_CONTEXT_H +#define __ASM_SH64_MMU_CONTEXT_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. + * + * include/asm-sh64/mmu_context.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003 Paul Mundt + * + * ASID handling idea taken from MIPS implementation. + * + */ + +#ifndef __ASSEMBLY__ + +/* + * Cache of MMU context last used. + * + * The MMU "context" consists of two things: + * (a) TLB cache version (or cycle, top 24 bits of mmu_context_cache) + * (b) ASID (Address Space IDentifier, bottom 8 bits of mmu_context_cache) + */ +extern unsigned long mmu_context_cache; + +#include +#include + + +/* Current mm's pgd */ +extern pgd_t *mmu_pdtp_cache; + +#define SR_ASID_MASK 0xffffffffff00ffffULL +#define SR_ASID_SHIFT 16 + +#define MMU_CONTEXT_ASID_MASK 0x000000ff +#define MMU_CONTEXT_VERSION_MASK 0xffffff00 +#define MMU_CONTEXT_FIRST_VERSION 0x00000100 +#define NO_CONTEXT 0 + +/* ASID is 8-bit value, so it can't be 0x100 */ +#define MMU_NO_ASID 0x100 + + +/* + * Virtual Page Number mask + */ +#define MMU_VPN_MASK 0xfffff000 + +extern __inline__ void +get_new_mmu_context(struct mm_struct *mm) +{ + extern void flush_tlb_all(void); + extern void flush_cache_all(void); + + unsigned long mc = ++mmu_context_cache; + + if (!(mc & MMU_CONTEXT_ASID_MASK)) { + /* We exhaust ASID of this version. + Flush all TLB and start new cycle. */ + flush_tlb_all(); + /* We have to flush all caches as ASIDs are + used in cache */ + flush_cache_all(); + /* Fix version if needed. + Note that we avoid version #0/asid #0 to distingush NO_CONTEXT. */ + if (!mc) + mmu_context_cache = mc = MMU_CONTEXT_FIRST_VERSION; + } + mm->context = mc; +} + +/* + * Get MMU context if needed. + */ +static __inline__ void +get_mmu_context(struct mm_struct *mm) +{ + if (mm) { + unsigned long mc = mmu_context_cache; + /* Check if we have old version of context. + If it's old, we need to get new context with new version. */ + if ((mm->context ^ mc) & MMU_CONTEXT_VERSION_MASK) + get_new_mmu_context(mm); + } +} + +/* + * Initialize the context related info for a new mm_struct + * instance. + */ +static inline int init_new_context(struct task_struct *tsk, + struct mm_struct *mm) +{ + mm->context = NO_CONTEXT; + + return 0; +} + +/* + * Destroy context related info for an mm_struct that is about + * to be put to rest. + */ +static inline void destroy_context(struct mm_struct *mm) +{ + extern void flush_tlb_mm(struct mm_struct *mm); + + /* Well, at least free TLB entries */ + flush_tlb_mm(mm); +} + +#endif /* __ASSEMBLY__ */ + +/* Common defines */ +#define TLB_STEP 0x00000010 +#define TLB_PTEH 0x00000000 +#define TLB_PTEL 0x00000008 + +/* PTEH defines */ +#define PTEH_ASID_SHIFT 2 +#define PTEH_VALID 0x0000000000000001 +#define PTEH_SHARED 0x0000000000000002 +#define PTEH_MATCH_ASID 0x00000000000003ff + +#ifndef __ASSEMBLY__ +/* This has to be a common function because the next location to fill + * information is shared. */ +extern void __do_tlb_refill(unsigned long address, unsigned long long is_text_not_data, pte_t *pte); + +/* Profiling counter. */ +#ifdef CONFIG_SH64_PROC_TLB +extern unsigned long long calls_to_do_fast_page_fault; +#endif + +static inline unsigned long get_asid(void) +{ + unsigned long long sr; + + asm volatile ("getcon " __SR ", %0\n\t" + : "=r" (sr)); + + sr = (sr >> SR_ASID_SHIFT) & MMU_CONTEXT_ASID_MASK; + return (unsigned long) sr; +} + +/* Set ASID into SR */ +static inline void set_asid(unsigned long asid) +{ + unsigned long long sr, pc; + + asm volatile ("getcon " __SR ", %0" : "=r" (sr)); + + sr = (sr & SR_ASID_MASK) | (asid << SR_ASID_SHIFT); + + /* + * It is possible that this function may be inlined and so to avoid + * the assembler reporting duplicate symbols we make use of the gas trick + * of generating symbols using numerics and forward reference. + */ + asm volatile ("movi 1, %1\n\t" + "shlli %1, 28, %1\n\t" + "or %0, %1, %1\n\t" + "putcon %1, " __SR "\n\t" + "putcon %0, " __SSR "\n\t" + "movi 1f, %1\n\t" + "ori %1, 1 , %1\n\t" + "putcon %1, " __SPC "\n\t" + "rte\n" + "1:\n\t" + : "=r" (sr), "=r" (pc) : "0" (sr)); +} + +/* + * 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_context(struct mm_struct *mm) +{ + get_mmu_context(mm); + set_asid(mm->context & MMU_CONTEXT_ASID_MASK); +} + + +static __inline__ void switch_mm(struct mm_struct *prev, + struct mm_struct *next, + struct task_struct *tsk) +{ + if (prev != next) { + mmu_pdtp_cache = next->pgd; + activate_context(next); + } +} + +#define deactivate_mm(tsk,mm) do { } while (0) + +#define activate_mm(prev, next) \ + switch_mm((prev),(next),NULL) + +static inline void +enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) +{ +} + +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_SH64_MMU_CONTEXT_H */ diff -puN /dev/null include/asm-sh64/mmu.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/mmu.h 2004-06-28 13:30:30.745129872 -0700 @@ -0,0 +1,7 @@ +#ifndef __MMU_H +#define __MMU_H + +/* Default "unsigned long" context */ +typedef unsigned long mm_context_t; + +#endif diff -puN /dev/null include/asm-sh64/module.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/module.h 2004-06-28 13:30:30.745129872 -0700 @@ -0,0 +1,12 @@ +#ifndef __ASM_SH64_MODULE_H +#define __ASM_SH64_MODULE_H +/* + * This file contains the SH architecture specific module code. + */ + +#define module_map(x) vmalloc(x) +#define module_unmap(x) vfree(x) +#define module_arch_init(x) (0) +#define arch_init_modules(x) do { } while (0) + +#endif /* __ASM_SH64_MODULE_H */ diff -puN /dev/null include/asm-sh64/msgbuf.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/msgbuf.h 2004-06-28 13:30:30.746129720 -0700 @@ -0,0 +1,42 @@ +#ifndef __ASM_SH64_MSGBUF_H +#define __ASM_SH64_MSGBUF_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. + * + * include/asm-sh64/msgbuf.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + */ + +/* + * The msqid64_ds structure for i386 architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 64-bit time_t to solve y2038 problem + * - 2 miscellaneous 32-bit values + */ + +struct msqid64_ds { + struct ipc64_perm msg_perm; + __kernel_time_t msg_stime; /* last msgsnd time */ + unsigned long __unused1; + __kernel_time_t msg_rtime; /* last msgrcv time */ + unsigned long __unused2; + __kernel_time_t msg_ctime; /* last change time */ + unsigned long __unused3; + unsigned long msg_cbytes; /* current number of bytes on queue */ + unsigned long msg_qnum; /* number of messages in queue */ + unsigned long msg_qbytes; /* max number of bytes on queue */ + __kernel_pid_t msg_lspid; /* pid of last msgsnd */ + __kernel_pid_t msg_lrpid; /* last receive pid */ + unsigned long __unused4; + unsigned long __unused5; +}; + +#endif /* __ASM_SH64_MSGBUF_H */ diff -puN /dev/null include/asm-sh64/namei.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/namei.h 2004-06-28 13:30:30.746129720 -0700 @@ -0,0 +1,24 @@ +#ifndef __ASM_SH64_NAMEI_H +#define __ASM_SH64_NAMEI_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. + * + * include/asm-sh64/namei.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + * Included from linux/fs/namei.c + * + */ + +/* This dummy routine maybe changed to something useful + * for /usr/gnemul/ emulation stuff. + * Look at asm-sparc/namei.h for details. + */ + +#define __emul_prefix() NULL + +#endif /* __ASM_SH64_NAMEI_H */ diff -puN /dev/null include/asm-sh64/page.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/page.h 2004-06-28 13:30:30.747129568 -0700 @@ -0,0 +1,137 @@ +#ifndef __ASM_SH64_PAGE_H +#define __ASM_SH64_PAGE_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. + * + * include/asm-sh64/page.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003, 2004 Paul Mundt + * + * benedict.gaster@superh.com 19th, 24th July 2002. + * + * Modified to take account of enabling for D-CACHE support. + * + */ + +#include + +/* PAGE_SHIFT determines the page size */ +#define PAGE_SHIFT 12 +#ifdef __ASSEMBLY__ +#define PAGE_SIZE 4096 +#else +#define PAGE_SIZE (1UL << PAGE_SHIFT) +#endif +#define PAGE_MASK (~(PAGE_SIZE-1)) +#define PTE_MASK PAGE_MASK + +#if defined(CONFIG_HUGETLB_PAGE_SIZE_64K) +#define HPAGE_SHIFT 16 +#elif defined(CONFIG_HUGETLB_PAGE_SIZE_1MB) +#define HPAGE_SHIFT 20 +#elif defined(CONFIG_HUGETLB_PAGE_SIZE_512MB) +#define HPAGE_SHIFT 29 +#endif + +#ifdef CONFIG_HUGETLB_PAGE +#define HPAGE_SIZE (1UL << HPAGE_SHIFT) +#define HPAGE_MASK (~(HPAGE_SIZE-1)) +#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT-PAGE_SHIFT) +#endif + +#ifdef __KERNEL__ +#ifndef __ASSEMBLY__ + +extern struct page *mem_map; +extern void sh64_page_clear(void *page); +extern void sh64_page_copy(void *from, void *to); + +#define clear_page(page) sh64_page_clear(page) +#define copy_page(to,from) sh64_page_copy(from, to) + +#if defined(CONFIG_DCACHE_DISABLED) + +#define clear_user_page(page, vaddr, pg) clear_page(page) +#define copy_user_page(to, from, vaddr, pg) copy_page(to, from) + +#else + +extern void clear_user_page(void *to, unsigned long address, struct page *pg); +extern void copy_user_page(void *to, void *from, unsigned long address, struct page *pg); + +#endif /* defined(CONFIG_DCACHE_DISABLED) */ + +/* + * These are used to make use of C type-checking.. + */ +typedef struct { unsigned long long pte; } pte_t; +typedef struct { unsigned long pmd; } pmd_t; +typedef struct { unsigned long pgd; } pgd_t; +typedef struct { unsigned long pgprot; } pgprot_t; + +#define pte_val(x) ((x).pte) +#define pmd_val(x) ((x).pmd) +#define pgd_val(x) ((x).pgd) +#define pgprot_val(x) ((x).pgprot) + +#define __pte(x) ((pte_t) { (x) } ) +#define __pmd(x) ((pmd_t) { (x) } ) +#define __pgd(x) ((pgd_t) { (x) } ) +#define __pgprot(x) ((pgprot_t) { (x) } ) + +#endif /* !__ASSEMBLY__ */ + +/* to align the pointer to the (next) page boundary */ +#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) + +/* + * Kconfig defined. + */ +#define __MEMORY_START (CONFIG_MEMORY_START) +#define PAGE_OFFSET (CONFIG_CACHED_MEMORY_OFFSET) + +#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET) +#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET)) +#define MAP_NR(addr) ((__pa(addr)-__MEMORY_START) >> PAGE_SHIFT) +#define VALID_PAGE(page) ((page - mem_map) < max_mapnr) + +#define phys_to_page(phys) (mem_map + (((phys) - __MEMORY_START) >> PAGE_SHIFT)) +#define page_to_phys(page) (((page - mem_map) << PAGE_SHIFT) + __MEMORY_START) + +/* PFN start number, because of __MEMORY_START */ +#define PFN_START (__MEMORY_START >> PAGE_SHIFT) + +#define pfn_to_page(pfn) (mem_map + (pfn) - PFN_START) +#define page_to_pfn(page) ((unsigned long)((page) - mem_map) + PFN_START) +#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) +#define pfn_valid(pfn) (((pfn) - PFN_START) < max_mapnr) +#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) + +#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ + VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) + +#ifndef __ASSEMBLY__ + +/* Pure 2^n version of get_order */ +extern __inline__ int get_order(unsigned long size) +{ + int order; + + size = (size-1) >> (PAGE_SHIFT-1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + return order; +} + +#endif + +#endif /* __KERNEL__ */ + +#endif /* __ASM_SH64_PAGE_H */ diff -puN /dev/null include/asm-sh64/param.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/param.h 2004-06-28 13:30:30.747129568 -0700 @@ -0,0 +1,43 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * include/asm-sh64/param.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003 Paul Mundt + * + */ +#ifndef __ASM_SH64_PARAM_H +#define __ASM_SH64_PARAM_H + +#include + +#ifdef __KERNEL__ +# ifdef CONFIG_SH_WDT +# define HZ 1000 /* Needed for high-res WOVF */ +# else +# define HZ 100 +# endif +# define USER_HZ 100 /* User interfaces are in "ticks" */ +# define CLOCKS_PER_SEC (USER_HZ) /* frequency at which times() counts */ +#endif + +#ifndef HZ +#define HZ 100 +#endif + +#define EXEC_PAGESIZE 4096 + +#ifndef NGROUPS +#define NGROUPS 32 +#endif + +#ifndef NOGROUP +#define NOGROUP (-1) +#endif + +#define MAXHOSTNAMELEN 64 /* max length of hostname */ + +#endif /* __ASM_SH64_PARAM_H */ diff -puN /dev/null include/asm-sh64/pci.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/pci.h 2004-06-28 13:30:30.748129416 -0700 @@ -0,0 +1,110 @@ +#ifndef __ASM_SH64_PCI_H +#define __ASM_SH64_PCI_H + +#ifdef __KERNEL__ + +#include + +/* Can be used to override the logic in pci_scan_bus for skipping + already-configured bus numbers - to be used for buggy BIOSes + or architectures with incomplete PCI setup by the loader */ + +#define pcibios_assign_all_busses() 1 + +/* + * These are currently the correct values for the STM overdrive board + * We need some way of setting this on a board specific way, it will + * not be the same on other boards I think + */ +#if defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103) +#define PCIBIOS_MIN_IO 0x2000 +#define PCIBIOS_MIN_MEM 0x40000000 +#endif + +extern void pcibios_set_master(struct pci_dev *dev); + +/* + * Set penalize isa irq function + */ +static inline void pcibios_penalize_isa_irq(int irq) +{ + /* We don't do dynamic PCI IRQ allocation */ +} + +/* Dynamic DMA mapping stuff. + * SuperH has everything mapped statically like x86. + */ + +/* The PCI address space does equal the physical memory + * address space. The networking and block device layers use + * this boolean for bounce buffer decisions. + */ +#define PCI_DMA_BUS_IS_PHYS (1) + +#include +#include +#include +#include +#include + +/* pci_unmap_{single,page} being a nop depends upon the + * configuration. + */ +#ifdef CONFIG_SH_PCIDMA_NONCOHERENT +#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \ + dma_addr_t ADDR_NAME; +#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) \ + __u32 LEN_NAME; +#define pci_unmap_addr(PTR, ADDR_NAME) \ + ((PTR)->ADDR_NAME) +#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) \ + (((PTR)->ADDR_NAME) = (VAL)) +#define pci_unmap_len(PTR, LEN_NAME) \ + ((PTR)->LEN_NAME) +#define pci_unmap_len_set(PTR, LEN_NAME, VAL) \ + (((PTR)->LEN_NAME) = (VAL)) +#else +#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) +#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) +#define pci_unmap_addr(PTR, ADDR_NAME) (0) +#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) do { } while (0) +#define pci_unmap_len(PTR, LEN_NAME) (0) +#define pci_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0) +#endif + +/* Not supporting more than 32-bit PCI bus addresses now, but + * must satisfy references to this function. Change if needed. + */ +#define pci_dac_dma_supported(pci_dev, mask) (0) + +/* These macros should be used after a pci_map_sg call has been done + * to get bus addresses of each of the SG entries and their lengths. + * You should only work with the number of sg entries pci_map_sg + * returns, or alternatively stop on the first sg_dma_len(sg) which + * is 0. + */ +#define sg_dma_address(sg) ((sg)->dma_address) +#define sg_dma_len(sg) ((sg)->length) + +/* Board-specific fixup routines. */ +extern void pcibios_fixup(void); +extern void pcibios_fixup_irqs(void); + +#ifdef CONFIG_PCI_AUTO +extern int pciauto_assign_resources(int busno, struct pci_channel *hose); +#endif + +static inline void pcibios_add_platform_entries(struct pci_dev *dev) +{ +} + +#endif /* __KERNEL__ */ + +/* generic pci stuff */ +#include + +/* generic DMA-mapping stuff */ +#include + +#endif /* __ASM_SH64_PCI_H */ + diff -puN /dev/null include/asm-sh64/percpu.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/percpu.h 2004-06-28 13:30:30.748129416 -0700 @@ -0,0 +1,6 @@ +#ifndef __ASM_SH64_PERCPU +#define __ASM_SH64_PERCPU + +#include + +#endif /* __ASM_SH64_PERCPU */ diff -puN /dev/null include/asm-sh64/pgalloc.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/pgalloc.h 2004-06-28 13:30:30.749129264 -0700 @@ -0,0 +1,202 @@ +#ifndef __ASM_SH64_PGALLOC_H +#define __ASM_SH64_PGALLOC_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. + * + * include/asm-sh64/pgalloc.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003, 2004 Paul Mundt + * Copyright (C) 2003, 2004 Richard Curnow + * + */ + +#include +#include +#include + +#define pgd_quicklist (current_cpu_data.pgd_quick) +#define pmd_quicklist (current_cpu_data.pmd_quick) +#define pte_quicklist (current_cpu_data.pte_quick) +#define pgtable_cache_size (current_cpu_data.pgtable_cache_sz) + +static inline void pgd_init(unsigned long page) +{ + unsigned long *pgd = (unsigned long *)page; + extern pte_t empty_bad_pte_table[PTRS_PER_PTE]; + int i; + + for (i = 0; i < USER_PTRS_PER_PGD; i++) + pgd[i] = (unsigned long)empty_bad_pte_table; +} + +/* + * Allocate and free page tables. The xxx_kernel() versions are + * used to allocate a kernel page table - this turns on ASN bits + * if any. + */ + +extern __inline__ pgd_t *get_pgd_slow(void) +{ + unsigned int pgd_size = (USER_PTRS_PER_PGD * sizeof(pgd_t)); + pgd_t *ret = (pgd_t *)kmalloc(pgd_size, GFP_KERNEL); + return ret; +} + +extern __inline__ pgd_t *get_pgd_fast(void) +{ + unsigned long *ret; + + if ((ret = pgd_quicklist) != NULL) { + pgd_quicklist = (unsigned long *)(*ret); + ret[0] = 0; + pgtable_cache_size--; + } else + ret = (unsigned long *)get_pgd_slow(); + + if (ret) { + memset(ret, 0, USER_PTRS_PER_PGD * sizeof(pgd_t)); + } + return (pgd_t *)ret; +} + +extern __inline__ void free_pgd_fast(pgd_t *pgd) +{ + *(unsigned long *)pgd = (unsigned long) pgd_quicklist; + pgd_quicklist = (unsigned long *) pgd; + pgtable_cache_size++; +} + +extern __inline__ void free_pgd_slow(pgd_t *pgd) +{ + kfree((void *)pgd); +} + +extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted); +extern pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long address_preadjusted); + +extern __inline__ pte_t *get_pte_fast(void) +{ + unsigned long *ret; + + if((ret = (unsigned long *)pte_quicklist) != NULL) { + pte_quicklist = (unsigned long *)(*ret); + ret[0] = ret[1]; + pgtable_cache_size--; + } + return (pte_t *)ret; +} + +extern __inline__ void free_pte_fast(pte_t *pte) +{ + *(unsigned long *)pte = (unsigned long) pte_quicklist; + pte_quicklist = (unsigned long *) pte; + pgtable_cache_size++; +} + +static inline void pte_free_kernel(pte_t *pte) +{ + free_page((unsigned long)pte); +} + +static inline void pte_free(struct page *pte) +{ + __free_page(pte); +} + +static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, + unsigned long address) +{ + pte_t *pte; + + pte = (pte_t *)__get_free_page(GFP_KERNEL | __GFP_REPEAT); + if (pte) + clear_page(pte); + + return pte; +} + +static inline struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) +{ + struct page *pte; + + pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT, 0); + if (pte) + clear_page(page_address(pte)); + + return pte; +} + +#define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte)) + +/* + * allocating and freeing a pmd is trivial: the 1-entry pmd is + * inside the pgd, so has no extra memory associated with it. + */ + +#if defined(CONFIG_SH64_PGTABLE_2_LEVEL) + +#define pmd_alloc_one(mm, addr) ({ BUG(); ((pmd_t *)2); }) +#define pmd_free(x) do { } while (0) +#define pgd_populate(mm, pmd, pte) BUG() +#define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte)) +#define __pmd_free_tlb(tlb,pmd) do { } while (0) + +#elif defined(CONFIG_SH64_PGTABLE_3_LEVEL) + +static __inline__ pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address) +{ + pmd_t *pmd; + pmd = (pmd_t *) __get_free_page(GFP_KERNEL|__GFP_REPEAT); + if (pmd) + clear_page(pmd); + return pmd; +} + +static __inline__ void pmd_free(pmd_t *pmd) +{ + free_page((unsigned long) pmd); +} + +#define pgd_populate(mm, pgd, pmd) pgd_set(pgd, pmd) +#define __pmd_free_tlb(tlb,pmd) pmd_free(pmd) + +#else +#error "No defined page table size" +#endif + +#define check_pgt_cache() do { } while (0) +#define pgd_free(pgd) free_pgd_slow(pgd) +#define pgd_alloc(mm) get_pgd_fast() + +extern int do_check_pgt_cache(int, int); + +extern inline void set_pgdir(unsigned long address, pgd_t entry) +{ + struct task_struct * p; + pgd_t *pgd; + + read_lock(&tasklist_lock); + for_each_process(p) { + if (!p->mm) + continue; + *pgd_offset(p->mm,address) = entry; + } + read_unlock(&tasklist_lock); + for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd) + pgd[address >> PGDIR_SHIFT] = entry; +} + +#define pmd_populate_kernel(mm, pmd, pte) \ + set_pmd(pmd, __pmd(_PAGE_TABLE + (unsigned long) (pte))) + +static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, + struct page *pte) +{ + set_pmd(pmd, __pmd(_PAGE_TABLE + (unsigned long) page_address (pte))); +} + +#endif /* __ASM_SH64_PGALLOC_H */ diff -puN /dev/null include/asm-sh64/pgtable.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/pgtable.h 2004-06-28 13:30:30.752128808 -0700 @@ -0,0 +1,498 @@ +#ifndef __ASM_SH64_PGTABLE_H +#define __ASM_SH64_PGTABLE_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. + * + * include/asm-sh64/pgtable.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003, 2004 Paul Mundt + * Copyright (C) 2003, 2004 Richard Curnow + * + * This file contains the functions and defines necessary to modify and use + * the SuperH page table tree. + */ + +#ifndef __ASSEMBLY__ +#include +#include +#include +#include + +extern void paging_init(void); + +/* We provide our own get_unmapped_area to avoid cache synonym issue */ +#define HAVE_ARCH_UNMAPPED_AREA + +/* + * Basically we have the same two-level (which is the logical three level + * Linux page table layout folded) page tables as the i386. + */ + +/* + * ZERO_PAGE is a global shared page that is always zero: used + * for zero-mapped memory areas etc.. + */ +extern unsigned char empty_zero_page[PAGE_SIZE]; +#define ZERO_PAGE(vaddr) (mem_map + MAP_NR(empty_zero_page)) + +#endif /* !__ASSEMBLY__ */ + +/* + * NEFF and NPHYS related defines. + * FIXME : These need to be model-dependent. For now this is OK, SH5-101 and SH5-103 + * implement 32 bits effective and 32 bits physical. But future implementations may + * extend beyond this. + */ +#define NEFF 32 +#define NEFF_SIGN (1LL << (NEFF - 1)) +#define NEFF_MASK (-1LL << NEFF) + +#define NPHYS 32 +#define NPHYS_SIGN (1LL << (NPHYS - 1)) +#define NPHYS_MASK (-1LL << NPHYS) + +/* Typically 2-level is sufficient up to 32 bits of virtual address space, beyond + that 3-level would be appropriate. */ +#if defined(CONFIG_SH64_PGTABLE_2_LEVEL) +/* For 4k pages, this contains 512 entries, i.e. 9 bits worth of address. */ +#define PTRS_PER_PTE ((1<> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) +#define __pgd_offset(address) pgd_index(address) +#define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address)) + +/* To find an entry in a kernel PGD. */ +#define pgd_offset_k(address) pgd_offset(&init_mm, address) + +/* + * PGD level access routines. + * + * Note1: + * There's no need to use physical addresses since the tree walk is all + * in performed in software, until the PTE translation. + * + * Note 2: + * A PGD entry can be uninitialized (_PGD_UNUSED), generically bad, + * clear (_PGD_EMPTY), present. When present, lower 3 nibbles contain + * _KERNPG_TABLE. Being a kernel virtual pointer also bit 31 must + * be 1. Assuming an arbitrary clear value of bit 31 set to 0 and + * lower 3 nibbles set to 0xFFF (_PGD_EMPTY) any other value is a + * bad pgd that must be notified via printk(). + * + */ +#define _PGD_EMPTY 0x0 + +#if defined(CONFIG_SH64_PGTABLE_2_LEVEL) +static inline int pgd_none(pgd_t pgd) { return 0; } +static inline int pgd_bad(pgd_t pgd) { return 0; } +#define pgd_present(pgd) ((pgd_val(pgd) & _PAGE_PRESENT) ? 1 : 0) +#define pgd_clear(xx) do { } while(0) + +#elif defined(CONFIG_SH64_PGTABLE_3_LEVEL) +#define pgd_present(pgd_entry) (1) +#define pgd_none(pgd_entry) (pgd_val((pgd_entry)) == _PGD_EMPTY) +/* TODO: Think later about what a useful definition of 'bad' would be now. */ +#define pgd_bad(pgd_entry) (0) +#define pgd_clear(pgd_entry_p) (set_pgd((pgd_entry_p), __pgd(_PGD_EMPTY))) + +#endif + + +#define pgd_page(pgd_entry) ((unsigned long) (pgd_val(pgd_entry) & PAGE_MASK)) + +/* + * PMD defines. Middle level. + */ + +/* PGD to PMD dereferencing */ +#if defined(CONFIG_SH64_PGTABLE_2_LEVEL) +static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address) +{ + return (pmd_t *) dir; +} +#elif defined(CONFIG_SH64_PGTABLE_3_LEVEL) +#define __pmd_offset(address) \ + (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1)) +#define pmd_offset(dir, addr) \ + ((pmd_t *) ((pgd_val(*(dir))) & PAGE_MASK) + __pmd_offset((addr))) +#endif + +/* + * PMD level access routines. Same notes as above. + */ +#define _PMD_EMPTY 0x0 +/* Either the PMD is empty or present, it's not paged out */ +#define pmd_present(pmd_entry) (pmd_val(pmd_entry) & _PAGE_PRESENT) +#define pmd_clear(pmd_entry_p) (set_pmd((pmd_entry_p), __pmd(_PMD_EMPTY))) +#define pmd_none(pmd_entry) (pmd_val((pmd_entry)) == _PMD_EMPTY) +#define pmd_bad(pmd_entry) ((pmd_val(pmd_entry) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE) + +#define pmd_page_kernel(pmd_entry) \ + ((unsigned long) __va(pmd_val(pmd_entry) & PAGE_MASK)) + +#define pmd_page(pmd) \ + (virt_to_page(pmd_val(pmd))) + +/* PMD to PTE dereferencing */ +#define pte_index(address) \ + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) + +#define pte_offset_kernel(dir, addr) \ + ((pte_t *) ((pmd_val(*(dir))) & PAGE_MASK) + pte_index((addr))) + +#define pte_offset_map(dir,addr) pte_offset_kernel(dir, addr) +#define pte_offset_map_nested(dir,addr) pte_offset_kernel(dir, addr) +#define pte_unmap(pte) do { } while (0) +#define pte_unmap_nested(pte) do { } while (0) + +/* Round it up ! */ +#define USER_PTRS_PER_PGD ((TASK_SIZE+PGDIR_SIZE-1)/PGDIR_SIZE) +#define FIRST_USER_PGD_NR 0 + +#ifndef __ASSEMBLY__ +#define VMALLOC_END 0xff000000 +#define VMALLOC_START 0xf0000000 +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) + +#define IOBASE_VADDR 0xff000000 +#define IOBASE_END 0xffffffff + +/* + * PTEL coherent flags. + * See Chapter 17 ST50 CPU Core Volume 1, Architecture. + */ +/* The bits that are required in the SH-5 TLB are placed in the h/w-defined + positions, to avoid expensive bit shuffling on every refill. The remaining + bits are used for s/w purposes and masked out on each refill. + + Note, the PTE slots are used to hold data of type swp_entry_t when a page is + swapped out. Only the _PAGE_PRESENT flag is significant when the page is + swapped out, and it must be placed so that it doesn't overlap either the + type or offset fields of swp_entry_t. For x86, offset is at [31:8] and type + at [6:1], with _PAGE_PRESENT at bit 0 for both pte_t and swp_entry_t. This + scheme doesn't map to SH-5 because bit [0] controls cacheability. So bit + [2] is used for _PAGE_PRESENT and the type field of swp_entry_t is split + into 2 pieces. That is handled by SWP_ENTRY and SWP_TYPE below. */ +#define _PAGE_WT 0x001 /* CB0: if cacheable, 1->write-thru, 0->write-back */ +#define _PAGE_DEVICE 0x001 /* CB0: if uncacheable, 1->device (i.e. no write-combining or reordering at bus level) */ +#define _PAGE_CACHABLE 0x002 /* CB1: uncachable/cachable */ +#define _PAGE_PRESENT 0x004 /* software: page referenced */ +#define _PAGE_FILE 0x004 /* software: only when !present */ +#define _PAGE_SIZE0 0x008 /* SZ0-bit : size of page */ +#define _PAGE_SIZE1 0x010 /* SZ1-bit : size of page */ +#define _PAGE_SHARED 0x020 /* software: reflects PTEH's SH */ +#define _PAGE_READ 0x040 /* PR0-bit : read access allowed */ +#define _PAGE_EXECUTE 0x080 /* PR1-bit : execute access allowed */ +#define _PAGE_WRITE 0x100 /* PR2-bit : write access allowed */ +#define _PAGE_USER 0x200 /* PR3-bit : user space access allowed */ +#define _PAGE_DIRTY 0x400 /* software: page accessed in write */ +#define _PAGE_ACCESSED 0x800 /* software: page referenced */ + +/* Mask which drops software flags */ +#define _PAGE_FLAGS_HARDWARE_MASK 0xfffffffffffff3dbLL +/* Flags default: 4KB, Read, Not write, Not execute, Not user */ +#define _PAGE_FLAGS_HARDWARE_DEFAULT 0x0000000000000040LL + +/* + * HugeTLB support + */ +#if defined(CONFIG_HUGETLB_PAGE_SIZE_64K) +#define _PAGE_SZHUGE (_PAGE_SIZE0) +#elif defined(CONFIG_HUGETLB_PAGE_SIZE_1MB) +#define _PAGE_SZHUGE (_PAGE_SIZE1) +#elif defined(CONFIG_HUGETLB_PAGE_SIZE_512MB) +#define _PAGE_SZHUGE (_PAGE_SIZE0 | _PAGE_SIZE1) +#endif + +/* + * Default flags for a Kernel page. + * This is fundametally also SHARED because the main use of this define + * (other than for PGD/PMD entries) is for the VMALLOC pool which is + * contextless. + * + * _PAGE_EXECUTE is required for modules + * + */ +#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \ + _PAGE_EXECUTE | \ + _PAGE_CACHABLE | _PAGE_ACCESSED | _PAGE_DIRTY | \ + _PAGE_SHARED) + +/* Default flags for a User page */ +#define _PAGE_TABLE (_KERNPG_TABLE | _PAGE_USER) + +#define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY) + +#define PAGE_NONE __pgprot(_PAGE_CACHABLE | _PAGE_ACCESSED) +#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \ + _PAGE_CACHABLE | _PAGE_ACCESSED | _PAGE_USER | \ + _PAGE_SHARED) +/* We need to include PAGE_EXECUTE in PAGE_COPY because it is the default + * protection mode for the stack. */ +#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_CACHABLE | \ + _PAGE_ACCESSED | _PAGE_USER | _PAGE_EXECUTE) +#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_CACHABLE | \ + _PAGE_ACCESSED | _PAGE_USER) +#define PAGE_KERNEL __pgprot(_KERNPG_TABLE) + + +/* + * In ST50 we have full permissions (Read/Write/Execute/Shared). + * Just match'em all. These are for mmap(), therefore all at least + * User/Cachable/Present/Accessed. No point in making Fault on Write. + */ +#define __MMAP_COMMON (_PAGE_PRESENT | _PAGE_USER | _PAGE_CACHABLE | _PAGE_ACCESSED) + /* sxwr */ +#define __P000 __pgprot(__MMAP_COMMON) +#define __P001 __pgprot(__MMAP_COMMON | _PAGE_READ) +#define __P010 __pgprot(__MMAP_COMMON) +#define __P011 __pgprot(__MMAP_COMMON | _PAGE_READ) +#define __P100 __pgprot(__MMAP_COMMON | _PAGE_EXECUTE) +#define __P101 __pgprot(__MMAP_COMMON | _PAGE_EXECUTE | _PAGE_READ) +#define __P110 __pgprot(__MMAP_COMMON | _PAGE_EXECUTE) +#define __P111 __pgprot(__MMAP_COMMON | _PAGE_EXECUTE | _PAGE_READ) + +#define __S000 __pgprot(__MMAP_COMMON | _PAGE_SHARED) +#define __S001 __pgprot(__MMAP_COMMON | _PAGE_SHARED | _PAGE_READ) +#define __S010 __pgprot(__MMAP_COMMON | _PAGE_SHARED | _PAGE_WRITE) +#define __S011 __pgprot(__MMAP_COMMON | _PAGE_SHARED | _PAGE_READ | _PAGE_WRITE) +#define __S100 __pgprot(__MMAP_COMMON | _PAGE_SHARED | _PAGE_EXECUTE) +#define __S101 __pgprot(__MMAP_COMMON | _PAGE_SHARED | _PAGE_EXECUTE | _PAGE_READ) +#define __S110 __pgprot(__MMAP_COMMON | _PAGE_SHARED | _PAGE_EXECUTE | _PAGE_WRITE) +#define __S111 __pgprot(__MMAP_COMMON | _PAGE_SHARED | _PAGE_EXECUTE | _PAGE_READ | _PAGE_WRITE) + +/* Make it a device mapping for maximum safety (e.g. for mapping device + registers into user-space via /dev/map). */ +#define pgprot_noncached(x) __pgprot(((x).pgprot & ~(_PAGE_CACHABLE)) | _PAGE_DEVICE) +#define pgprot_writecombine(prot) __pgprot(pgprot_val(prot) & ~_PAGE_CACHABLE) + +/* + * Handling allocation failures during page table setup. + */ +extern void __handle_bad_pmd_kernel(pmd_t * pmd); +#define __handle_bad_pmd(x) __handle_bad_pmd_kernel(x) + +/* + * PTE level access routines. + * + * Note1: + * It's the tree walk leaf. This is physical address to be stored. + * + * Note 2: + * Regarding the choice of _PTE_EMPTY: + + We must choose a bit pattern that cannot be valid, whether or not the page + is present. bit[2]==1 => present, bit[2]==0 => swapped out. If swapped + out, bits [31:8], [6:3], [1:0] are under swapper control, so only bit[7] is + left for us to select. If we force bit[7]==0 when swapped out, we could use + the combination bit[7,2]=2'b10 to indicate an empty PTE. Alternatively, if + we force bit[7]==1 when swapped out, we can use all zeroes to indicate + empty. This is convenient, because the page tables get cleared to zero + when they are allocated. + + */ +#define _PTE_EMPTY 0x0 +#define pte_present(x) (pte_val(x) & _PAGE_PRESENT) +#define pte_clear(xp) (set_pte(xp, __pte(_PTE_EMPTY))) +#define pte_none(x) (pte_val(x) == _PTE_EMPTY) + +/* + * Some definitions to translate between mem_map, PTEs, and page + * addresses: + */ + +/* + * Given a PTE, return the index of the mem_map[] entry corresponding + * to the page frame the PTE. Get the absolute physical address, make + * a relative physical address and translate it to an index. + */ +#define pte_pagenr(x) (((unsigned long) (pte_val(x)) - \ + __MEMORY_START) >> PAGE_SHIFT) + +/* + * Given a PTE, return the "struct page *". + */ +#define pte_page(x) (mem_map + pte_pagenr(x)) + +/* + * Return number of (down rounded) MB corresponding to x pages. + */ +#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT)) + + +/* + * The following have defined behavior only work if pte_present() is true. + */ +static inline int pte_read(pte_t pte) { return pte_val(pte) & _PAGE_READ; } +static inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_EXECUTE; } +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 int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; } +static inline int pte_write(pte_t pte){ return pte_val(pte) & _PAGE_WRITE; } + +extern inline pte_t pte_rdprotect(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_READ)); return pte; } +extern inline pte_t pte_wrprotect(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_WRITE)); return pte; } +extern inline pte_t pte_exprotect(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_EXECUTE)); return pte; } +extern inline pte_t pte_mkclean(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_DIRTY)); return pte; } +extern inline pte_t pte_mkold(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_ACCESSED)); return pte; } + +extern inline pte_t pte_mkread(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_READ)); return pte; } +extern inline pte_t pte_mkwrite(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_WRITE)); return pte; } +extern inline pte_t pte_mkexec(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_EXECUTE)); return pte; } +extern inline pte_t pte_mkdirty(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_DIRTY)); return pte; } +extern inline pte_t pte_mkyoung(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_ACCESSED)); return pte; } + +/* + * Conversion functions: convert a page and protection to a page entry. + * + * extern pte_t mk_pte(struct page *page, pgprot_t pgprot) + */ +#define mk_pte(page,pgprot) \ +({ \ + pte_t __pte; \ + \ + set_pte(&__pte, __pte((((page)-mem_map) << PAGE_SHIFT) | \ + __MEMORY_START | pgprot_val((pgprot)))); \ + __pte; \ +}) + +/* + * This takes a (absolute) physical page address that is used + * by the remapping functions + */ +#define mk_pte_phys(physpage, pgprot) \ +({ pte_t __pte; set_pte(&__pte, __pte(physpage | pgprot_val(pgprot))); __pte; }) + +extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot) +{ set_pte(&pte, __pte((pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot))); return pte; } + +#define page_pte_prot(page, prot) mk_pte(page, prot) +#define page_pte(page) page_pte_prot(page, __pgprot(0)) + +typedef pte_t *pte_addr_t; +#define pgtable_cache_init() do { } while (0) + +extern void update_mmu_cache(struct vm_area_struct * vma, + unsigned long address, pte_t pte); + +/* Encode and decode a swap entry */ +#define __swp_type(x) (((x).val & 3) + (((x).val >> 1) & 0x3c)) +#define __swp_offset(x) ((x).val >> 8) +#define __swp_entry(type, offset) ((swp_entry_t) { ((offset << 8) + ((type & 0x3c) << 1) + (type & 3)) }) +#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) +#define __swp_entry_to_pte(x) ((pte_t) { (x).val }) + +/* Encode and decode a nonlinear file mapping entry */ +#define PTE_FILE_MAX_BITS 29 +#define pte_to_pgoff(pte) (pte_val(pte)) +#define pgoff_to_pte(off) ((pte_t) { (off) | _PAGE_FILE }) + +/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */ +#define PageSkip(page) (0) +#define kern_addr_valid(addr) (1) + +#define io_remap_page_range remap_page_range +#endif /* !__ASSEMBLY__ */ + +/* + * No page table caches to initialise + */ +#define pgtable_cache_init() do { } while (0) + +#define pte_pfn(x) (((unsigned long)((x).pte)) >> PAGE_SHIFT) +#define pfn_pte(pfn, prot) __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot)) +#define pfn_pmd(pfn, prot) __pmd(((pfn) << PAGE_SHIFT) | pgprot_val(prot)) + +extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; + +#include + +#endif /* __ASM_SH64_PGTABLE_H */ diff -puN /dev/null include/asm-sh64/platform.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/platform.h 2004-06-28 13:30:30.753128656 -0700 @@ -0,0 +1,69 @@ +#ifndef __ASM_SH64_PLATFORM_H +#define __ASM_SH64_PLATFORM_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. + * + * include/asm-sh64/platform.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + * benedict.gaster@superh.com: 3rd May 2002 + * Added support for ramdisk, removing statically linked romfs at the same time. + */ + +#include +#include + + +/* + * Platform definition structure. + */ +struct sh64_platform { + unsigned int readonly_rootfs; + unsigned int ramdisk_flags; + unsigned int initial_root_dev; + unsigned int loader_type; + unsigned int initrd_start; + unsigned int initrd_size; + unsigned int fpu_flags; + unsigned int io_res_count; + unsigned int kram_res_count; + unsigned int xram_res_count; + unsigned int rom_res_count; + struct resource *io_res_p; + struct resource *kram_res_p; + struct resource *xram_res_p; + struct resource *rom_res_p; +}; + +extern struct sh64_platform platform_parms; + +extern unsigned long long memory_start, memory_end; + +extern unsigned long long fpu_in_use; + +extern int platform_int_priority[NR_INTC_IRQS]; + +#define FPU_FLAGS (platform_parms.fpu_flags) +#define STANDARD_IO_RESOURCES (platform_parms.io_res_count) +#define STANDARD_KRAM_RESOURCES (platform_parms.kram_res_count) +#define STANDARD_XRAM_RESOURCES (platform_parms.xram_res_count) +#define STANDARD_ROM_RESOURCES (platform_parms.rom_res_count) + +/* + * Kernel Memory description, Respectively: + * code = last but one memory descriptor + * data = last memory descriptor + */ +#define code_resource (platform_parms.kram_res_p[STANDARD_KRAM_RESOURCES - 2]) +#define data_resource (platform_parms.kram_res_p[STANDARD_KRAM_RESOURCES - 1]) + +/* Be prepared to 64-bit sign extensions */ +#define PFN_UP(x) ((((x) + PAGE_SIZE-1) >> PAGE_SHIFT) & 0x000fffff) +#define PFN_DOWN(x) (((x) >> PAGE_SHIFT) & 0x000fffff) +#define PFN_PHYS(x) ((x) << PAGE_SHIFT) + +#endif /* __ASM_SH64_PLATFORM_H */ diff -puN /dev/null include/asm-sh64/poll.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/poll.h 2004-06-28 13:30:30.753128656 -0700 @@ -0,0 +1,36 @@ +#ifndef __ASM_SH64_POLL_H +#define __ASM_SH64_POLL_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. + * + * include/asm-sh64/poll.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + */ + +/* These are specified by iBCS2 */ +#define POLLIN 0x0001 +#define POLLPRI 0x0002 +#define POLLOUT 0x0004 +#define POLLERR 0x0008 +#define POLLHUP 0x0010 +#define POLLNVAL 0x0020 + +/* The rest seem to be more-or-less nonstandard. Check them! */ +#define POLLRDNORM 0x0040 +#define POLLRDBAND 0x0080 +#define POLLWRNORM 0x0100 +#define POLLWRBAND 0x0200 +#define POLLMSG 0x0400 + +struct pollfd { + int fd; + short events; + short revents; +}; + +#endif /* __ASM_SH64_POLL_H */ diff -puN /dev/null include/asm-sh64/posix_types.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/posix_types.h 2004-06-28 13:30:30.754128504 -0700 @@ -0,0 +1,131 @@ +#ifndef __ASM_SH64_POSIX_TYPES_H +#define __ASM_SH64_POSIX_TYPES_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. + * + * include/asm-sh64/posix_types.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003 Paul Mundt + * + * This file is generally used by user-level software, so you need to + * be a little careful about namespace pollution etc. Also, we cannot + * assume GCC is being used. + */ + +typedef unsigned long __kernel_ino_t; +typedef unsigned short __kernel_mode_t; +typedef unsigned short __kernel_nlink_t; +typedef long __kernel_off_t; +typedef int __kernel_pid_t; +typedef unsigned short __kernel_ipc_pid_t; +typedef unsigned short __kernel_uid_t; +typedef unsigned short __kernel_gid_t; +typedef long unsigned int __kernel_size_t; +typedef int __kernel_ssize_t; +typedef int __kernel_ptrdiff_t; +typedef long __kernel_time_t; +typedef long __kernel_suseconds_t; +typedef long __kernel_clock_t; +typedef int __kernel_timer_t; +typedef int __kernel_clockid_t; +typedef int __kernel_daddr_t; +typedef char * __kernel_caddr_t; +typedef unsigned short __kernel_uid16_t; +typedef unsigned short __kernel_gid16_t; +typedef unsigned int __kernel_uid32_t; +typedef unsigned int __kernel_gid32_t; + +typedef unsigned short __kernel_old_uid_t; +typedef unsigned short __kernel_old_gid_t; +typedef unsigned short __kernel_old_dev_t; + +#ifdef __GNUC__ +typedef long long __kernel_loff_t; +#endif + +typedef struct { +#if defined(__KERNEL__) || defined(__USE_ALL) + int val[2]; +#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */ + int __val[2]; +#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */ +} __kernel_fsid_t; + +#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) + +#undef __FD_SET +static __inline__ void __FD_SET(unsigned long __fd, __kernel_fd_set *__fdsetp) +{ + unsigned long __tmp = __fd / __NFDBITS; + unsigned long __rem = __fd % __NFDBITS; + __fdsetp->fds_bits[__tmp] |= (1UL<<__rem); +} + +#undef __FD_CLR +static __inline__ void __FD_CLR(unsigned long __fd, __kernel_fd_set *__fdsetp) +{ + unsigned long __tmp = __fd / __NFDBITS; + unsigned long __rem = __fd % __NFDBITS; + __fdsetp->fds_bits[__tmp] &= ~(1UL<<__rem); +} + + +#undef __FD_ISSET +static __inline__ int __FD_ISSET(unsigned long __fd, const __kernel_fd_set *__p) +{ + unsigned long __tmp = __fd / __NFDBITS; + unsigned long __rem = __fd % __NFDBITS; + return (__p->fds_bits[__tmp] & (1UL<<__rem)) != 0; +} + +/* + * This will unroll the loop for the normal constant case (8 ints, + * for a 256-bit fd_set) + */ +#undef __FD_ZERO +static __inline__ void __FD_ZERO(__kernel_fd_set *__p) +{ + unsigned long *__tmp = __p->fds_bits; + int __i; + + if (__builtin_constant_p(__FDSET_LONGS)) { + switch (__FDSET_LONGS) { + case 16: + __tmp[ 0] = 0; __tmp[ 1] = 0; + __tmp[ 2] = 0; __tmp[ 3] = 0; + __tmp[ 4] = 0; __tmp[ 5] = 0; + __tmp[ 6] = 0; __tmp[ 7] = 0; + __tmp[ 8] = 0; __tmp[ 9] = 0; + __tmp[10] = 0; __tmp[11] = 0; + __tmp[12] = 0; __tmp[13] = 0; + __tmp[14] = 0; __tmp[15] = 0; + return; + + case 8: + __tmp[ 0] = 0; __tmp[ 1] = 0; + __tmp[ 2] = 0; __tmp[ 3] = 0; + __tmp[ 4] = 0; __tmp[ 5] = 0; + __tmp[ 6] = 0; __tmp[ 7] = 0; + return; + + case 4: + __tmp[ 0] = 0; __tmp[ 1] = 0; + __tmp[ 2] = 0; __tmp[ 3] = 0; + return; + } + } + __i = __FDSET_LONGS; + while (__i) { + __i--; + *__tmp = 0; + __tmp++; + } +} + +#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */ + +#endif /* __ASM_SH64_POSIX_TYPES_H */ diff -puN /dev/null include/asm-sh64/processor.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/processor.h 2004-06-28 13:30:30.755128352 -0700 @@ -0,0 +1,292 @@ +#ifndef __ASM_SH64_PROCESSOR_H +#define __ASM_SH64_PROCESSOR_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. + * + * include/asm-sh64/processor.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003 Paul Mundt + * Copyright (C) 2004 Richard Curnow + * + */ + +#include + +#ifndef __ASSEMBLY__ + +#include +#include +#include +#include + +/* + * Default implementation of macro that returns current + * instruction pointer ("program counter"). + */ +#define current_text_addr() ({ \ +void *pc; \ +unsigned long long __dummy = 0; \ +__asm__("gettr tr0, %1\n\t" \ + "pta 4, tr0\n\t" \ + "gettr tr0, %0\n\t" \ + "ptabs %1, tr0\n\t" \ + :"=r" (pc), "=r" (__dummy) \ + : "1" (__dummy)); \ +pc; }) + +/* + * CPU type and hardware bug flags. Kept separately for each CPU. + */ +enum cpu_type { + CPU_SH5_101, + CPU_SH5_103, + CPU_SH_NONE +}; + +/* + * TLB information structure + * + * Defined for both I and D tlb, per-processor. + */ +struct tlb_info { + unsigned long long next; + unsigned long long first; + unsigned long long last; + + unsigned int entries; + unsigned int step; + + unsigned long flags; +}; + +struct sh_cpuinfo { + enum cpu_type type; + unsigned long loops_per_jiffy; + + char hard_math; + + unsigned long *pgd_quick; + unsigned long *pmd_quick; + unsigned long *pte_quick; + unsigned long pgtable_cache_sz; + unsigned int cpu_clock, master_clock, bus_clock, module_clock; + + /* Cache info */ + struct cache_info icache; + struct cache_info dcache; + + /* TLB info */ + struct tlb_info itlb; + struct tlb_info dtlb; +}; + +extern struct sh_cpuinfo boot_cpu_data; + +#define cpu_data (&boot_cpu_data) +#define current_cpu_data boot_cpu_data + +#endif + +/* + * User space process size: 2GB - 4k. + */ +#define TASK_SIZE 0x7ffff000UL + +/* This decides where the kernel will search for a free chunk of vm + * space during mmap's. + */ +#define TASK_UNMAPPED_BASE (TASK_SIZE / 3) + +/* + * Bit of SR register + * + * FD-bit: + * When it's set, it means the processor doesn't have right to use FPU, + * and it results exception when the floating operation is executed. + * + * IMASK-bit: + * Interrupt level mask + * + * STEP-bit: + * Single step bit + * + */ +#define SR_FD 0x00008000 + +#if defined(CONFIG_SH64_SR_WATCH) +#define SR_MMU 0x84000000 +#else +#define SR_MMU 0x80000000 +#endif + +#define SR_IMASK 0x000000f0 +#define SR_SSTEP 0x08000000 + +#ifndef __ASSEMBLY__ + +/* + * FPU structure and data : require 8-byte alignment as we need to access it + with fld.p, fst.p + */ + +struct sh_fpu_hard_struct { + unsigned long fp_regs[64]; + unsigned int fpscr; + /* long status; * software status information */ +}; + +#if 0 +/* Dummy fpu emulator */ +struct sh_fpu_soft_struct { + unsigned long long fp_regs[32]; + unsigned int fpscr; + unsigned char lookahead; + unsigned long entry_pc; +}; +#endif + +union sh_fpu_union { + struct sh_fpu_hard_struct hard; + /* 'hard' itself only produces 32 bit alignment, yet we need + to access it using 64 bit load/store as well. */ + unsigned long long alignment_dummy; +}; + +struct thread_struct { + unsigned long sp; + unsigned long pc; + /* This stores the address of the pt_regs built during a context + switch, or of the register save area built for a kernel mode + exception. It is used for backtracing the stack of a sleeping task + or one that traps in kernel mode. */ + struct pt_regs *kregs; + /* This stores the address of the pt_regs constructed on entry from + user mode. It is a fixed value over the lifetime of a process, or + NULL for a kernel thread. */ + struct pt_regs *uregs; + + unsigned long trap_no, error_code; + unsigned long address; + /* Hardware debugging registers may come here */ + + /* floating point info */ + union sh_fpu_union fpu; +}; + +#define INIT_MMAP \ +{ &init_mm, 0, 0, NULL, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL } + +extern struct pt_regs fake_swapper_regs; + +#define INIT_THREAD { \ + .sp = sizeof(init_stack) + \ + (long) &init_stack, \ + .pc = 0, \ + .kregs = &fake_swapper_regs, \ + .uregs = NULL, \ + .trap_no = 0, \ + .error_code = 0, \ + .address = 0, \ + .fpu = { { { 0, } }, } \ +} + +/* + * Do necessary setup to start up a newly executed thread. + */ +#define SR_USER (SR_MMU | SR_FD) + +#define start_thread(regs, new_pc, new_sp) \ + set_fs(USER_DS); \ + regs->sr = SR_USER; /* User mode. */ \ + regs->pc = new_pc - 4; /* Compensate syscall exit */ \ + regs->pc |= 1; /* Set SHmedia ! */ \ + regs->regs[18] = 0; \ + regs->regs[15] = new_sp + +/* Forward declaration, a strange C thing */ +struct task_struct; +struct mm_struct; + +/* Free all resources held by a thread. */ +extern void release_thread(struct task_struct *); +/* + * create a kernel thread without removing it from tasklists + */ +extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); + +/* + * Bus types + */ +#define MCA_bus 0 +#define MCA_bus__is_a_macro /* for versions in ksyms.c */ + + +/* Copy and release all segment info associated with a VM */ +#define copy_segments(p, mm) do { } while (0) +#define release_segments(mm) do { } while (0) +#define forget_segments() do { } while (0) +#define prepare_to_copy(tsk) do { } while (0) +/* + * FPU lazy state save handling. + */ + +extern __inline__ void release_fpu(void) +{ + unsigned long long __dummy; + + /* Set FD flag in SR */ + __asm__ __volatile__("getcon " __SR ", %0\n\t" + "or %0, %1, %0\n\t" + "putcon %0, " __SR "\n\t" + : "=&r" (__dummy) + : "r" (SR_FD)); +} + +extern __inline__ void grab_fpu(void) +{ + unsigned long long __dummy; + + /* Clear out FD flag in SR */ + __asm__ __volatile__("getcon " __SR ", %0\n\t" + "and %0, %1, %0\n\t" + "putcon %0, " __SR "\n\t" + : "=&r" (__dummy) + : "r" (~SR_FD)); +} + +/* Round to nearest, no exceptions on inexact, overflow, underflow, + zero-divide, invalid. Configure option for whether to flush denorms to + zero, or except if a denorm is encountered. */ +#if defined(CONFIG_SH64_FPU_DENORM_FLUSH) +#define FPSCR_INIT 0x00040000 +#else +#define FPSCR_INIT 0x00000000 +#endif + +/* Save the current FP regs */ +void fpsave(struct sh_fpu_hard_struct *fpregs); + +/* Initialise the FP state of a task */ +void fpinit(struct sh_fpu_hard_struct *fpregs); + +extern struct task_struct *last_task_used_math; + +/* + * Return saved PC of a blocked thread. + */ +#define thread_saved_pc(tsk) (tsk->thread.pc) + +extern unsigned long get_wchan(struct task_struct *p); + +#define KSTK_EIP(tsk) ((tsk)->thread.pc) +#define KSTK_ESP(tsk) ((tsk)->thread.sp) + +#define cpu_relax() do { } while (0) + +#endif /* __ASSEMBLY__ */ +#endif /* __ASM_SH64_PROCESSOR_H */ + diff -puN /dev/null include/asm-sh64/ptrace.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/ptrace.h 2004-06-28 13:30:30.755128352 -0700 @@ -0,0 +1,36 @@ +#ifndef __ASM_SH64_PTRACE_H +#define __ASM_SH64_PTRACE_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. + * + * include/asm-sh64/ptrace.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + */ + +/* + * This struct defines the way the registers are stored on the + * kernel stack during a system call or other kernel entry. + */ +struct pt_regs { + unsigned long long pc; + unsigned long long sr; + unsigned long long syscall_nr; + unsigned long long regs[63]; + unsigned long long tregs[8]; + unsigned long long pad[2]; +}; + +#ifdef __KERNEL__ +#define user_mode(regs) (((regs)->sr & 0x40000000)==0) +#define instruction_pointer(regs) ((regs)->pc) +extern void show_regs(struct pt_regs *); +#endif + +#define PTRACE_O_TRACESYSGOOD 0x00000001 + +#endif /* __ASM_SH64_PTRACE_H */ diff -puN /dev/null include/asm-sh64/registers.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/registers.h 2004-06-28 13:30:30.756128200 -0700 @@ -0,0 +1,106 @@ +#ifndef __ASM_SH64_REGISTERS_H +#define __ASM_SH64_REGISTERS_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. + * + * include/asm-sh64/registers.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2004 Richard Curnow + */ + +#ifdef __ASSEMBLY__ +/* ===================================================================== +** +** Section 1: acts on assembly sources pre-processed by GPP ( ). +** Assigns symbolic names to control & target registers. +*/ + +/* + * Define some useful aliases for control registers. + */ +#define SR cr0 +#define SSR cr1 +#define PSSR cr2 + /* cr3 UNDEFINED */ +#define INTEVT cr4 +#define EXPEVT cr5 +#define PEXPEVT cr6 +#define TRA cr7 +#define SPC cr8 +#define PSPC cr9 +#define RESVEC cr10 +#define VBR cr11 + /* cr12 UNDEFINED */ +#define TEA cr13 + /* cr14-cr15 UNDEFINED */ +#define DCR cr16 +#define KCR0 cr17 +#define KCR1 cr18 + /* cr19-cr31 UNDEFINED */ + /* cr32-cr61 RESERVED */ +#define CTC cr62 +#define USR cr63 + +/* + * ABI dependent registers (general purpose set) + */ +#define RET r2 +#define ARG1 r2 +#define ARG2 r3 +#define ARG3 r4 +#define ARG4 r5 +#define ARG5 r6 +#define ARG6 r7 +#define SP r15 +#define LINK r18 +#define ZERO r63 + +/* + * Status register defines: used only by assembly sources (and + * syntax independednt) + */ +#define SR_RESET_VAL 0x0000000050008000 +#define SR_HARMLESS 0x00000000500080f0 /* Write ignores for most */ +#define SR_ENABLE_FPU 0xffffffffffff7fff /* AND with this */ + +#if defined (CONFIG_SH64_SR_WATCH) +#define SR_ENABLE_MMU 0x0000000084000000 /* OR with this */ +#else +#define SR_ENABLE_MMU 0x0000000080000000 /* OR with this */ +#endif + +#define SR_UNBLOCK_EXC 0xffffffffefffffff /* AND with this */ +#define SR_BLOCK_EXC 0x0000000010000000 /* OR with this */ + +#else /* Not __ASSEMBLY__ syntax */ + +/* +** Stringify reg. name +*/ +#define __str(x) #x + +/* Stringify control register names for use in inline assembly */ +#define __SR __str(SR) +#define __SSR __str(SSR) +#define __PSSR __str(PSSR) +#define __INTEVT __str(INTEVT) +#define __EXPEVT __str(EXPEVT) +#define __PEXPEVT __str(PEXPEVT) +#define __TRA __str(TRA) +#define __SPC __str(SPC) +#define __PSPC __str(PSPC) +#define __RESVEC __str(RESVEC) +#define __VBR __str(VBR) +#define __TEA __str(TEA) +#define __DCR __str(DCR) +#define __KCR0 __str(KCR0) +#define __KCR1 __str(KCR1) +#define __CTC __str(CTC) +#define __USR __str(USR) + +#endif /* __ASSEMBLY__ */ +#endif /* __ASM_SH64_REGISTERS_H */ diff -puN /dev/null include/asm-sh64/resource.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/resource.h 2004-06-28 13:30:30.757128048 -0700 @@ -0,0 +1,47 @@ +#ifndef __ASM_SH_RESOURCE_H +#define __ASM_SH_RESOURCE_H + +/* + * Resource limits + */ + +#define RLIMIT_CPU 0 /* CPU time in ms */ +#define RLIMIT_FSIZE 1 /* Maximum filesize */ +#define RLIMIT_DATA 2 /* max data size */ +#define RLIMIT_STACK 3 /* max stack size */ +#define RLIMIT_CORE 4 /* max core file size */ +#define RLIMIT_RSS 5 /* max resident set size */ +#define RLIMIT_NPROC 6 /* max number of processes */ +#define RLIMIT_NOFILE 7 /* max number of open files */ +#define RLIMIT_MEMLOCK 8 /* max locked-in-memory address space */ +#define RLIMIT_AS 9 /* address space limit */ +#define RLIMIT_LOCKS 10 /* maximum file locks held */ + +#define RLIM_NLIMITS 11 + +#ifdef __KERNEL__ + +/* + * SuS says limits have to be unsigned. + * Which makes a ton more sense anyway. + */ +#define RLIM_INFINITY (~0UL) + +#define INIT_RLIMITS \ +{ \ + { RLIM_INFINITY, RLIM_INFINITY }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ + { _STK_LIM, RLIM_INFINITY }, \ + { 0, RLIM_INFINITY }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ + { 0, 0 }, \ + { INR_OPEN, INR_OPEN }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ +} + +#endif /* __KERNEL__ */ + +#endif /* __ASM_SH_RESOURCE_H */ diff -puN /dev/null include/asm-sh64/scatterlist.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/scatterlist.h 2004-06-28 13:30:30.757128048 -0700 @@ -0,0 +1,23 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * include/asm-sh64/scatterlist.h + * + * Copyright (C) 2003 Paul Mundt + * + */ +#ifndef __ASM_SH64_SCATTERLIST_H +#define __ASM_SH64_SCATTERLIST_H + +struct scatterlist { + struct page * page; /* Location for highmem page, if any */ + unsigned int offset;/* for highmem, page offset */ + dma_addr_t dma_address; + unsigned int length; +}; + +#define ISA_DMA_THRESHOLD (0xffffffff) + +#endif /* !__ASM_SH64_SCATTERLIST_H */ diff -puN /dev/null include/asm-sh64/sections.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/sections.h 2004-06-28 13:30:30.757128048 -0700 @@ -0,0 +1,7 @@ +#ifndef __ASM_SH64_SECTIONS_H +#define __ASM_SH64_SECTIONS_H + +#include + +#endif /* __ASM_SH64_SECTIONS_H */ + diff -puN /dev/null include/asm-sh64/segment.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/segment.h 2004-06-28 13:30:30.757128048 -0700 @@ -0,0 +1,6 @@ +#ifndef _ASM_SEGMENT_H +#define _ASM_SEGMENT_H + +/* Only here because we have some old header files that expect it.. */ + +#endif /* _ASM_SEGMENT_H */ diff -puN /dev/null include/asm-sh64/semaphore.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/semaphore.h 2004-06-28 13:30:30.758127896 -0700 @@ -0,0 +1,146 @@ +#ifndef __ASM_SH64_SEMAPHORE_H +#define __ASM_SH64_SEMAPHORE_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. + * + * include/asm-sh64/semaphore.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + * SMP- and interrupt-safe semaphores. + * + * (C) Copyright 1996 Linus Torvalds + * + * SuperH verison by Niibe Yutaka + * (Currently no asm implementation but generic C code...) + * + */ + +#include +#include +#include +#include + +#include +#include + +struct semaphore { + atomic_t count; + int sleepers; + wait_queue_head_t wait; +#ifdef WAITQUEUE_DEBUG + long __magic; +#endif +}; + +#ifdef WAITQUEUE_DEBUG +# define __SEM_DEBUG_INIT(name) \ + , (int)&(name).__magic +#else +# define __SEM_DEBUG_INIT(name) +#endif + +#define __SEMAPHORE_INITIALIZER(name,count) \ +{ ATOMIC_INIT(count), 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ + __SEM_DEBUG_INIT(name) } + +#define __MUTEX_INITIALIZER(name) \ + __SEMAPHORE_INITIALIZER(name,1) + +#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ + struct semaphore name = __SEMAPHORE_INITIALIZER(name,count) + +#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) +#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0) + +static inline void sema_init (struct semaphore *sem, int val) +{ +/* + * *sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val); + * + * i'd rather use the more flexible initialization above, but sadly + * GCC 2.7.2.3 emits a bogus warning. EGCS doesnt. Oh well. + */ + atomic_set(&sem->count, val); + sem->sleepers = 0; + init_waitqueue_head(&sem->wait); +#ifdef WAITQUEUE_DEBUG + sem->__magic = (int)&sem->__magic; +#endif +} + +static inline void init_MUTEX (struct semaphore *sem) +{ + sema_init(sem, 1); +} + +static inline void init_MUTEX_LOCKED (struct semaphore *sem) +{ + sema_init(sem, 0); +} + +#if 0 +asmlinkage void __down_failed(void /* special register calling convention */); +asmlinkage int __down_failed_interruptible(void /* params in registers */); +asmlinkage int __down_failed_trylock(void /* params in registers */); +asmlinkage void __up_wakeup(void /* special register calling convention */); +#endif + +asmlinkage void __down(struct semaphore * sem); +asmlinkage int __down_interruptible(struct semaphore * sem); +asmlinkage int __down_trylock(struct semaphore * sem); +asmlinkage void __up(struct semaphore * sem); + +extern spinlock_t semaphore_wake_lock; + +static inline void down(struct semaphore * sem) +{ +#ifdef WAITQUEUE_DEBUG + CHECK_MAGIC(sem->__magic); +#endif + + if (atomic_dec_return(&sem->count) < 0) + __down(sem); +} + +static inline int down_interruptible(struct semaphore * sem) +{ + int ret = 0; +#ifdef WAITQUEUE_DEBUG + CHECK_MAGIC(sem->__magic); +#endif + + if (atomic_dec_return(&sem->count) < 0) + ret = __down_interruptible(sem); + return ret; +} + +static inline int down_trylock(struct semaphore * sem) +{ + int ret = 0; +#ifdef WAITQUEUE_DEBUG + CHECK_MAGIC(sem->__magic); +#endif + + if (atomic_dec_return(&sem->count) < 0) + ret = __down_trylock(sem); + return ret; +} + +/* + * Note! This is subtle. We jump to wake people up only if + * the semaphore was negative (== somebody was waiting on it). + */ +static inline void up(struct semaphore * sem) +{ +#ifdef WAITQUEUE_DEBUG + CHECK_MAGIC(sem->__magic); +#endif + if (atomic_inc_return(&sem->count) <= 0) + __up(sem); +} + +#endif /* __ASM_SH64_SEMAPHORE_H */ diff -puN /dev/null include/asm-sh64/semaphore-helper.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/semaphore-helper.h 2004-06-28 13:30:30.759127744 -0700 @@ -0,0 +1,101 @@ +#ifndef __ASM_SH64_SEMAPHORE_HELPER_H +#define __ASM_SH64_SEMAPHORE_HELPER_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. + * + * include/asm-sh64/semaphore-helper.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + */ +#include + +/* + * SMP- and interrupt-safe semaphores helper functions. + * + * (C) Copyright 1996 Linus Torvalds + * (C) Copyright 1999 Andrea Arcangeli + */ + +/* + * These two _must_ execute atomically wrt each other. + * + * This is trivially done with load_locked/store_cond, + * which we have. Let the rest of the losers suck eggs. + */ +static __inline__ void wake_one_more(struct semaphore * sem) +{ + atomic_inc((atomic_t *)&sem->sleepers); +} + +static __inline__ int waking_non_zero(struct semaphore *sem) +{ + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&semaphore_wake_lock, flags); + if (sem->sleepers > 0) { + sem->sleepers--; + ret = 1; + } + spin_unlock_irqrestore(&semaphore_wake_lock, flags); + return ret; +} + +/* + * waking_non_zero_interruptible: + * 1 got the lock + * 0 go to sleep + * -EINTR interrupted + * + * We must undo the sem->count down_interruptible() increment while we are + * protected by the spinlock in order to make atomic this atomic_inc() with the + * atomic_read() in wake_one_more(), otherwise we can race. -arca + */ +static __inline__ int waking_non_zero_interruptible(struct semaphore *sem, + struct task_struct *tsk) +{ + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&semaphore_wake_lock, flags); + if (sem->sleepers > 0) { + sem->sleepers--; + ret = 1; + } else if (signal_pending(tsk)) { + atomic_inc(&sem->count); + ret = -EINTR; + } + spin_unlock_irqrestore(&semaphore_wake_lock, flags); + return ret; +} + +/* + * waking_non_zero_trylock: + * 1 failed to lock + * 0 got the lock + * + * We must undo the sem->count down_trylock() increment while we are + * protected by the spinlock in order to make atomic this atomic_inc() with the + * atomic_read() in wake_one_more(), otherwise we can race. -arca + */ +static __inline__ int waking_non_zero_trylock(struct semaphore *sem) +{ + unsigned long flags; + int ret = 1; + + spin_lock_irqsave(&semaphore_wake_lock, flags); + if (sem->sleepers <= 0) + atomic_inc(&sem->count); + else { + sem->sleepers--; + ret = 0; + } + spin_unlock_irqrestore(&semaphore_wake_lock, flags); + return ret; +} + +#endif /* __ASM_SH64_SEMAPHORE_HELPER_H */ diff -puN /dev/null include/asm-sh64/sembuf.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/sembuf.h 2004-06-28 13:30:30.759127744 -0700 @@ -0,0 +1,36 @@ +#ifndef __ASM_SH64_SEMBUF_H +#define __ASM_SH64_SEMBUF_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. + * + * include/asm-sh64/sembuf.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + */ + +/* + * The semid64_ds structure for i386 architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 64-bit time_t to solve y2038 problem + * - 2 miscellaneous 32-bit values + */ + +struct semid64_ds { + struct ipc64_perm sem_perm; /* permissions .. see ipc.h */ + __kernel_time_t sem_otime; /* last semop time */ + unsigned long __unused1; + __kernel_time_t sem_ctime; /* last change time */ + unsigned long __unused2; + unsigned long sem_nsems; /* no. of semaphores in array */ + unsigned long __unused3; + unsigned long __unused4; +}; + +#endif /* __ASM_SH64_SEMBUF_H */ diff -puN /dev/null include/asm-sh64/serial.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/serial.h 2004-06-28 13:30:30.759127744 -0700 @@ -0,0 +1,33 @@ +/* + * include/asm-sh/serial.h + * + * Configuration details for 8250, 16450, 16550, etc. serial ports + */ + +#ifndef _ASM_SERIAL_H +#define _ASM_SERIAL_H + +/* + * This assumes you have a 1.8432 MHz clock for your UART. + * + * It'd be nice if someone built a serial card with a 24.576 MHz + * clock, since the 16550A is capable of handling a top speed of 1.5 + * megabits/second; but this requires the faster clock. + */ +#define BASE_BAUD ( 1843200 / 16 ) + +#define RS_TABLE_SIZE 2 + +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) + +#define STD_SERIAL_PORT_DEFNS \ + /* UART CLK PORT IRQ FLAGS */ \ + { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS }, /* ttyS0 */ \ + { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS } /* ttyS1 */ + +#define SERIAL_PORT_DFNS STD_SERIAL_PORT_DEFNS + +/* XXX: This should be moved ino irq.h */ +#define irq_cannonicalize(x) (x) + +#endif /* _ASM_SERIAL_H */ diff -puN /dev/null include/asm-sh64/shmbuf.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/shmbuf.h 2004-06-28 13:30:30.760127592 -0700 @@ -0,0 +1,53 @@ +#ifndef __ASM_SH64_SHMBUF_H +#define __ASM_SH64_SHMBUF_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. + * + * include/asm-sh64/shmbuf.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + */ + +/* + * The shmid64_ds structure for i386 architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 64-bit time_t to solve y2038 problem + * - 2 miscellaneous 32-bit values + */ + +struct shmid64_ds { + struct ipc64_perm shm_perm; /* operation perms */ + size_t shm_segsz; /* size of segment (bytes) */ + __kernel_time_t shm_atime; /* last attach time */ + unsigned long __unused1; + __kernel_time_t shm_dtime; /* last detach time */ + unsigned long __unused2; + __kernel_time_t shm_ctime; /* last change time */ + unsigned long __unused3; + __kernel_pid_t shm_cpid; /* pid of creator */ + __kernel_pid_t shm_lpid; /* pid of last operator */ + unsigned long shm_nattch; /* no. of current attaches */ + unsigned long __unused4; + unsigned long __unused5; +}; + +struct shminfo64 { + unsigned long shmmax; + unsigned long shmmin; + unsigned long shmmni; + unsigned long shmseg; + unsigned long shmall; + unsigned long __unused1; + unsigned long __unused2; + unsigned long __unused3; + unsigned long __unused4; +}; + +#endif /* __ASM_SH64_SHMBUF_H */ diff -puN /dev/null include/asm-sh64/shmparam.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/shmparam.h 2004-06-28 13:30:30.760127592 -0700 @@ -0,0 +1,20 @@ +#ifndef __ASM_SH64_SHMPARAM_H +#define __ASM_SH64_SHMPARAM_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. + * + * include/asm-sh64/shmparam.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + */ + +#include + +/* attach addr a multiple of this */ +#define SHMLBA (cpu_data->dcache.sets * L1_CACHE_BYTES) + +#endif /* __ASM_SH64_SHMPARAM_H */ diff -puN /dev/null include/asm-sh64/sigcontext.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/sigcontext.h 2004-06-28 13:30:30.761127440 -0700 @@ -0,0 +1,30 @@ +#ifndef __ASM_SH64_SIGCONTEXT_H +#define __ASM_SH64_SIGCONTEXT_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. + * + * include/asm-sh64/sigcontext.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + */ + +struct sigcontext { + unsigned long oldmask; + + /* CPU registers */ + unsigned long long sc_regs[63]; + unsigned long long sc_tregs[8]; + unsigned long long sc_pc; + unsigned long long sc_sr; + + /* FPU registers */ + unsigned long long sc_fpregs[32]; + unsigned int sc_fpscr; + unsigned int sc_fpvalid; +}; + +#endif /* __ASM_SH64_SIGCONTEXT_H */ diff -puN /dev/null include/asm-sh64/siginfo.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/siginfo.h 2004-06-28 13:30:30.761127440 -0700 @@ -0,0 +1,6 @@ +#ifndef __ASM_SH64_SIGINFO_H +#define __ASM_SH64_SIGINFO_H + +#include + +#endif /* __ASM_SH64_SIGINFO_H */ diff -puN /dev/null include/asm-sh64/signal.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/signal.h 2004-06-28 13:30:30.762127288 -0700 @@ -0,0 +1,185 @@ +#ifndef __ASM_SH64_SIGNAL_H +#define __ASM_SH64_SIGNAL_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. + * + * include/asm-sh64/signal.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + */ + +#include +#include + +/* Avoid too many header ordering problems. */ +struct siginfo; + +#define _NSIG 64 +#define _NSIG_BPW 32 +#define _NSIG_WORDS (_NSIG / _NSIG_BPW) + +typedef unsigned long old_sigset_t; /* at least 32 bits */ + +typedef struct { + unsigned long sig[_NSIG_WORDS]; +} sigset_t; + +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGIOT 6 +#define SIGBUS 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGSEGV 11 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGURG 23 +#define SIGXCPU 24 +#define SIGXFSZ 25 +#define SIGVTALRM 26 +#define SIGPROF 27 +#define SIGWINCH 28 +#define SIGIO 29 +#define SIGPOLL SIGIO +/* +#define SIGLOST 29 +*/ +#define SIGPWR 30 +#define SIGSYS 31 +#define SIGUNUSED 31 + +/* These should not be considered constants from userland. */ +#define SIGRTMIN 32 +#define SIGRTMAX (_NSIG-1) + +/* + * SA_FLAGS values: + * + * SA_ONSTACK indicates that a registered stack_t will be used. + * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the + * SA_RESTART flag to get restarting signals (which were the default long ago) + * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. + * SA_RESETHAND clears the handler when the signal is delivered. + * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. + * SA_NODEFER prevents the current signal from being masked in the handler. + * + * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single + * Unix names RESETHAND and NODEFER respectively. + */ +#define SA_NOCLDSTOP 0x00000001 +#define SA_NOCLDWAIT 0x00000002 /* not supported yet */ +#define SA_SIGINFO 0x00000004 +#define SA_ONSTACK 0x08000000 +#define SA_RESTART 0x10000000 +#define SA_NODEFER 0x40000000 +#define SA_RESETHAND 0x80000000 + +#define SA_NOMASK SA_NODEFER +#define SA_ONESHOT SA_RESETHAND +#define SA_INTERRUPT 0x20000000 /* dummy -- ignored */ + +#define SA_RESTORER 0x04000000 + +/* + * sigaltstack controls + */ +#define SS_ONSTACK 1 +#define SS_DISABLE 2 + +#define MINSIGSTKSZ 2048 +#define SIGSTKSZ THREAD_SIZE + +#ifdef __KERNEL__ + +/* + * These values of sa_flags are used only by the kernel as part of the + * irq handling routines. + * + * SA_INTERRUPT is also used by the irq handling routines. + * SA_SHIRQ is for shared interrupt support on PCI and EISA. + */ +#define SA_PROBE SA_ONESHOT +#define SA_SAMPLE_RANDOM SA_RESTART +#define SA_SHIRQ 0x04000000 +#endif + +#define SIG_BLOCK 0 /* for blocking signals */ +#define SIG_UNBLOCK 1 /* for unblocking signals */ +#define SIG_SETMASK 2 /* for setting the signal mask */ + +/* Type of a signal handler. */ +typedef void (*__sighandler_t)(int); + +#define SIG_DFL ((__sighandler_t)0) /* default signal handling */ +#define SIG_IGN ((__sighandler_t)1) /* ignore signal */ +#define SIG_ERR ((__sighandler_t)-1) /* error return from signal */ + +#ifdef __KERNEL__ +struct old_sigaction { + __sighandler_t sa_handler; + old_sigset_t sa_mask; + unsigned long sa_flags; + void (*sa_restorer)(void); +}; + +struct sigaction { + __sighandler_t sa_handler; + unsigned long sa_flags; + void (*sa_restorer)(void); + sigset_t sa_mask; /* mask last for extensibility */ +}; + +struct k_sigaction { + struct sigaction sa; +}; +#else +/* Here we must cater to libcs that poke about in kernel headers. */ + +struct sigaction { + union { + __sighandler_t _sa_handler; + void (*_sa_sigaction)(int, struct siginfo *, void *); + } _u; + sigset_t sa_mask; + unsigned long sa_flags; + void (*sa_restorer)(void); +}; + +#define sa_handler _u._sa_handler +#define sa_sigaction _u._sa_sigaction + +#endif /* __KERNEL__ */ + +typedef struct sigaltstack { + void *ss_sp; + int ss_flags; + size_t ss_size; +} stack_t; + +#ifdef __KERNEL__ +#include + +#define sigmask(sig) (1UL << ((sig) - 1)) +#define ptrace_signal_deliver(regs, cookie) do { } while (0) + +#endif /* __KERNEL__ */ + +#endif /* __ASM_SH64_SIGNAL_H */ diff -puN /dev/null include/asm-sh64/smp.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/smp.h 2004-06-28 13:30:30.762127288 -0700 @@ -0,0 +1,15 @@ +#ifndef __ASM_SH64_SMP_H +#define __ASM_SH64_SMP_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. + * + * include/asm-sh64/smp.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + */ + +#endif /* __ASM_SH64_SMP_H */ diff -puN /dev/null include/asm-sh64/smplock.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/smplock.h 2004-06-28 13:30:30.762127288 -0700 @@ -0,0 +1,77 @@ +#ifndef __ASM_SH64_SMPLOCK_H +#define __ASM_SH64_SMPLOCK_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. + * + * include/asm-sh64/smplock.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + */ + +#include + +#ifndef CONFIG_SMP + +#define lock_kernel() do { } while(0) +#define unlock_kernel() do { } while(0) +#define release_kernel_lock(task, cpu, depth) ((depth) = 1) +#define reacquire_kernel_lock(task, cpu, depth) do { } while(0) + +#else + +#error "We do not support SMP on SH64 yet" +/* + * Default SMP lock implementation + */ + +#include +#include + +extern spinlock_t kernel_flag; + +/* + * Getting the big kernel lock. + * + * This cannot happen asynchronously, + * so we only need to worry about other + * CPU's. + */ +extern __inline__ void lock_kernel(void) +{ + if (!++current->lock_depth) + spin_lock(&kernel_flag); +} + +extern __inline__ void unlock_kernel(void) +{ + if (--current->lock_depth < 0) + spin_unlock(&kernel_flag); +} + +/* + * Release global kernel lock and global interrupt lock + */ +#define release_kernel_lock(task, cpu) \ +do { \ + if (task->lock_depth >= 0) \ + spin_unlock(&kernel_flag); \ + release_irqlock(cpu); \ + __sti(); \ +} while (0) + +/* + * Re-acquire the kernel lock + */ +#define reacquire_kernel_lock(task) \ +do { \ + if (task->lock_depth >= 0) \ + spin_lock(&kernel_flag); \ +} while (0) + +#endif /* CONFIG_SMP */ + +#endif /* __ASM_SH64_SMPLOCK_H */ diff -puN /dev/null include/asm-sh64/socket.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/socket.h 2004-06-28 13:30:30.763127136 -0700 @@ -0,0 +1,6 @@ +#ifndef __ASM_SH64_SOCKET_H +#define __ASM_SH64_SOCKET_H + +#include + +#endif /* __ASM_SH64_SOCKET_H */ diff -puN /dev/null include/asm-sh64/sockios.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/sockios.h 2004-06-28 13:30:30.763127136 -0700 @@ -0,0 +1,24 @@ +#ifndef __ASM_SH64_SOCKIOS_H +#define __ASM_SH64_SOCKIOS_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. + * + * include/asm-sh64/sockios.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + */ + +/* Socket-level I/O control calls. */ +#define FIOGETOWN _IOR('f', 123, int) +#define FIOSETOWN _IOW('f', 124, int) + +#define SIOCATMARK _IOR('s', 7, int) +#define SIOCSPGRP _IOW('s', 8, pid_t) +#define SIOCGPGRP _IOR('s', 9, pid_t) + +#define SIOCGSTAMP _IOR('s', 100, struct timeval) /* Get stamp - linux-specific */ +#endif /* __ASM_SH64_SOCKIOS_H */ diff -puN /dev/null include/asm-sh64/softirq.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/softirq.h 2004-06-28 13:30:30.764126984 -0700 @@ -0,0 +1,30 @@ +#ifndef __ASM_SH_SOFTIRQ_H +#define __ASM_SH_SOFTIRQ_H + +#include +#include + +#define local_bh_disable() \ +do { \ + local_bh_count(smp_processor_id())++; \ + barrier(); \ +} while (0) + +#define __local_bh_enable() \ +do { \ + barrier(); \ + local_bh_count(smp_processor_id())--; \ +} while (0) + +#define local_bh_enable() \ +do { \ + barrier(); \ + if (!--local_bh_count(smp_processor_id()) \ + && softirq_pending(smp_processor_id())) { \ + do_softirq(); \ + } \ +} while (0) + +#define in_softirq() (local_bh_count(smp_processor_id()) != 0) + +#endif /* __ASM_SH_SOFTIRQ_H */ diff -puN /dev/null include/asm-sh64/spinlock.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/spinlock.h 2004-06-28 13:30:30.764126984 -0700 @@ -0,0 +1,17 @@ +#ifndef __ASM_SH64_SPINLOCK_H +#define __ASM_SH64_SPINLOCK_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. + * + * include/asm-sh64/spinlock.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + */ + +#error "No SMP on SH64" + +#endif /* __ASM_SH64_SPINLOCK_H */ diff -puN /dev/null include/asm-sh64/statfs.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/statfs.h 2004-06-28 13:30:30.764126984 -0700 @@ -0,0 +1,6 @@ +#ifndef __ASM_SH64_STATFS_H +#define __ASM_SH64_STATFS_H + +#include + +#endif /* __ASM_SH64_STATFS_H */ diff -puN /dev/null include/asm-sh64/stat.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/stat.h 2004-06-28 13:30:30.765126832 -0700 @@ -0,0 +1,88 @@ +#ifndef __ASM_SH64_STAT_H +#define __ASM_SH64_STAT_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. + * + * include/asm-sh64/stat.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + */ + +struct __old_kernel_stat { + unsigned short st_dev; + unsigned short st_ino; + unsigned short st_mode; + unsigned short st_nlink; + unsigned short st_uid; + unsigned short st_gid; + unsigned short st_rdev; + unsigned long st_size; + unsigned long st_atime; + unsigned long st_mtime; + unsigned long st_ctime; +}; + +struct stat { + unsigned short st_dev; + unsigned short __pad1; + unsigned long st_ino; + unsigned short st_mode; + unsigned short st_nlink; + unsigned short st_uid; + unsigned short st_gid; + unsigned short st_rdev; + unsigned short __pad2; + unsigned long st_size; + unsigned long st_blksize; + unsigned long st_blocks; + unsigned long st_atime; + unsigned long st_atime_nsec; + unsigned long st_mtime; + unsigned long st_mtime_nsec; + unsigned long st_ctime; + unsigned long st_ctime_nsec; + unsigned long __unused4; + unsigned long __unused5; +}; + +/* This matches struct stat64 in glibc2.1, hence the absolutely + * insane amounts of padding around dev_t's. + */ +struct stat64 { + unsigned short st_dev; + unsigned char __pad0[10]; + + unsigned long st_ino; + unsigned int st_mode; + unsigned int st_nlink; + + unsigned long st_uid; + unsigned long st_gid; + + unsigned short st_rdev; + unsigned char __pad3[10]; + + long long st_size; + unsigned long st_blksize; + + unsigned long st_blocks; /* Number 512-byte blocks allocated. */ + unsigned long __pad4; /* future possible st_blocks high bits */ + + unsigned long st_atime; + unsigned long st_atime_nsec; + + unsigned long st_mtime; + unsigned long st_mtime_nsec; + + unsigned long st_ctime; + unsigned long st_ctime_nsec; /* will be high 32 bits of ctime someday */ + + unsigned long __unused1; + unsigned long __unused2; +}; + +#endif /* __ASM_SH64_STAT_H */ diff -puN /dev/null include/asm-sh64/string.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/string.h 2004-06-28 13:30:30.765126832 -0700 @@ -0,0 +1,21 @@ +#ifndef __ASM_SH64_STRING_H +#define __ASM_SH64_STRING_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. + * + * include/asm-sh64/string.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + * Empty on purpose. ARCH SH64 ASM libs are out of the current project scope. + * + */ + +#define __HAVE_ARCH_MEMCPY + +extern void *memcpy(void *dest, const void *src, size_t count); + +#endif diff -puN /dev/null include/asm-sh64/system.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/system.h 2004-06-28 13:30:30.766126680 -0700 @@ -0,0 +1,194 @@ +#ifndef __ASM_SH64_SYSTEM_H +#define __ASM_SH64_SYSTEM_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. + * + * include/asm-sh64/system.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003 Paul Mundt + * Copyright (C) 2004 Richard Curnow + * + */ + +#include +#include +#include +#include + +/* + * switch_to() should switch tasks to task nr n, first + */ + +typedef struct { + unsigned long seg; +} mm_segment_t; + +extern struct task_struct *sh64_switch_to(struct task_struct *prev, + struct thread_struct *prev_thread, + struct task_struct *next, + struct thread_struct *next_thread); + +#define switch_to(prev,next,last) \ + do {\ + if (last_task_used_math != next) {\ + struct pt_regs *regs = next->thread.uregs;\ + if (regs) regs->sr |= SR_FD;\ + }\ + last = sh64_switch_to(prev, &prev->thread, next, &next->thread);\ + } while(0) + +#define nop() __asm__ __volatile__ ("nop") + +#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) + +#define tas(ptr) (xchg((ptr), 1)) + +extern void __xchg_called_with_bad_pointer(void); + +#define mb() __asm__ __volatile__ ("synco": : :"memory") +#define rmb() mb() +#define wmb() __asm__ __volatile__ ("synco": : :"memory") +#define read_barrier_depends() do { } while (0) + +#ifdef CONFIG_SMP +#define smp_mb() mb() +#define smp_rmb() rmb() +#define smp_wmb() wmb() +#define smp_read_barrier_depends() read_barrier_depends() +#else +#define smp_mb() barrier() +#define smp_rmb() barrier() +#define smp_wmb() barrier() +#define smp_read_barrier_depends() do { } while (0) +#endif /* CONFIG_SMP */ + +#define set_rmb(var, value) do { xchg(&var, value); } while (0) +#define set_mb(var, value) set_rmb(var, value) +#define set_wmb(var, value) do { var = value; wmb(); } while (0) + +/* Interrupt Control */ +#ifndef HARD_CLI +#define SR_MASK_L 0x000000f0L +#define SR_MASK_LL 0x00000000000000f0LL +#else +#define SR_MASK_L 0x10000000L +#define SR_MASK_LL 0x0000000010000000LL +#endif + +static __inline__ void local_irq_enable(void) +{ + /* cli/sti based on SR.BL */ + unsigned long long __dummy0, __dummy1=~SR_MASK_LL; + + __asm__ __volatile__("getcon " __SR ", %0\n\t" + "and %0, %1, %0\n\t" + "putcon %0, " __SR "\n\t" + : "=&r" (__dummy0) + : "r" (__dummy1)); +} + +static __inline__ void local_irq_disable(void) +{ + /* cli/sti based on SR.BL */ + unsigned long long __dummy0, __dummy1=SR_MASK_LL; + __asm__ __volatile__("getcon " __SR ", %0\n\t" + "or %0, %1, %0\n\t" + "putcon %0, " __SR "\n\t" + : "=&r" (__dummy0) + : "r" (__dummy1)); +} + +#define local_save_flags(x) \ +(__extension__ ({ unsigned long long __dummy=SR_MASK_LL; \ + __asm__ __volatile__( \ + "getcon " __SR ", %0\n\t" \ + "and %0, %1, %0" \ + : "=&r" (x) \ + : "r" (__dummy));})) + +#define local_irq_save(x) \ +(__extension__ ({ unsigned long long __d2=SR_MASK_LL, __d1; \ + __asm__ __volatile__( \ + "getcon " __SR ", %1\n\t" \ + "or %1, r63, %0\n\t" \ + "or %1, %2, %1\n\t" \ + "putcon %1, " __SR "\n\t" \ + "and %0, %2, %0" \ + : "=&r" (x), "=&r" (__d1) \ + : "r" (__d2));})); + +#define local_irq_restore(x) do { \ + if ( ((x) & SR_MASK_L) == 0 ) /* dropping to 0 ? */ \ + local_irq_enable(); /* yes...re-enable */ \ +} while (0) + +#define irqs_disabled() \ +({ \ + unsigned long flags; \ + local_save_flags(flags); \ + (flags != 0); \ +}) + +extern __inline__ unsigned long xchg_u32(volatile int * m, unsigned long val) +{ + unsigned long flags, retval; + + local_irq_save(flags); + retval = *m; + *m = val; + local_irq_restore(flags); + return retval; +} + +extern __inline__ unsigned long xchg_u8(volatile unsigned char * m, unsigned long val) +{ + unsigned long flags, retval; + + local_irq_save(flags); + retval = *m; + *m = val & 0xff; + local_irq_restore(flags); + return retval; +} + +static __inline__ unsigned long __xchg(unsigned long x, volatile void * ptr, int size) +{ + switch (size) { + case 4: + return xchg_u32(ptr, x); + break; + case 1: + return xchg_u8(ptr, x); + break; + } + __xchg_called_with_bad_pointer(); + return x; +} + +/* XXX + * disable hlt during certain critical i/o operations + */ +#define HAVE_DISABLE_HLT +void disable_hlt(void); +void enable_hlt(void); + + +#define smp_mb() barrier() +#define smp_rmb() barrier() +#define smp_wmb() barrier() + +#ifdef CONFIG_SH_ALPHANUMERIC +/* This is only used for debugging. */ +extern void print_seg(char *file,int line); +#define PLS() print_seg(__FILE__,__LINE__) +#else /* CONFIG_SH_ALPHANUMERIC */ +#define PLS() +#endif /* CONFIG_SH_ALPHANUMERIC */ + +#define PL() printk("@ <%s,%s:%d>\n",__FILE__,__FUNCTION__,__LINE__) + +#endif /* __ASM_SH64_SYSTEM_H */ diff -puN /dev/null include/asm-sh64/termbits.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/termbits.h 2004-06-28 13:30:30.766126680 -0700 @@ -0,0 +1,6 @@ +#ifndef __ASM_SH64_TERMBITS_H +#define __ASM_SH64_TERMBITS_H + +#include + +#endif /* __ASM_SH64_TERMBITS_H */ diff -puN /dev/null include/asm-sh64/termios.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/termios.h 2004-06-28 13:30:30.767126528 -0700 @@ -0,0 +1,117 @@ +#ifndef __ASM_SH64_TERMIOS_H +#define __ASM_SH64_TERMIOS_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. + * + * include/asm-sh64/termios.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + */ + +#include +#include + +struct winsize { + unsigned short ws_row; + unsigned short ws_col; + unsigned short ws_xpixel; + unsigned short ws_ypixel; +}; + +#define NCC 8 +struct termio { + unsigned short c_iflag; /* input mode flags */ + unsigned short c_oflag; /* output mode flags */ + unsigned short c_cflag; /* control mode flags */ + unsigned short c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[NCC]; /* control characters */ +}; + +/* modem lines */ +#define TIOCM_LE 0x001 +#define TIOCM_DTR 0x002 +#define TIOCM_RTS 0x004 +#define TIOCM_ST 0x008 +#define TIOCM_SR 0x010 +#define TIOCM_CTS 0x020 +#define TIOCM_CAR 0x040 +#define TIOCM_RNG 0x080 +#define TIOCM_DSR 0x100 +#define TIOCM_CD TIOCM_CAR +#define TIOCM_RI TIOCM_RNG +#define TIOCM_OUT1 0x2000 +#define TIOCM_OUT2 0x4000 +#define TIOCM_LOOP 0x8000 + +/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ + +/* line disciplines */ +#define N_TTY 0 +#define N_SLIP 1 +#define N_MOUSE 2 +#define N_PPP 3 +#define N_STRIP 4 +#define N_AX25 5 +#define N_X25 6 /* X.25 async */ +#define N_6PACK 7 +#define N_MASC 8 /* Reserved for Mobitex module */ +#define N_R3964 9 /* Reserved for Simatic R3964 module */ +#define N_PROFIBUS_FDL 10 /* Reserved for Profibus */ +#define N_IRDA 11 /* Linux IR - http://www.cs.uit.no/~dagb/irda/irda.html */ +#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */ +#define N_HDLC 13 /* synchronous HDLC */ +#define N_SYNC_PPP 14 +#define N_HCI 15 /* Bluetooth HCI UART */ + +#ifdef __KERNEL__ + +/* intr=^C quit=^\ erase=del kill=^U + eof=^D vtime=\0 vmin=\1 sxtc=\0 + start=^Q stop=^S susp=^Z eol=\0 + reprint=^R discard=^U werase=^W lnext=^V + eol2=\0 +*/ +#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0" + +/* + * Translate a "termio" structure into a "termios". Ugh. + */ +#define SET_LOW_TERMIOS_BITS(termios, termio, x) { \ + unsigned short __tmp; \ + get_user(__tmp,&(termio)->x); \ + *(unsigned short *) &(termios)->x = __tmp; \ +} + +#define user_termio_to_kernel_termios(termios, termio) \ +({ \ + SET_LOW_TERMIOS_BITS(termios, termio, c_iflag); \ + SET_LOW_TERMIOS_BITS(termios, termio, c_oflag); \ + SET_LOW_TERMIOS_BITS(termios, termio, c_cflag); \ + SET_LOW_TERMIOS_BITS(termios, termio, c_lflag); \ + copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \ +}) + +/* + * Translate a "termios" structure into a "termio". Ugh. + */ +#define kernel_termios_to_user_termio(termio, termios) \ +({ \ + put_user((termios)->c_iflag, &(termio)->c_iflag); \ + put_user((termios)->c_oflag, &(termio)->c_oflag); \ + put_user((termios)->c_cflag, &(termio)->c_cflag); \ + put_user((termios)->c_lflag, &(termio)->c_lflag); \ + put_user((termios)->c_line, &(termio)->c_line); \ + copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \ +}) + +#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios)) +#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios)) + +#endif /* __KERNEL__ */ + +#endif /* __ASM_SH64_TERMIOS_H */ diff -puN /dev/null include/asm-sh64/thread_info.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/thread_info.h 2004-06-28 13:30:30.767126528 -0700 @@ -0,0 +1,82 @@ +#ifndef __ASM_SH64_THREAD_INFO_H +#define __ASM_SH64_THREAD_INFO_H + +/* + * SuperH 5 version + * Copyright (C) 2003 Paul Mundt + */ + +#ifdef __KERNEL__ + +#ifndef __ASSEMBLY__ +#include + +/* + * 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 thread_info { + struct task_struct *task; /* main task structure */ + struct exec_domain *exec_domain; /* execution domain */ + __u32 flags; /* low level flags */ + /* Put the 4 32-bit fields together to make asm offsetting easier. */ + __s32 preempt_count; /* 0 => preemptable, <0 => BUG */ + __u16 cpu; + + mm_segment_t addr_limit; + struct restart_block restart_block; + + __u8 supervisor_stack[0]; +}; + +/* + * macros/functions for gaining access to the thread information structure + */ +#define INIT_THREAD_INFO(tsk) \ +{ \ + .task = &tsk, \ + .exec_domain = &default_exec_domain, \ + .flags = 0, \ + .cpu = 0, \ + .preempt_count = 1, \ + .addr_limit = KERNEL_DS, \ + .restart_block = { \ + .fn = do_no_restart_syscall, \ + }, \ +} + +#define init_thread_info (init_thread_union.thread_info) +#define init_stack (init_thread_union.stack) + +/* how to get the thread information struct from C */ +static inline struct thread_info *current_thread_info(void) +{ + struct thread_info *ti; + + __asm__ __volatile__ ("getcon " __KCR0 ", %0\n\t" : "=r" (ti)); + + return ti; +} + +/* thread information allocation */ +#define alloc_thread_info(ti) ((struct thread_info *) __get_free_pages(GFP_KERNEL,2)) +#define free_thread_info(ti) free_pages((unsigned long) (ti), 1) +#define get_thread_info(ti) get_task_struct((ti)->task) +#define put_thread_info(ti) put_task_struct((ti)->task) + +#endif /* __ASSEMBLY__ */ + +#define PREEMPT_ACTIVE 0x4000000 + +/* thread information flags */ +#define TIF_SYSCALL_TRACE 0 /* syscall trace active */ +#define TIF_SIGPENDING 2 /* signal pending */ +#define TIF_NEED_RESCHED 3 /* rescheduling necessary */ + +#define THREAD_SIZE 16384 + +#endif /* __KERNEL__ */ + +#endif /* __ASM_SH64_THREAD_INFO_H */ diff -puN /dev/null include/asm-sh64/timex.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/timex.h 2004-06-28 13:30:30.768126376 -0700 @@ -0,0 +1,36 @@ +#ifndef __ASM_SH64_TIMEX_H +#define __ASM_SH64_TIMEX_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. + * + * include/asm-sh64/timex.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003 Paul Mundt + * + * sh-5 architecture timex specifications + * + */ + +#define CLOCK_TICK_RATE 1193180 /* Underlying HZ */ +#define CLOCK_TICK_FACTOR 20 /* Factor of both 1000000 and CLOCK_TICK_RATE */ +#define FINETUNE ((((((long)LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \ + (1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \ + << (SHIFT_SCALE-SHIFT_HZ)) / HZ) + +typedef unsigned long cycles_t; + +extern cycles_t cacheflush_time; + +static __inline__ cycles_t get_cycles (void) +{ + return 0; +} + +#define vxtime_lock() do {} while (0) +#define vxtime_unlock() do {} while (0) + +#endif /* __ASM_SH64_TIMEX_H */ diff -puN /dev/null include/asm-sh64/tlbflush.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/tlbflush.h 2004-06-28 13:30:30.768126376 -0700 @@ -0,0 +1,31 @@ +#ifndef __ASM_SH64_TLBFLUSH_H +#define __ASM_SH64_TLBFLUSH_H + +#include + +/* + * TLB flushing: + * + * - flush_tlb() flushes the current mm struct TLBs + * - flush_tlb_all() flushes all processes TLBs + * - flush_tlb_mm(mm) flushes the specified mm context TLB's + * - flush_tlb_page(vma, vmaddr) flushes one page + * - flush_tlb_range(mm, start, end) flushes a range of pages + * + */ + +extern void flush_tlb(void); +extern void flush_tlb_all(void); +extern void flush_tlb_mm(struct mm_struct *mm); +extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end); +extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long page); +extern inline void flush_tlb_pgtables(struct mm_struct *mm, + unsigned long start, unsigned long end) +{ +} + +extern void flush_tlb_kernel_range(unsigned long start, unsigned long end); + +#endif /* __ASM_SH64_TLBFLUSH_H */ + diff -puN /dev/null include/asm-sh64/tlb.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/tlb.h 2004-06-28 13:30:30.769126224 -0700 @@ -0,0 +1,92 @@ +/* + * include/asm-sh64/tlb.h + * + * Copyright (C) 2003 Paul Mundt + * + * 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_SH64_TLB_H +#define __ASM_SH64_TLB_H + +/* + * Note! These are mostly unused, we just need the xTLB_LAST_VAR_UNRESTRICTED + * for head.S! Once this limitation is gone, we can clean the rest of this up. + */ + +/* ITLB defines */ +#define ITLB_FIXED 0x00000000 /* First fixed ITLB, see head.S */ +#define ITLB_LAST_VAR_UNRESTRICTED 0x000003F0 /* Last ITLB */ + +/* DTLB defines */ +#define DTLB_FIXED 0x00800000 /* First fixed DTLB, see head.S */ +#define DTLB_LAST_VAR_UNRESTRICTED 0x008003F0 /* Last DTLB */ + +#ifndef __ASSEMBLY__ + +/** + * for_each_dtlb_entry + * + * @tlb: TLB entry + * + * Iterate over free (non-wired) DTLB entries + */ +#define for_each_dtlb_entry(tlb) \ + for (tlb = cpu_data->dtlb.first; \ + tlb <= cpu_data->dtlb.last; \ + tlb += cpu_data->dtlb.step) + +/** + * for_each_itlb_entry + * + * @tlb: TLB entry + * + * Iterate over free (non-wired) ITLB entries + */ +#define for_each_itlb_entry(tlb) \ + for (tlb = cpu_data->itlb.first; \ + tlb <= cpu_data->itlb.last; \ + tlb += cpu_data->itlb.step) + +/** + * __flush_tlb_slot + * + * @slot: Address of TLB slot. + * + * Flushes TLB slot @slot. + */ +static inline void __flush_tlb_slot(unsigned long long slot) +{ + __asm__ __volatile__ ("putcfg %0, 0, r63\n" : : "r" (slot)); +} + +/* arch/sh64/mm/tlb.c */ +extern int sh64_tlb_init(void); +extern unsigned long long sh64_next_free_dtlb_entry(void); +extern unsigned long long sh64_get_wired_dtlb_entry(void); +extern int sh64_put_wired_dtlb_entry(unsigned long long entry); + +extern void sh64_setup_tlb_slot(unsigned long long config_addr, unsigned long eaddr, unsigned long asid, unsigned long paddr); +extern void sh64_teardown_tlb_slot(unsigned long long config_addr); + +#define tlb_start_vma(tlb, vma) \ + flush_cache_range(vma, vma->vm_start, vma->vm_end) + +#define tlb_end_vma(tlb, vma) \ + flush_tlb_range(vma, vma->vm_start, vma->vm_end) + +#define __tlb_remove_tlb_entry(tlb, pte, address) do { } while (0) + +/* + * Flush whole TLBs for MM + */ +#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm) + +#include + +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_SH64_TLB_H */ + diff -puN /dev/null include/asm-sh64/topology.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/topology.h 2004-06-28 13:30:30.769126224 -0700 @@ -0,0 +1,6 @@ +#ifndef __ASM_SH64_TOPOLOGY_H +#define __ASM_SH64_TOPOLOGY_H + +#include + +#endif /* __ASM_SH64_TOPOLOGY_H */ diff -puN /dev/null include/asm-sh64/types.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/types.h 2004-06-28 13:30:30.769126224 -0700 @@ -0,0 +1,76 @@ +#ifndef __ASM_SH64_TYPES_H +#define __ASM_SH64_TYPES_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. + * + * include/asm-sh64/types.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + */ + +#ifndef __ASSEMBLY__ + +typedef unsigned short umode_t; + +/* + * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the + * header files exported to user space + */ + +typedef __signed__ char __s8; +typedef unsigned char __u8; + +typedef __signed__ short __s16; +typedef unsigned short __u16; + +typedef __signed__ int __s32; +typedef unsigned int __u32; + +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) +typedef __signed__ long long __s64; +typedef unsigned long long __u64; +#endif + +#endif /* __ASSEMBLY__ */ + +/* + * These aren't exported outside the kernel to avoid name space clashes + */ +#ifdef __KERNEL__ + +#ifndef __ASSEMBLY__ + +typedef __signed__ char s8; +typedef unsigned char u8; + +typedef __signed__ short s16; +typedef unsigned short u16; + +typedef __signed__ int s32; +typedef unsigned int u32; + +typedef __signed__ long long s64; +typedef unsigned long long u64; + +/* DMA addresses come in generic and 64-bit flavours. */ + +#ifdef CONFIG_HIGHMEM64G +typedef u64 dma_addr_t; +#else +typedef u32 dma_addr_t; +#endif +typedef u64 dma64_addr_t; + +typedef unsigned int kmem_bufctl_t; + +#endif /* __ASSEMBLY__ */ + +#define BITS_PER_LONG 32 + +#endif /* __KERNEL__ */ + +#endif /* __ASM_SH64_TYPES_H */ diff -puN /dev/null include/asm-sh64/uaccess.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/uaccess.h 2004-06-28 13:30:30.771125920 -0700 @@ -0,0 +1,317 @@ +#ifndef __ASM_SH64_UACCESS_H +#define __ASM_SH64_UACCESS_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. + * + * include/asm-sh64/uaccess.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003, 2004 Paul Mundt + * + * User space memory access functions + * + * Copyright (C) 1999 Niibe Yutaka + * + * Based on: + * MIPS implementation version 1.15 by + * Copyright (C) 1996, 1997, 1998 by Ralf Baechle + * and i386 version. + * + */ + +#include +#include + +#define VERIFY_READ 0 +#define VERIFY_WRITE 1 + +/* + * 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 (Data Segment Register?), these macros are misnamed. + */ + +#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) + +#define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF) +#define USER_DS MAKE_MM_SEG(0x80000000) + +#define get_ds() (KERNEL_DS) +#define get_fs() (current_thread_info()->addr_limit) +#define set_fs(x) (current_thread_info()->addr_limit=(x)) + +#define segment_eq(a,b) ((a).seg == (b).seg) + +#define __addr_ok(addr) ((unsigned long)(addr) < (current_thread_info()->addr_limit.seg)) + +/* + * Uhhuh, this needs 33-bit arithmetic. We have a carry.. + * + * sum := addr + size; carry? --> flag = true; + * if (sum >= addr_limit) flag = true; + */ +#define __range_ok(addr,size) (((unsigned long) (addr) + (size) < (current_thread_info()->addr_limit.seg)) ? 0 : 1) + +#define access_ok(type,addr,size) (__range_ok(addr,size) == 0) +#define __access_ok(addr,size) (__range_ok(addr,size) == 0) + +extern inline int verify_area(int type, const void __user * addr, unsigned long size) +{ + return access_ok(type,addr,size) ? 0 : -EFAULT; +} + +/* + * Uh, these should become the main single-value transfer routines ... + * They automatically use the right size if we just have the right + * pointer type ... + * + * As MIPS uses the same address space for kernel and user data, we + * can just do these as direct assignments. + * + * Careful to not + * (a) re-use the arguments for side effects (sizeof is ok) + * (b) require any knowledge of processes at this stage + */ +#define put_user(x,ptr) __put_user_check((x),(ptr),sizeof(*(ptr))) +#define get_user(x,ptr) __get_user_check((x),(ptr),sizeof(*(ptr))) + +/* + * The "__xxx" versions do not do address space checking, useful when + * doing multiple accesses to the same area (the user has to do the + * checks by hand with "access_ok()") + */ +#define __put_user(x,ptr) __put_user_nocheck((x),(ptr),sizeof(*(ptr))) +#define __get_user(x,ptr) __get_user_nocheck((x),(ptr),sizeof(*(ptr))) + +/* + * The "xxx_ret" versions return constant specified in third argument, if + * something bad happens. These macros can be optimized for the + * case of just returning from the function xxx_ret is used. + */ + +#define put_user_ret(x,ptr,ret) ({ \ +if (put_user(x,ptr)) return ret; }) + +#define get_user_ret(x,ptr,ret) ({ \ +if (get_user(x,ptr)) return ret; }) + +#define __put_user_ret(x,ptr,ret) ({ \ +if (__put_user(x,ptr)) return ret; }) + +#define __get_user_ret(x,ptr,ret) ({ \ +if (__get_user(x,ptr)) return ret; }) + +struct __large_struct { unsigned long buf[100]; }; +#define __m(x) (*(struct __large_struct *)(x)) + +#define __get_user_size(x,ptr,size,retval) \ +do { \ + retval = 0; \ + switch (size) { \ + case 1: \ + retval = __get_user_asm_b(x, ptr); \ + break; \ + case 2: \ + retval = __get_user_asm_w(x, ptr); \ + break; \ + case 4: \ + retval = __get_user_asm_l(x, ptr); \ + break; \ + case 8: \ + retval = __get_user_asm_q(x, ptr); \ + break; \ + default: \ + __get_user_unknown(); \ + break; \ + } \ +} while (0) + +#define __get_user_nocheck(x,ptr,size) \ +({ \ + long __gu_addr = (long)(ptr); \ + long __gu_err; \ + __typeof(*(ptr)) __gu_val; \ + __asm__ ("":"=r" (__gu_val)); \ + __asm__ ("":"=r" (__gu_err)); \ + __get_user_size((void *)&__gu_val, __gu_addr, (size), __gu_err); \ + (x) = (__typeof__(*(ptr))) __gu_val; \ + __gu_err; \ +}) + +#define __get_user_check(x,ptr,size) \ +({ \ + long __gu_addr = (long)(ptr); \ + long __gu_err = -EFAULT; \ + __typeof(*(ptr)) __gu_val; \ + __asm__ ("":"=r" (__gu_val)); \ + __asm__ ("":"=r" (__gu_err)); \ + if (__access_ok(__gu_addr, (size))) \ + __get_user_size((void *)&__gu_val, __gu_addr, (size), __gu_err); \ + (x) = (__typeof__(*(ptr))) __gu_val; \ + __gu_err; \ +}) + +extern long __get_user_asm_b(void *, long); +extern long __get_user_asm_w(void *, long); +extern long __get_user_asm_l(void *, long); +extern long __get_user_asm_q(void *, long); +extern void __get_user_unknown(void); + +#define __put_user_size(x,ptr,size,retval) \ +do { \ + retval = 0; \ + switch (size) { \ + case 1: \ + retval = __put_user_asm_b(x, ptr); \ + break; \ + case 2: \ + retval = __put_user_asm_w(x, ptr); \ + break; \ + case 4: \ + retval = __put_user_asm_l(x, ptr); \ + break; \ + case 8: \ + retval = __put_user_asm_q(x, ptr); \ + break; \ + default: \ + __put_user_unknown(); \ + } \ +} while (0) + +#define __put_user_nocheck(x,ptr,size) \ +({ \ + long __pu_err; \ + __typeof__(*(ptr)) __pu_val = (x); \ + __put_user_size((void *)&__pu_val, (long)(ptr), (size), __pu_err); \ + __pu_err; \ +}) + +#define __put_user_check(x,ptr,size) \ +({ \ + long __pu_err = -EFAULT; \ + long __pu_addr = (long)(ptr); \ + __typeof__(*(ptr)) __pu_val = (x); \ + \ + if (__access_ok(__pu_addr, (size))) \ + __put_user_size((void *)&__pu_val, __pu_addr, (size), __pu_err);\ + __pu_err; \ +}) + +extern long __put_user_asm_b(void *, long); +extern long __put_user_asm_w(void *, long); +extern long __put_user_asm_l(void *, long); +extern long __put_user_asm_q(void *, long); +extern void __put_user_unknown(void); + + +/* Generic arbitrary sized copy. */ +/* Return the number of bytes NOT copied */ +/* XXX: should be such that: 4byte and the rest. */ +extern __kernel_size_t __copy_user(void *__to, const void *__from, __kernel_size_t __n); + +#define copy_to_user(to,from,n) ({ \ +void *__copy_to = (void *) (to); \ +__kernel_size_t __copy_size = (__kernel_size_t) (n); \ +__kernel_size_t __copy_res; \ +if(__copy_size && __access_ok((unsigned long)__copy_to, __copy_size)) { \ +__copy_res = __copy_user(__copy_to, (void *) (from), __copy_size); \ +} else __copy_res = __copy_size; \ +__copy_res; }) + +#define copy_to_user_ret(to,from,n,retval) ({ \ +if (copy_to_user(to,from,n)) \ + return retval; \ +}) + +#define __copy_to_user(to,from,n) \ + __copy_user((void *)(to), \ + (void *)(from), n) + +#define __copy_to_user_ret(to,from,n,retval) ({ \ +if (__copy_to_user(to,from,n)) \ + return retval; \ +}) + +#define copy_from_user(to,from,n) ({ \ +void *__copy_to = (void *) (to); \ +void *__copy_from = (void *) (from); \ +__kernel_size_t __copy_size = (__kernel_size_t) (n); \ +__kernel_size_t __copy_res; \ +if(__copy_size && __access_ok((unsigned long)__copy_from, __copy_size)) { \ +__copy_res = __copy_user(__copy_to, __copy_from, __copy_size); \ +} else __copy_res = __copy_size; \ +__copy_res; }) + +#define copy_from_user_ret(to,from,n,retval) ({ \ +if (copy_from_user(to,from,n)) \ + return retval; \ +}) + +#define __copy_from_user(to,from,n) \ + __copy_user((void *)(to), \ + (void *)(from), n) + +#define __copy_from_user_ret(to,from,n,retval) ({ \ +if (__copy_from_user(to,from,n)) \ + return retval; \ +}) + +/* XXX: Not sure it works well.. + should be such that: 4byte clear and the rest. */ +extern __kernel_size_t __clear_user(void *addr, __kernel_size_t size); + +#define clear_user(addr,n) ({ \ +void * __cl_addr = (addr); \ +unsigned long __cl_size = (n); \ +if (__cl_size && __access_ok(((unsigned long)(__cl_addr)), __cl_size)) \ +__cl_size = __clear_user(__cl_addr, __cl_size); \ +__cl_size; }) + +extern int __strncpy_from_user(unsigned long __dest, unsigned long __src, int __count); + +#define strncpy_from_user(dest,src,count) ({ \ +unsigned long __sfu_src = (unsigned long) (src); \ +int __sfu_count = (int) (count); \ +long __sfu_res = -EFAULT; \ +if(__access_ok(__sfu_src, __sfu_count)) { \ +__sfu_res = __strncpy_from_user((unsigned long) (dest), __sfu_src, __sfu_count); \ +} __sfu_res; }) + +#define strlen_user(str) strnlen_user(str, ~0UL >> 1) + +/* + * Return the size of a string (including the ending 0!) + */ +extern long __strnlen_user(const char *__s, long __n); + +extern __inline__ long strnlen_user(const char *s, long n) +{ + if (!__addr_ok(s)) + return 0; + else + return __strnlen_user(s, n); +} + +struct exception_table_entry +{ + unsigned long insn, fixup; +}; + +#define ARCH_HAS_SEARCH_EXTABLE + +/* If gcc inlines memset, it will use st.q instructions. Therefore, we need + kmalloc allocations to be 8-byte aligned. Without this, the alignment + becomes BYTE_PER_WORD i.e. only 4 (since sizeof(long)==sizeof(void*)==4 on + sh64 at the moment). */ +#define ARCH_KMALLOC_MINALIGN 8 + +/* Returns 0 if exception not found and fixup.unit otherwise. */ +extern unsigned long search_exception_table(unsigned long addr); +extern const struct exception_table_entry *search_exception_tables (unsigned long addr); + +#endif /* __ASM_SH64_UACCESS_H */ diff -puN /dev/null include/asm-sh64/ucontext.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/ucontext.h 2004-06-28 13:30:30.771125920 -0700 @@ -0,0 +1,23 @@ +#ifndef __ASM_SH64_UCONTEXT_H +#define __ASM_SH64_UCONTEXT_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. + * + * include/asm-sh64/ucontext.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + */ + +struct ucontext { + unsigned long uc_flags; + struct ucontext *uc_link; + stack_t uc_stack; + struct sigcontext uc_mcontext; + sigset_t uc_sigmask; /* mask last for extensibility */ +}; + +#endif /* __ASM_SH64_UCONTEXT_H */ diff -puN /dev/null include/asm-sh64/unaligned.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/unaligned.h 2004-06-28 13:30:30.772125768 -0700 @@ -0,0 +1,28 @@ +#ifndef __ASM_SH64_UNALIGNED_H +#define __ASM_SH64_UNALIGNED_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. + * + * include/asm-sh64/unaligned.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + */ + +#include + + +/* Use memmove here, so gcc does not insert a __builtin_memcpy. */ + +#define get_unaligned(ptr) \ + ({ __typeof__(*(ptr)) __tmp; memmove(&__tmp, (ptr), sizeof(*(ptr))); __tmp; }) + +#define put_unaligned(val, ptr) \ + ({ __typeof__(*(ptr)) __tmp = (val); \ + memmove((ptr), &__tmp, sizeof(*(ptr))); \ + (void)0; }) + +#endif /* __ASM_SH64_UNALIGNED_H */ diff -puN /dev/null include/asm-sh64/unistd.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/unistd.h 2004-06-28 13:30:30.775125312 -0700 @@ -0,0 +1,555 @@ +#ifndef __ASM_SH64_UNISTD_H +#define __ASM_SH64_UNISTD_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. + * + * include/asm-sh64/unistd.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003 Paul Mundt + * Copyright (C) 2004 Sean McGoogan + * + * This file contains the system call numbers. + * + */ + +#define __NR_setup 0 /* used only by init, to get system going */ +#define __NR_exit 1 +#define __NR_fork 2 +#define __NR_read 3 +#define __NR_write 4 +#define __NR_open 5 +#define __NR_close 6 +#define __NR_waitpid 7 +#define __NR_creat 8 +#define __NR_link 9 +#define __NR_unlink 10 +#define __NR_execve 11 +#define __NR_chdir 12 +#define __NR_time 13 +#define __NR_mknod 14 +#define __NR_chmod 15 +#define __NR_lchown 16 +#define __NR_break 17 +#define __NR_oldstat 18 +#define __NR_lseek 19 +#define __NR_getpid 20 +#define __NR_mount 21 +#define __NR_umount 22 +#define __NR_setuid 23 +#define __NR_getuid 24 +#define __NR_stime 25 +#define __NR_ptrace 26 +#define __NR_alarm 27 +#define __NR_oldfstat 28 +#define __NR_pause 29 +#define __NR_utime 30 +#define __NR_stty 31 +#define __NR_gtty 32 +#define __NR_access 33 +#define __NR_nice 34 +#define __NR_ftime 35 +#define __NR_sync 36 +#define __NR_kill 37 +#define __NR_rename 38 +#define __NR_mkdir 39 +#define __NR_rmdir 40 +#define __NR_dup 41 +#define __NR_pipe 42 +#define __NR_times 43 +#define __NR_prof 44 +#define __NR_brk 45 +#define __NR_setgid 46 +#define __NR_getgid 47 +#define __NR_signal 48 +#define __NR_geteuid 49 +#define __NR_getegid 50 +#define __NR_acct 51 +#define __NR_umount2 52 +#define __NR_lock 53 +#define __NR_ioctl 54 +#define __NR_fcntl 55 +#define __NR_mpx 56 +#define __NR_setpgid 57 +#define __NR_ulimit 58 +#define __NR_oldolduname 59 +#define __NR_umask 60 +#define __NR_chroot 61 +#define __NR_ustat 62 +#define __NR_dup2 63 +#define __NR_getppid 64 +#define __NR_getpgrp 65 +#define __NR_setsid 66 +#define __NR_sigaction 67 +#define __NR_sgetmask 68 +#define __NR_ssetmask 69 +#define __NR_setreuid 70 +#define __NR_setregid 71 +#define __NR_sigsuspend 72 +#define __NR_sigpending 73 +#define __NR_sethostname 74 +#define __NR_setrlimit 75 +#define __NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */ +#define __NR_getrusage 77 +#define __NR_gettimeofday 78 +#define __NR_settimeofday 79 +#define __NR_getgroups 80 +#define __NR_setgroups 81 +#define __NR_select 82 +#define __NR_symlink 83 +#define __NR_oldlstat 84 +#define __NR_readlink 85 +#define __NR_uselib 86 +#define __NR_swapon 87 +#define __NR_reboot 88 +#define __NR_readdir 89 +#define __NR_mmap 90 +#define __NR_munmap 91 +#define __NR_truncate 92 +#define __NR_ftruncate 93 +#define __NR_fchmod 94 +#define __NR_fchown 95 +#define __NR_getpriority 96 +#define __NR_setpriority 97 +#define __NR_profil 98 +#define __NR_statfs 99 +#define __NR_fstatfs 100 +#define __NR_ioperm 101 +#define __NR_socketcall 102 /* old implementation of socket systemcall */ +#define __NR_syslog 103 +#define __NR_setitimer 104 +#define __NR_getitimer 105 +#define __NR_stat 106 +#define __NR_lstat 107 +#define __NR_fstat 108 +#define __NR_olduname 109 +#define __NR_iopl 110 +#define __NR_vhangup 111 +#define __NR_idle 112 +#define __NR_vm86old 113 +#define __NR_wait4 114 +#define __NR_swapoff 115 +#define __NR_sysinfo 116 +#define __NR_ipc 117 +#define __NR_fsync 118 +#define __NR_sigreturn 119 +#define __NR_clone 120 +#define __NR_setdomainname 121 +#define __NR_uname 122 +#define __NR_modify_ldt 123 +#define __NR_adjtimex 124 +#define __NR_mprotect 125 +#define __NR_sigprocmask 126 +#define __NR_create_module 127 +#define __NR_init_module 128 +#define __NR_delete_module 129 +#define __NR_get_kernel_syms 130 +#define __NR_quotactl 131 +#define __NR_getpgid 132 +#define __NR_fchdir 133 +#define __NR_bdflush 134 +#define __NR_sysfs 135 +#define __NR_personality 136 +#define __NR_afs_syscall 137 /* Syscall for Andrew File System */ +#define __NR_setfsuid 138 +#define __NR_setfsgid 139 +#define __NR__llseek 140 +#define __NR_getdents 141 +#define __NR__newselect 142 +#define __NR_flock 143 +#define __NR_msync 144 +#define __NR_readv 145 +#define __NR_writev 146 +#define __NR_getsid 147 +#define __NR_fdatasync 148 +#define __NR__sysctl 149 +#define __NR_mlock 150 +#define __NR_munlock 151 +#define __NR_mlockall 152 +#define __NR_munlockall 153 +#define __NR_sched_setparam 154 +#define __NR_sched_getparam 155 +#define __NR_sched_setscheduler 156 +#define __NR_sched_getscheduler 157 +#define __NR_sched_yield 158 +#define __NR_sched_get_priority_max 159 +#define __NR_sched_get_priority_min 160 +#define __NR_sched_rr_get_interval 161 +#define __NR_nanosleep 162 +#define __NR_mremap 163 +#define __NR_setresuid 164 +#define __NR_getresuid 165 +#define __NR_vm86 166 +#define __NR_query_module 167 +#define __NR_poll 168 +#define __NR_nfsservctl 169 +#define __NR_setresgid 170 +#define __NR_getresgid 171 +#define __NR_prctl 172 +#define __NR_rt_sigreturn 173 +#define __NR_rt_sigaction 174 +#define __NR_rt_sigprocmask 175 +#define __NR_rt_sigpending 176 +#define __NR_rt_sigtimedwait 177 +#define __NR_rt_sigqueueinfo 178 +#define __NR_rt_sigsuspend 179 +#define __NR_pread 180 +#define __NR_pwrite 181 +#define __NR_chown 182 +#define __NR_getcwd 183 +#define __NR_capget 184 +#define __NR_capset 185 +#define __NR_sigaltstack 186 +#define __NR_sendfile 187 +#define __NR_streams1 188 /* some people actually want it */ +#define __NR_streams2 189 /* some people actually want it */ +#define __NR_vfork 190 +#define __NR_ugetrlimit 191 /* SuS compliant getrlimit */ +#define __NR_mmap2 192 +#define __NR_truncate64 193 +#define __NR_ftruncate64 194 +#define __NR_stat64 195 +#define __NR_lstat64 196 +#define __NR_fstat64 197 +#define __NR_lchown32 198 +#define __NR_getuid32 199 +#define __NR_getgid32 200 +#define __NR_geteuid32 201 +#define __NR_getegid32 202 +#define __NR_setreuid32 203 +#define __NR_setregid32 204 +#define __NR_getgroups32 205 +#define __NR_setgroups32 206 +#define __NR_fchown32 207 +#define __NR_setresuid32 208 +#define __NR_getresuid32 209 +#define __NR_setresgid32 210 +#define __NR_getresgid32 211 +#define __NR_chown32 212 +#define __NR_setuid32 213 +#define __NR_setgid32 214 +#define __NR_setfsuid32 215 +#define __NR_setfsgid32 216 +#define __NR_pivot_root 217 +#define __NR_mincore 218 +#define __NR_madvise 219 + +/* Non-multiplexed socket family */ +#define __NR_socket 220 +#define __NR_bind 221 +#define __NR_connect 222 +#define __NR_listen 223 +#define __NR_accept 224 +#define __NR_getsockname 225 +#define __NR_getpeername 226 +#define __NR_socketpair 227 +#define __NR_send 228 +#define __NR_sendto 229 +#define __NR_recv 230 +#define __NR_recvfrom 231 +#define __NR_shutdown 232 +#define __NR_setsockopt 233 +#define __NR_getsockopt 234 +#define __NR_sendmsg 235 +#define __NR_recvmsg 236 + +/* Non-multiplexed IPC family */ +#define __NR_semop 237 +#define __NR_semget 238 +#define __NR_semctl 239 +#define __NR_msgsnd 240 +#define __NR_msgrcv 241 +#define __NR_msgget 242 +#define __NR_msgctl 243 +#if 0 +#define __NR_shmatcall 244 +#endif +#define __NR_shmdt 245 +#define __NR_shmget 246 +#define __NR_shmctl 247 + +#define __NR_getdents64 248 +#define __NR_fcntl64 249 +/* 223 is unused */ +#define __NR_gettid 252 +#define __NR_readahead 253 +#define __NR_setxattr 254 +#define __NR_lsetxattr 255 +#define __NR_fsetxattr 256 +#define __NR_getxattr 257 +#define __NR_lgetxattr 258 +#define __NR_fgetxattr 269 +#define __NR_listxattr 260 +#define __NR_llistxattr 261 +#define __NR_flistxattr 262 +#define __NR_removexattr 263 +#define __NR_lremovexattr 264 +#define __NR_fremovexattr 265 +#define __NR_tkill 266 +#define __NR_sendfile64 267 +#define __NR_futex 268 +#define __NR_sched_setaffinity 269 +#define __NR_sched_getaffinity 270 +#define __NR_set_thread_area 271 +#define __NR_get_thread_area 272 +#define __NR_io_setup 273 +#define __NR_io_destroy 274 +#define __NR_io_getevents 275 +#define __NR_io_submit 276 +#define __NR_io_cancel 277 +#define __NR_fadvise64 278 +#define __NR_exit_group 280 + +#define __NR_lookup_dcookie 281 +#define __NR_epoll_create 282 +#define __NR_epoll_ctl 283 +#define __NR_epoll_wait 284 +#define __NR_remap_file_pages 285 +#define __NR_set_tid_address 286 +#define __NR_timer_create 287 +#define __NR_timer_settime (__NR_timer_create+1) +#define __NR_timer_gettime (__NR_timer_create+2) +#define __NR_timer_getoverrun (__NR_timer_create+3) +#define __NR_timer_delete (__NR_timer_create+4) +#define __NR_clock_settime (__NR_timer_create+5) +#define __NR_clock_gettime (__NR_timer_create+6) +#define __NR_clock_getres (__NR_timer_create+7) +#define __NR_clock_nanosleep (__NR_timer_create+8) +#define __NR_statfs64 296 +#define __NR_fstatfs64 297 +#define __NR_tgkill 298 +#define __NR_utimes 299 +#define __NR_fadvise64_64 300 +#define __NR_vserver 301 +#define __NR_mbind 302 +#define __NR_get_mempolicy 303 +#define __NR_set_mempolicy 304 +#define __NR_mq_open 305 +#define __NR_mq_unlink (__NR_mq_open+1) +#define __NR_mq_timedsend (__NR_mq_open+2) +#define __NR_mq_timedreceive (__NR_mq_open+3) +#define __NR_mq_notify (__NR_mq_open+4) +#define __NR_mq_getsetattr (__NR_mq_open+5) + +#define NR_syscalls 311 + +/* user-visible error numbers are in the range -1 - -125: see */ + +#define __syscall_return(type, res) \ +do { \ + /* Note: when returning from kernel the return value is in r9 \ + ** This prevents conflicts between return value and arg1 \ + ** when dispatching signal handler, in other words makes \ + ** life easier in the system call epilogue (see entry.S) \ + */ \ + register unsigned long __sr2 __asm__ ("r2") = res; \ + if ((unsigned long)(res) >= (unsigned long)(-125)) { \ + errno = -(res); \ + __sr2 = -1; \ + } \ + return (type) (__sr2); \ +} while (0) + +/* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */ + +#define _syscall0(type,name) \ +type name(void) \ +{ \ +register unsigned long __sc0 __asm__ ("r9") = ((0x10 << 16) | __NR_##name); \ +__asm__ __volatile__ ("trapa %1 !\t\t\t" #name "()" \ + : "=r" (__sc0) \ + : "r" (__sc0) ); \ +__syscall_return(type,__sc0); \ +} + + /* + * The apparent spurious "dummy" assembler comment is *needed*, + * as without it, the compiler treats the arg variables + * as no longer live just before the asm. The compiler can + * then optimize the storage into any registers it wishes. + * The additional dummy statement forces the compiler to put + * the arguments into the correct registers before the TRAPA. + */ +#define _syscall1(type,name,type1,arg1) \ +type name(type1 arg1) \ +{ \ +register unsigned long __sc0 __asm__ ("r9") = ((0x11 << 16) | __NR_##name); \ +register unsigned long __sc2 __asm__ ("r2") = (unsigned long) arg1; \ +__asm__ __volatile__ ("trapa %1 !\t\t\t" #name "(%2)" \ + : "=r" (__sc0) \ + : "r" (__sc0), "r" (__sc2)); \ +__asm__ __volatile__ ("!dummy %0 %1" \ + : \ + : "r" (__sc0), "r" (__sc2)); \ +__syscall_return(type,__sc0); \ +} + +#define _syscall2(type,name,type1,arg1,type2,arg2) \ +type name(type1 arg1,type2 arg2) \ +{ \ +register unsigned long __sc0 __asm__ ("r9") = ((0x12 << 16) | __NR_##name); \ +register unsigned long __sc2 __asm__ ("r2") = (unsigned long) arg1; \ +register unsigned long __sc3 __asm__ ("r3") = (unsigned long) arg2; \ +__asm__ __volatile__ ("trapa %1 !\t\t\t" #name "(%2,%3)" \ + : "=r" (__sc0) \ + : "r" (__sc0), "r" (__sc2), "r" (__sc3) ); \ +__asm__ __volatile__ ("!dummy %0 %1 %2" \ + : \ + : "r" (__sc0), "r" (__sc2), "r" (__sc3) ); \ +__syscall_return(type,__sc0); \ +} + +#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ +type name(type1 arg1,type2 arg2,type3 arg3) \ +{ \ +register unsigned long __sc0 __asm__ ("r9") = ((0x13 << 16) | __NR_##name); \ +register unsigned long __sc2 __asm__ ("r2") = (unsigned long) arg1; \ +register unsigned long __sc3 __asm__ ("r3") = (unsigned long) arg2; \ +register unsigned long __sc4 __asm__ ("r4") = (unsigned long) arg3; \ +__asm__ __volatile__ ("trapa %1 !\t\t\t" #name "(%2,%3,%4)" \ + : "=r" (__sc0) \ + : "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4) ); \ +__asm__ __volatile__ ("!dummy %0 %1 %2 %3" \ + : \ + : "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4) ); \ +__syscall_return(type,__sc0); \ +} + +#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ +type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \ +{ \ +register unsigned long __sc0 __asm__ ("r9") = ((0x14 << 16) | __NR_##name); \ +register unsigned long __sc2 __asm__ ("r2") = (unsigned long) arg1; \ +register unsigned long __sc3 __asm__ ("r3") = (unsigned long) arg2; \ +register unsigned long __sc4 __asm__ ("r4") = (unsigned long) arg3; \ +register unsigned long __sc5 __asm__ ("r5") = (unsigned long) arg4; \ +__asm__ __volatile__ ("trapa %1 !\t\t\t" #name "(%2,%3,%4,%5)" \ + : "=r" (__sc0) \ + : "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4), "r" (__sc5) );\ +__asm__ __volatile__ ("!dummy %0 %1 %2 %3 %4" \ + : \ + : "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4), "r" (__sc5) );\ +__syscall_return(type,__sc0); \ +} + +#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \ +type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \ +{ \ +register unsigned long __sc0 __asm__ ("r9") = ((0x15 << 16) | __NR_##name); \ +register unsigned long __sc2 __asm__ ("r2") = (unsigned long) arg1; \ +register unsigned long __sc3 __asm__ ("r3") = (unsigned long) arg2; \ +register unsigned long __sc4 __asm__ ("r4") = (unsigned long) arg3; \ +register unsigned long __sc5 __asm__ ("r5") = (unsigned long) arg4; \ +register unsigned long __sc6 __asm__ ("r6") = (unsigned long) arg5; \ +__asm__ __volatile__ ("trapa %1 !\t\t\t" #name "(%2,%3,%4,%5,%6)" \ + : "=r" (__sc0) \ + : "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4), "r" (__sc5), \ + "r" (__sc6)); \ +__asm__ __volatile__ ("!dummy %0 %1 %2 %3 %4 %5" \ + : \ + : "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4), "r" (__sc5), \ + "r" (__sc6)); \ +__syscall_return(type,__sc0); \ +} + +#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5, type6, arg6) \ +type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6) \ +{ \ +register unsigned long __sc0 __asm__ ("r9") = ((0x16 << 16) | __NR_##name); \ +register unsigned long __sc2 __asm__ ("r2") = (unsigned long) arg1; \ +register unsigned long __sc3 __asm__ ("r3") = (unsigned long) arg2; \ +register unsigned long __sc4 __asm__ ("r4") = (unsigned long) arg3; \ +register unsigned long __sc5 __asm__ ("r5") = (unsigned long) arg4; \ +register unsigned long __sc6 __asm__ ("r6") = (unsigned long) arg5; \ +register unsigned long __sc7 __asm__ ("r7") = (unsigned long) arg6; \ +__asm__ __volatile__ ("trapa %1 !\t\t\t" #name "(%2,%3,%4,%5,%6,%7)" \ + : "=r" (__sc0) \ + : "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4), "r" (__sc5), \ + "r" (__sc6), "r" (__sc7)); \ +__asm__ __volatile__ ("!dummy %0 %1 %2 %3 %4 %5 %6" \ + : \ + : "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4), "r" (__sc5), \ + "r" (__sc6), "r" (__sc7)); \ +__syscall_return(type,__sc0); \ +} + +#ifdef __KERNEL__ +#define __ARCH_WANT_IPC_PARSE_VERSION +#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_SGETMASK +#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_RT_SIGACTION +#endif + +#ifdef __KERNEL_SYSCALLS__ + +/* Copy from sh */ +#include +#include +#include + +/* + * we need this inline - forking from kernel space will result + * in NO COPY ON WRITE (!!!), until an execve is executed. This + * is no problem, but for the stack. This is handled by not letting + * main() use the stack at all after fork(). Thus, no function + * calls - which means inline code for fork too, as otherwise we + * would use the stack upon exit from 'fork()'. + * + * Actually only pause and fork are needed inline, so that there + * won't be any messing with the stack from main(), but we define + * some others too. + */ +#define __NR__exit __NR_exit +static inline _syscall0(int,pause) +static inline _syscall1(int,setup,int,magic) +static inline _syscall0(int,sync) +static inline _syscall0(pid_t,setsid) +static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count) +static inline _syscall3(int,read,int,fd,char *,buf,off_t,count) +static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count) +static inline _syscall1(int,dup,int,fd) +static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) +static inline _syscall3(int,open,const char *,file,int,flag,int,mode) +static inline _syscall1(int,close,int,fd) +static inline _syscall1(int,_exit,int,exitcode) +static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) +static inline _syscall1(int,delete_module,const char *,name) + +static inline pid_t wait(int * wait_stat) +{ + return waitpid(-1,wait_stat,0); +} +#endif + +/* + * "Conditional" syscalls + * + * What we want is __attribute__((weak,alias("sys_ni_syscall"))), + * but it doesn't work on all toolchains, so we just do it by hand + */ +#ifndef cond_syscall +#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall"); +#endif + +#endif /* __ASM_SH64_UNISTD_H */ diff -puN /dev/null include/asm-sh64/user.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/asm-sh64/user.h 2004-06-28 13:30:30.776125160 -0700 @@ -0,0 +1,71 @@ +#ifndef __ASM_SH64_USER_H +#define __ASM_SH64_USER_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. + * + * include/asm-sh64/user.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * + */ + +#include +#include +#include +#include + +/* + * Core file format: The core file is written in such a way that gdb + * can understand it and provide useful information to the user (under + * linux we use the `trad-core' bfd). The file contents are as follows: + * + * upage: 1 page consisting of a user struct that tells gdb + * what is present in the file. Directly after this is a + * copy of the task_struct, which is currently not used by gdb, + * but it may come in handy at some point. All of the registers + * are stored as part of the upage. The upage should always be + * only one page long. + * data: The data segment follows next. We use current->end_text to + * current->brk to pick up all of the user variables, plus any memory + * that may have been sbrk'ed. No attempt is made to determine if a + * page is demand-zero or if a page is totally unused, we just cover + * the entire range. All of the addresses are rounded in such a way + * that an integral number of pages is written. + * stack: We need the stack information in order to get a meaningful + * backtrace. We need to write the data from usp to + * current->start_stack, so we round each of these in order to be able + * to write an integer number of pages. + */ + +struct user_fpu_struct { + unsigned long long fp_regs[32]; + unsigned int fpscr; +}; + +struct user { + struct pt_regs regs; /* entire machine state */ + struct user_fpu_struct fpu; /* Math Co-processor registers */ + int u_fpvalid; /* True if math co-processor being used */ + size_t u_tsize; /* text size (pages) */ + size_t u_dsize; /* data size (pages) */ + size_t u_ssize; /* stack size (pages) */ + unsigned long start_code; /* text starting address */ + unsigned long start_data; /* data starting address */ + unsigned long start_stack; /* stack starting address */ + long int signal; /* signal causing core dump */ + struct regs * u_ar0; /* help gdb find registers */ + struct user_fpu_struct* u_fpstate; /* Math Co-processor pointer */ + unsigned long magic; /* identifies a core file */ + char u_comm[32]; /* user command name */ +}; + +#define NBPG PAGE_SIZE +#define UPAGES 1 +#define HOST_TEXT_START_ADDR (u.start_code) +#define HOST_DATA_START_ADDR (u.start_data) +#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG) + +#endif /* __ASM_SH64_USER_H */ diff -puN include/linux/fb.h~sh64-merge include/linux/fb.h --- 25/include/linux/fb.h~sh64-merge 2004-06-28 13:30:30.624148264 -0700 +++ 25-akpm/include/linux/fb.h 2004-06-28 13:30:30.776125160 -0700 @@ -593,7 +593,7 @@ struct fb_info { #define fb_writeq sbus_writeq #define fb_memset sbus_memset_io -#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || defined(__hppa__) || defined(__sh__) || defined(__powerpc__) +#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || defined(__hppa__) || (defined(__sh__) && !defined(__SH5__)) || defined(__powerpc__) #define fb_readb __raw_readb #define fb_readw __raw_readw _