diff options
Diffstat (limited to 'arch/xtensa')
200 files changed, 27133 insertions, 0 deletions
diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig new file mode 100644 index 00000000..8a3f8351 --- /dev/null +++ b/arch/xtensa/Kconfig @@ -0,0 +1,250 @@ +config FRAME_POINTER + def_bool n + +config ZONE_DMA + def_bool y + +config XTENSA + def_bool y + select HAVE_IDE + select HAVE_GENERIC_HARDIRQS + select GENERIC_IRQ_SHOW + select GENERIC_CPU_DEVICES + help + Xtensa processors are 32-bit RISC machines designed by Tensilica + primarily for embedded systems. These processors are both + configurable and extensible. The Linux port to the Xtensa + architecture supports all processor configurations and extensions, + with reasonable minimum requirements. The Xtensa Linux project has + a home page at <http://xtensa.sourceforge.net/>. + +config RWSEM_XCHGADD_ALGORITHM + def_bool y + +config GENERIC_HWEIGHT + def_bool y + +config GENERIC_GPIO + def_bool y + +config ARCH_HAS_ILOG2_U32 + def_bool n + +config ARCH_HAS_ILOG2_U64 + def_bool n + +config NO_IOPORT + def_bool y + +config HZ + int + default 100 + +source "init/Kconfig" +source "kernel/Kconfig.freezer" + +config MMU + def_bool n + +config VARIANT_IRQ_SWITCH + def_bool n + +menu "Processor type and features" + +choice + prompt "Xtensa Processor Configuration" + default XTENSA_VARIANT_FSF + +config XTENSA_VARIANT_FSF + bool "fsf - default (not generic) configuration" + select MMU + +config XTENSA_VARIANT_DC232B + bool "dc232b - Diamond 232L Standard Core Rev.B (LE)" + select MMU + help + This variant refers to Tensilica's Diamond 232L Standard core Rev.B (LE). + +config XTENSA_VARIANT_S6000 + bool "s6000 - Stretch software configurable processor" + select VARIANT_IRQ_SWITCH + select ARCH_REQUIRE_GPIOLIB + select XTENSA_CALIBRATE_CCOUNT +endchoice + +config XTENSA_UNALIGNED_USER + bool "Unaligned memory access in use space" + help + The Xtensa architecture currently does not handle unaligned + memory accesses in hardware but through an exception handler. + Per default, unaligned memory accesses are disabled in user space. + + Say Y here to enable unaligned memory access in user space. + +source "kernel/Kconfig.preempt" + +config MATH_EMULATION + bool "Math emulation" + help + Can we use information of configuration file? + +endmenu + +config XTENSA_CALIBRATE_CCOUNT + def_bool n + help + On some platforms (XT2000, for example), the CPU clock rate can + vary. The frequency can be determined, however, by measuring + against a well known, fixed frequency, such as an UART oscillator. + +config SERIAL_CONSOLE + def_bool n + +config XTENSA_ISS_NETWORK + def_bool n + +menu "Bus options" + +config PCI + bool "PCI support" + default y + 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. + +source "drivers/pci/Kconfig" + +endmenu + +menu "Platform options" + +choice + prompt "Xtensa System Type" + default XTENSA_PLATFORM_ISS + +config XTENSA_PLATFORM_ISS + bool "ISS" + select XTENSA_CALIBRATE_CCOUNT + select SERIAL_CONSOLE + select XTENSA_ISS_NETWORK + help + ISS is an acronym for Tensilica's Instruction Set Simulator. + +config XTENSA_PLATFORM_XT2000 + bool "XT2000" + help + XT2000 is the name of Tensilica's feature-rich emulation platform. + This hardware is capable of running a full Linux distribution. + +config XTENSA_PLATFORM_S6105 + bool "S6105" + select SERIAL_CONSOLE + +endchoice + + +config XTENSA_CPU_CLOCK + int "CPU clock rate [MHz]" + depends on !XTENSA_CALIBRATE_CCOUNT + default 16 + +config GENERIC_CALIBRATE_DELAY + bool "Auto calibration of the BogoMIPS value" + help + The BogoMIPS value can easily be derived from the CPU frequency. + +config CMDLINE_BOOL + bool "Default bootloader kernel arguments" + +config CMDLINE + string "Initial kernel command string" + depends on CMDLINE_BOOL + default "console=ttyS0,38400 root=/dev/ram" + help + On some architectures (EBSA110 and CATS), there is currently no way + for the boot loader to pass arguments to the kernel. For these + architectures, you should supply some command-line options at build + time by entering them here. As a minimum, you should specify the + memory size and the root device (e.g., mem=64M root=/dev/nfs). + +source "mm/Kconfig" + +config HOTPLUG + bool "Support for hot-pluggable devices" + help + Say Y here if you want to plug devices into your computer while + the system is running, and be able to use them quickly. In many + cases, the devices can likewise be unplugged at any time too. + + One well known example of this is PCMCIA- or PC-cards, credit-card + size devices such as network cards, modems or hard drives which are + plugged into slots found on all modern laptop computers. Another + example, used on modern desktops as well as laptops, is USB. + + Enable HOTPLUG and build a modular kernel. Get agent software + (from <http://linux-hotplug.sourceforge.net/>) and install it. + Then your kernel will automatically call out to a user mode "policy + agent" (/sbin/hotplug) to load modules and set up software needed + to use devices as you hotplug them. + +source "drivers/pcmcia/Kconfig" + +source "drivers/pci/hotplug/Kconfig" + +endmenu + +menu "Executable file formats" + +# only elf supported +config KCORE_ELF + def_bool y + depends on PROC_FS + help + If you enabled support for /proc file system then the file + /proc/kcore will contain the kernel core image in ELF format. This + can be used in gdb: + + $ cd /usr/src/linux ; gdb vmlinux /proc/kcore + + This is especially useful if you have compiled the kernel with the + "-g" option to preserve debugging information. It is mainly used + for examining kernel data structures on the live kernel. + +source "fs/Kconfig.binfmt" + +endmenu + +source "net/Kconfig" + +source "drivers/Kconfig" + +source "fs/Kconfig" + +menu "Xtensa initrd options" + depends on BLK_DEV_INITRD + +config EMBEDDED_RAMDISK + bool "Embed root filesystem ramdisk into the kernel" + +config EMBEDDED_RAMDISK_IMAGE + string "Filename of gzipped ramdisk image" + depends on EMBEDDED_RAMDISK + default "ramdisk.gz" + help + This is the filename of the ramdisk image to be built into the + kernel. Relative pathnames are relative to arch/xtensa/boot/ramdisk/. + The ramdisk image is not part of the kernel distribution; you must + provide one yourself. +endmenu + +source "arch/xtensa/Kconfig.debug" + +source "security/Kconfig" + +source "crypto/Kconfig" + +source "lib/Kconfig" + + diff --git a/arch/xtensa/Kconfig.debug b/arch/xtensa/Kconfig.debug new file mode 100644 index 00000000..11c58529 --- /dev/null +++ b/arch/xtensa/Kconfig.debug @@ -0,0 +1,7 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +endmenu + + diff --git a/arch/xtensa/Makefile b/arch/xtensa/Makefile new file mode 100644 index 00000000..7608559d --- /dev/null +++ b/arch/xtensa/Makefile @@ -0,0 +1,96 @@ +# +# 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) 2001 - 2005 Tensilica Inc. +# +# 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 + +# Core configuration. +# (Use VAR=<xtensa_config> to use another default compiler.) + +variant-$(CONFIG_XTENSA_VARIANT_FSF) := fsf +variant-$(CONFIG_XTENSA_VARIANT_DC232B) := dc232b +variant-$(CONFIG_XTENSA_VARIANT_S6000) := s6000 +variant-$(CONFIG_XTENSA_VARIANT_LINUX_CUSTOM) := custom + +VARIANT = $(variant-y) +export VARIANT + +# Platform configuration + +platform-$(CONFIG_XTENSA_PLATFORM_XT2000) := xt2000 +platform-$(CONFIG_XTENSA_PLATFORM_ISS) := iss +platform-$(CONFIG_XTENSA_PLATFORM_S6105) := s6105 + +PLATFORM = $(platform-y) +export PLATFORM + +# temporarily until string.h is fixed +KBUILD_CFLAGS += -ffreestanding + +KBUILD_CFLAGS += -pipe -mlongcalls + +KBUILD_CFLAGS += $(call cc-option,-mforce-no-pic,) + +vardirs := $(patsubst %,arch/xtensa/variants/%/,$(variant-y)) +plfdirs := $(patsubst %,arch/xtensa/platforms/%/,$(platform-y)) + +ifeq ($(KBUILD_SRC),) +KBUILD_CPPFLAGS += $(patsubst %,-I%include,$(vardirs) $(plfdirs)) +else +KBUILD_CPPFLAGS += $(patsubst %,-I$(srctree)/%include,$(vardirs) $(plfdirs)) +endif + +KBUILD_DEFCONFIG := iss_defconfig + +# ramdisk/initrd support +# You need a compressed ramdisk image, named ramdisk.gz in +# arch/xtensa/boot/ramdisk + +core-$(CONFIG_EMBEDDED_RAMDISK) += arch/xtensa/boot/ramdisk/ + +# Test for cross compiling + +ifneq ($(VARIANT),) + COMPILE_ARCH = $(shell uname -m) + + ifneq ($(COMPILE_ARCH), xtensa) + ifndef CROSS_COMPILE + CROSS_COMPILE = xtensa_$(VARIANT)- + endif + endif +endif + +# Only build variant and/or platform if it includes a Makefile + +buildvar := $(shell test -a $(srctree)/arch/xtensa/variants/$(VARIANT)/Makefile && echo arch/xtensa/variants/$(VARIANT)/) +buildplf := $(shell test -a $(srctree)/arch/xtensa/platforms/$(PLATFORM)/Makefile && echo arch/xtensa/platforms/$(PLATFORM)/) + +# Find libgcc.a + +LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name) + +head-y := arch/xtensa/kernel/head.o +core-y += arch/xtensa/kernel/ arch/xtensa/mm/ +core-y += $(buildvar) $(buildplf) + +libs-y += arch/xtensa/lib/ $(LIBGCC) + +boot := arch/xtensa/boot + +all: zImage + +bzImage : zImage + +zImage zImage.initrd: vmlinux + $(Q)$(MAKE) $(build)=$(boot) $@ + +define archhelp + @echo '* zImage - Compressed kernel image (arch/xtensa/boot/images/zImage.*)' +endef + diff --git a/arch/xtensa/boot/Makefile b/arch/xtensa/boot/Makefile new file mode 100644 index 00000000..70fd1453 --- /dev/null +++ b/arch/xtensa/boot/Makefile @@ -0,0 +1,33 @@ +# +# arch/xtensa/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. +# +# + + +# KBUILD_CFLAGS used when building rest of boot (takes effect recursively) +KBUILD_CFLAGS += -fno-builtin -Iarch/$(ARCH)/boot/include +HOSTFLAGS += -Iarch/$(ARCH)/boot/include + +BIG_ENDIAN := $(shell echo -e __XTENSA_EB__ | $(CC) -E - | grep -v "\#") + +export ccflags-y +export BIG_ENDIAN + +subdir-y := lib + +# Subdirs for the boot loader(s) + +bootdir-$(CONFIG_XTENSA_PLATFORM_ISS) += boot-elf +bootdir-$(CONFIG_XTENSA_PLATFORM_XT2000) += boot-redboot boot-elf + + +zImage zImage.initrd Image Image.initrd: $(bootdir-y) + +$(bootdir-y): $(addprefix $(obj)/,$(subdir-y)) \ + $(addprefix $(obj)/,$(host-progs)) + $(Q)$(MAKE) $(build)=$(obj)/$@ $(MAKECMDGOALS) + diff --git a/arch/xtensa/boot/boot-elf/Makefile b/arch/xtensa/boot/boot-elf/Makefile new file mode 100644 index 00000000..08e8814f --- /dev/null +++ b/arch/xtensa/boot/boot-elf/Makefile @@ -0,0 +1,53 @@ +# +# 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. +# + +GZIP = gzip +GZIP_FLAGS = -v9fc + +ifeq ($(BIG_ENDIAN),1) +OBJCOPY_ARGS := -O elf32-xtensa-be +else +OBJCOPY_ARGS := -O elf32-xtensa-le +endif + +export OBJCOPY_ARGS +export CPPFLAGS_boot.lds += -P -C + +boot-y := bootstrap.o + +OBJS := $(addprefix $(obj)/,$(boot-y)) + +Image: vmlinux $(OBJS) arch/$(ARCH)/boot/boot-elf/boot.lds + $(OBJCOPY) --strip-all -R .comment -R .note.gnu.build-id -O binary \ + vmlinux vmlinux.tmp + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ + --add-section image=vmlinux.tmp \ + --set-section-flags image=contents,alloc,load,load,data \ + $(OBJS) $@.tmp + $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) \ + -T arch/$(ARCH)/boot/boot-elf/boot.lds \ + -o arch/$(ARCH)/boot/$@.elf $@.tmp + rm -f $@.tmp vmlinux.tmp + +Image.initrd: vmlinux $(OBJS) + $(OBJCOPY) --strip-all -R .comment -R .note.gnu.build-id -O binary \ + --add-section .initrd=arch/$(ARCH)/boot/ramdisk \ + --set-section-flags .initrd=contents,alloc,load,load,data \ + vmlinux vmlinux.tmp + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ + --add-section image=vmlinux.tmp \ + --set-section-flags image=contents,alloc,load,load,data \ + $(OBJS) $@.tmp + $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) \ + -T $(srctree)/arch/$(ARCH)/boot/boot-elf/boot.ld \ + -o arch/$(ARCH)/boot/$@.elf $@.tmp + rm -f $@.tmp vmlinux.tmp + + +zImage: Image + +zImage.initrd: Image.initrd + diff --git a/arch/xtensa/boot/boot-elf/boot.lds.S b/arch/xtensa/boot/boot-elf/boot.lds.S new file mode 100644 index 00000000..4e53b74d --- /dev/null +++ b/arch/xtensa/boot/boot-elf/boot.lds.S @@ -0,0 +1,73 @@ +#include <variant/core.h> +OUTPUT_ARCH(xtensa) +ENTRY(_ResetVector) + +SECTIONS +{ + .start 0xD0000000 : { *(.start) } + + .text 0xD0000000: + { + __reloc_start = . ; + _text_start = . ; + *(.literal .text.literal .text) + _text_end = . ; + } + + .rodata ALIGN(0x04): + { + *(.rodata) + *(.rodata1) + } + + .data ALIGN(0x04): + { + *(.data) + *(.data1) + *(.sdata) + *(.sdata2) + *(.got.plt) + *(.got) + *(.dynamic) + } + + __reloc_end = . ; + + .initrd ALIGN(0x10) : + { + boot_initrd_start = . ; + *(.initrd) + boot_initrd_end = .; + } + + . = ALIGN(0x10); + __image_load = . ; + .image 0xd0001000: + { + _image_start = .; + *(image) + . = (. + 3) & ~ 3; + _image_end = . ; + } + + + .bss ((LOADADDR(.image) + SIZEOF(.image) + 3) & ~ 3): + { + __bss_start = .; + *(.sbss) + *(.scommon) + *(.dynbss) + *(.bss) + __bss_end = .; + } + _end = .; + _param_start = .; + + .ResetVector.text XCHAL_RESET_VECTOR_VADDR : + { + *(.ResetVector.text) + } + + + PROVIDE (end = .); +} diff --git a/arch/xtensa/boot/boot-elf/bootstrap.S b/arch/xtensa/boot/boot-elf/bootstrap.S new file mode 100644 index 00000000..464298bc --- /dev/null +++ b/arch/xtensa/boot/boot-elf/bootstrap.S @@ -0,0 +1,33 @@ + +#include <asm/bootparam.h> + + +/* ResetVector + */ + .section .ResetVector.text, "ax" + .global _ResetVector +_ResetVector: + _j reset + .align 4 +RomInitAddr: + .word 0xd0001000 +RomBootParam: + .word _bootparam +reset: + l32r a0, RomInitAddr + l32r a2, RomBootParam + movi a3, 0 + movi a4, 0 + jx a0 + + .align 4 + .section .bootstrap.data, "aw" + + .globl _bootparam +_bootparam: + .short BP_TAG_FIRST + .short 4 + .long BP_VERSION + .short BP_TAG_LAST + .short 0 + .long 0 diff --git a/arch/xtensa/boot/boot-redboot/Makefile b/arch/xtensa/boot/boot-redboot/Makefile new file mode 100644 index 00000000..872029b8 --- /dev/null +++ b/arch/xtensa/boot/boot-redboot/Makefile @@ -0,0 +1,35 @@ +# +# 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. +# + +GZIP = gzip +GZIP_FLAGS = -v9fc +ifeq ($(BIG_ENDIAN),1) +OBJCOPY_ARGS := -O elf32-xtensa-be +else +OBJCOPY_ARGS := -O elf32-xtensa-le +endif + +LD_ARGS = -T $(srctree)/$(obj)/boot.ld + +boot-y := bootstrap.o + +OBJS := $(addprefix $(obj)/,$(boot-y)) +LIBS := arch/xtensa/boot/lib/lib.a arch/xtensa/lib/lib.a + +LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name) + +zImage: vmlinux $(OBJS) $(LIBS) + $(OBJCOPY) --strip-all -R .comment -R .note.gnu.build-id -O binary \ + vmlinux vmlinux.tmp + gzip -vf9 vmlinux.tmp + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ + --add-section image=vmlinux.tmp.gz \ + --set-section-flags image=contents,alloc,load,load,data \ + $(OBJS) $@.tmp + $(LD) $(LD_ARGS) -o $@.elf $@.tmp $(LIBS) -L/xtensa-elf/lib $(LIBGCC) + $(OBJCOPY) -S -O binary $@.elf arch/$(ARCH)/boot/$@.redboot + rm -f $@.tmp $@.elf vmlinux.tmp.gz + diff --git a/arch/xtensa/boot/boot-redboot/boot.ld b/arch/xtensa/boot/boot-redboot/boot.ld new file mode 100644 index 00000000..774db20d --- /dev/null +++ b/arch/xtensa/boot/boot-redboot/boot.ld @@ -0,0 +1,66 @@ +OUTPUT_ARCH(xtensa) + +SECTIONS +{ + .start 0xD1000000 : { *(.start) } + + .text : + { + __reloc_start = . ; + _text_start = . ; + *(.literal .text.literal .text) + _text_end = . ; + } + + .rodata ALIGN(0x04): + { + *(.rodata) + *(.rodata1) + } + + .data ALIGN(0x04): + { + *(.data) + *(.data1) + *(.sdata) + *(.sdata2) + *(.got.plt) + *(.got) + *(.dynamic) + } + + __reloc_end = . ; + + .initrd ALIGN(0x10) : + { + boot_initrd_start = . ; + *(.initrd) + boot_initrd_end = .; + } + + . = ALIGN(0x10); + __image_load = . ; + .image 0xd0001000: AT(__image_load) + { + _image_start = .; + *(image) + . = (. + 3) & ~ 3; + _image_end = . ; + } + + + .bss ((LOADADDR(.image) + SIZEOF(.image) + 3) & ~ 3): + { + __bss_start = .; + *(.sbss) + *(.scommon) + *(.dynbss) + *(.bss) + __bss_end = .; + } + _end = .; + _param_start = .; + + + PROVIDE (end = .); +} diff --git a/arch/xtensa/boot/boot-redboot/bootstrap.S b/arch/xtensa/boot/boot-redboot/bootstrap.S new file mode 100644 index 00000000..5582e8cf --- /dev/null +++ b/arch/xtensa/boot/boot-redboot/bootstrap.S @@ -0,0 +1,259 @@ +#include <variant/core.h> +#include <asm/regs.h> +#include <asm/asmmacro.h> +#include <asm/cacheasm.h> + /* + * RB-Data: RedBoot data/bss + * P: Boot-Parameters + * L: Kernel-Loader + * + * The Linux-Kernel image including the loader must be loaded + * to a position so that the kernel and the boot parameters + * can fit in the space before the load address. + * ______________________________________________________ + * |_RB-Data_|_P_|__________|_L_|___Linux-Kernel___|______| + * ^ + * ^ Load address + * ______________________________________________________ + * |___Linux-Kernel___|_P_|_L_|___________________________| + * + * The loader copies the parameter to the position that will + * be the end of the kernel and itself to the end of the + * parameter list. + */ + +/* Make sure we have enough space for the 'uncompressor' */ + +#define STACK_SIZE 32768 +#define HEAP_SIZE (131072*4) + + # a2: Parameter list + # a3: Size of parameter list + + .section .start, "ax" + + .globl __start + /* this must be the first byte of the loader! */ +__start: + entry sp, 32 # we do not intend to return + _call0 _start +__start_a0: + .align 4 + + .section .text, "ax" + .begin literal_prefix .text + + /* put literals in here! */ + + .globl _start +_start: + + /* 'reset' window registers */ + + movi a4, 1 + wsr a4, PS + rsync + + rsr a5, WINDOWBASE + ssl a5 + sll a4, a4 + wsr a4, WINDOWSTART + rsync + + movi a4, 0x00040000 + wsr a4, PS + rsync + + /* copy the loader to its address + * Note: The loader itself is a very small piece, so we assume we + * don't partially overlap. We also assume (even more important) + * that the kernel image is out of the way. Usually, when the + * load address of this image is not at an arbitrary address, + * but aligned to some 10K's we shouldn't overlap. + */ + + /* Note: The assembler cannot relax "addi a0, a0, ..." to an + l32r, so we load to a4 first. */ + + # addi a4, a0, __start - __start_a0 + # mov a0, a4 + + movi a4, __start + movi a5, __start_a0 + add a4, a0, a4 + sub a0, a4, a5 + + movi a4, __start + movi a5, __reloc_end + + # a0: address where this code has been loaded + # a4: compiled address of __start + # a5: compiled end address + + mov.n a7, a0 + mov.n a8, a4 + +1: + l32i a10, a7, 0 + l32i a11, a7, 4 + s32i a10, a8, 0 + s32i a11, a8, 4 + l32i a10, a7, 8 + l32i a11, a7, 12 + s32i a10, a8, 8 + s32i a11, a8, 12 + addi a8, a8, 16 + addi a7, a7, 16 + blt a8, a5, 1b + + + /* We have to flush and invalidate the caches here before we jump. */ + +#if XCHAL_DCACHE_IS_WRITEBACK + + ___flush_dcache_all a5 a6 + +#endif + + ___invalidate_icache_all a5 a6 + isync + + movi a11, _reloc + jx a11 + + .globl _reloc +_reloc: + + /* RedBoot is now at the end of the memory, so we don't have + * to copy the parameter list. Keep the code around; in case + * we need it again. */ +#if 0 + # a0: load address + # a2: start address of parameter list + # a3: length of parameter list + # a4: __start + + /* copy the parameter list out of the way */ + + movi a6, _param_start + add a3, a2, a3 +2: + l32i a8, a2, 0 + s32i a8, a6, 0 + addi a2, a2, 4 + addi a6, a6, 4 + blt a2, a3, 2b +#endif + + /* clear BSS section */ + movi a6, __bss_start + movi a7, __bss_end + movi.n a5, 0 +3: + s32i a5, a6, 0 + addi a6, a6, 4 + blt a6, a7, 3b + + movi a5, -16 + movi a1, _stack + STACK_SIZE + and a1, a1, a5 + + /* Uncompress the kernel */ + + # a0: load address + # a2: boot parameter + # a4: __start + + movi a3, __image_load + sub a4, a3, a4 + add a8, a0, a4 + + # a1 Stack + # a8(a4) Load address of the image + + movi a6, _image_start + movi a10, _image_end + movi a7, 0x1000000 + sub a11, a10, a6 + movi a9, complen + s32i a11, a9, 0 + + movi a0, 0 + + # a6 destination + # a7 maximum size of destination + # a8 source + # a9 ptr to length + + .extern gunzip + movi a4, gunzip + beqz a4, 1f + + callx4 a4 + + j 2f + + + # a6 destination start + # a7 maximum size of destination + # a8 source start + # a9 ptr to length + # a10 destination end + +1: + l32i a9, a8, 0 + l32i a11, a8, 4 + s32i a9, a6, 0 + s32i a11, a6, 4 + l32i a9, a8, 8 + l32i a11, a8, 12 + s32i a9, a6, 8 + s32i a11, a6, 12 + addi a6, a6, 16 + addi a8, a8, 16 + blt a6, a10, 1b + + + /* jump to the kernel */ +2: +#if XCHAL_DCACHE_IS_WRITEBACK + + ___flush_dcache_all a5 a6 + +#endif + + ___invalidate_icache_all a5 a6 + + isync + + movi a5, __start + movi a3, boot_initrd_start + movi a4, boot_initrd_end + sub a3, a3, a5 + sub a4, a4, a5 + add a3, a0, a3 + add a4, a0, a4 + + # a2 Boot parameter list + # a3 initrd_start (virtual load address) + # a4 initrd_end (virtual load address) + + movi a0, _image_start + jx a0 + + .align 16 + .data + .globl avail_ram +avail_ram: + .long _heap + .globl end_avail +end_avail: + .long _heap + HEAP_SIZE + + .comm _stack, STACK_SIZE + .comm _heap, HEAP_SIZE + + .globl end_avail + .comm complen, 4 + + .end literal_prefix diff --git a/arch/xtensa/boot/lib/Makefile b/arch/xtensa/boot/lib/Makefile new file mode 100644 index 00000000..ad8952e8 --- /dev/null +++ b/arch/xtensa/boot/lib/Makefile @@ -0,0 +1,17 @@ +# +# Makefile for some libs needed by zImage. +# + +zlib := inffast.c inflate.c inftrees.c + +lib-y += $(zlib:.c=.o) zmem.o + +ccflags-y := -Ilib/zlib_inflate + +quiet_cmd_copy_zlib = COPY $@ + cmd_copy_zlib = cat $< > $@ + +$(addprefix $(obj)/,$(zlib)): $(obj)/%: $(srctree)/lib/zlib_inflate/% + $(call cmd,copy_zlib) + +clean-files := $(zlib) diff --git a/arch/xtensa/boot/lib/zmem.c b/arch/xtensa/boot/lib/zmem.c new file mode 100644 index 00000000..d9862aa8 --- /dev/null +++ b/arch/xtensa/boot/lib/zmem.c @@ -0,0 +1,79 @@ +#include <linux/zlib.h> + +/* bits taken from ppc */ + +extern void *avail_ram, *end_avail; + +void exit (void) +{ + for (;;); +} + +void *zalloc(unsigned size) +{ + void *p = avail_ram; + + size = (size + 7) & -8; + avail_ram += size; + if (avail_ram > end_avail) { + //puts("oops... out of memory\n"); + //pause(); + exit (); + } + return p; +} + +#define HEAD_CRC 2 +#define EXTRA_FIELD 4 +#define ORIG_NAME 8 +#define COMMENT 0x10 +#define RESERVED 0xe0 + +#define DEFLATED 8 + +void gunzip (void *dst, int dstlen, unsigned char *src, int *lenp) +{ + z_stream s; + int r, i, flags; + + /* skip header */ + i = 10; + flags = src[3]; + if (src[2] != DEFLATED || (flags & RESERVED) != 0) { + //puts("bad gzipped data\n"); + exit(); + } + if ((flags & EXTRA_FIELD) != 0) + i = 12 + src[10] + (src[11] << 8); + if ((flags & ORIG_NAME) != 0) + while (src[i++] != 0) + ; + if ((flags & COMMENT) != 0) + while (src[i++] != 0) + ; + if ((flags & HEAD_CRC) != 0) + i += 2; + if (i >= *lenp) { + //puts("gunzip: ran out of data in header\n"); + exit(); + } + + s.workspace = zalloc(zlib_inflate_workspacesize()); + r = zlib_inflateInit2(&s, -MAX_WBITS); + if (r != Z_OK) { + //puts("inflateInit2 returned "); puthex(r); puts("\n"); + exit(); + } + s.next_in = src + i; + s.avail_in = *lenp - i; + s.next_out = dst; + s.avail_out = dstlen; + r = zlib_inflate(&s, Z_FINISH); + if (r != Z_OK && r != Z_STREAM_END) { + //puts("inflate returned "); puthex(r); puts("\n"); + exit(); + } + *lenp = s.next_out - (unsigned char *) dst; + zlib_inflateEnd(&s); +} + diff --git a/arch/xtensa/boot/ramdisk/Makefile b/arch/xtensa/boot/ramdisk/Makefile new file mode 100644 index 00000000..b12f7635 --- /dev/null +++ b/arch/xtensa/boot/ramdisk/Makefile @@ -0,0 +1,23 @@ +# +# Makefile for a ramdisk image +# + +BIG_ENDIAN := $(shell echo -e "\#ifdef __XTENSA_EL__\nint little;\n\#else\nint big;\n\#endif" | $(CC) -E -|grep -c big) + +ifeq ($(BIG_ENDIAN),1) +OBJCOPY_ARGS := -O elf32-xtensa-be +else +OBJCOPY_ARGS := -O elf32-xtensa-le +endif + +obj-y = ramdisk.o + +RAMDISK_IMAGE = arch/$(ARCH)/boot/ramdisk/$(CONFIG_EMBEDDED_RAMDISK_IMAGE) + +arch/$(ARCH)/boot/ramdisk/ramdisk.o: + $(Q)echo -e "dummy:" | $(AS) -o $@; + $(Q)$(OBJCOPY) $(OBJCOPY_ARGS) \ + --add-section .initrd=$(RAMDISK_IMAGE) \ + --set-section-flags .initrd=contents,alloc,load,load,data \ + arch/$(ARCH)/boot/ramdisk/ramdisk.o $@ + diff --git a/arch/xtensa/configs/common_defconfig b/arch/xtensa/configs/common_defconfig new file mode 100644 index 00000000..b90038e4 --- /dev/null +++ b/arch/xtensa/configs/common_defconfig @@ -0,0 +1,662 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.11-rc2 +# Tue Mar 1 16:36:53 2005 +# +# CONFIG_FRAME_POINTER is not set +CONFIG_XTENSA=y +# CONFIG_UID16 is not set +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_HAVE_DEC_LOCK=y +CONFIG_GENERIC_HARDIRQS=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_HOTPLUG is not set +CONFIG_KOBJECT_UEVENT=y +# CONFIG_IKCONFIG is not set +# CONFIG_EXPERT is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +CONFIG_CC_ALIGN_JUMPS=0 +# CONFIG_TINY_SHMEM is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODULE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +CONFIG_MODVERSIONS=y +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y + +# +# Processor type and features +# +CONFIG_XTENSA_ARCH_LINUX_BE=y +# CONFIG_XTENSA_ARCH_LINUX_LE is not set +# CONFIG_XTENSA_ARCH_LINUX_TEST is not set +# CONFIG_XTENSA_ARCH_S5 is not set +# CONFIG_XTENSA_CUSTOM is not set +CONFIG_MMU=y +# CONFIG_XTENSA_UNALIGNED_USER is not set +# CONFIG_PREEMPT is not set +# CONFIG_MATH_EMULATION is not set +# CONFIG_HIGHMEM is not set + +# +# Platform options +# +# CONFIG_XTENSA_PLATFORM_ISS is not set +CONFIG_XTENSA_PLATFORM_XT2000=y +CONFIG_XTENSA_CALIBRATE_CCOUNT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="console=ttyS0,38400 ip=bootp root=nfs nfsroot=/opt/montavista/pro/devkit/xtensa/linux_be/target" + +# +# Bus options +# +CONFIG_PCI=y +# CONFIG_PCI_LEGACY_PROC is not set +# CONFIG_PCI_NAMES is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# PC-card bridges +# + +# +# PCI Hotplug Support +# +# CONFIG_HOTPLUG_PCI is not set + +# +# Exectuable file formats +# +CONFIG_KCORE_ELF=y +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=y + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set + +# +# 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_COW_COMMON is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_RAM is not set +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CDROM_PKTCDVD is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_ATA_OVER_ETH 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 is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE 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_INET_TUNNEL is not set +# CONFIG_IP_TCPDIAG is not set +# CONFIG_IP_TCPDIAG_IPV6 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 + +# +# QoS and/or fair queueing +# +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CLK_JIFFIES=y +# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set +# CONFIG_NET_SCH_CLK_CPU is not set +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_HTB=m +# CONFIG_NET_SCH_HFSC is not set +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +# CONFIG_NET_SCH_NETEM is not set +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_QOS=y +CONFIG_NET_ESTIMATOR=y +CONFIG_NET_CLS=y +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +# CONFIG_CLS_U32_PERF is not set +# CONFIG_NET_CLS_IND is not set +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +# CONFIG_NET_CLS_ACT is not set +CONFIG_NET_CLS_POLICE=y + +# +# 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=y +# 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_XT2000_SONIC=y +# 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 is not set +# CONFIG_HP100 is not set +# CONFIG_NET_PCI 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=y + +# +# Obsolete Wireless cards support (pre-802.11) +# +CONFIG_STRIP=m + +# +# Wireless 802.11b ISA/PCI cards support +# +CONFIG_HERMES=m +# CONFIG_PLX_HERMES is not set +# CONFIG_TMD_HERMES is not set +# CONFIG_PCI_HERMES is not set +# CONFIG_ATMEL is not set + +# +# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support +# +# CONFIG_PRISM54 is not set +CONFIG_NET_WIRELESS=y + +# +# 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 is not set +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 is not set +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PCIPS2 is not set +# CONFIG_SERIO_RAW is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE 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=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG 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_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 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 is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# File systems +# +# CONFIG_EXT2_FS 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 is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# 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_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +# CONFIG_PROC_KCORE is not set +CONFIG_SYSFS=y +CONFIG_DEVFS_FS=y +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS_XATTR is not set +# CONFIG_TMPFS is not set +# CONFIG_HUGETLB_PAGE is not set +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_RPCSEC_GSS_SPKM3 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_DEBUG_KERNEL=y +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_SLAB is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_KGDB is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Hardware crypto devices +# + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC32 is not set +# CONFIG_LIBCRC32C is not set diff --git a/arch/xtensa/configs/iss_defconfig b/arch/xtensa/configs/iss_defconfig new file mode 100644 index 00000000..ddab37b2 --- /dev/null +++ b/arch/xtensa/configs/iss_defconfig @@ -0,0 +1,765 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.34-rc6 +# Tue Aug 3 00:10:54 2010 +# +# CONFIG_FRAME_POINTER is not set +CONFIG_ZONE_DMA=y +CONFIG_XTENSA=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_GPIO=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_NO_IOPORT=y +CONFIG_HZ=100 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_CONSTRUCTORS=y + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_AUDIT is not set + +# +# RCU Subsystem +# +CONFIG_TREE_RCU=y +# CONFIG_TREE_PREEMPT_RCU is not set +# CONFIG_TINY_RCU is not set +# CONFIG_RCU_TRACE is not set +CONFIG_RCU_FANOUT=32 +# CONFIG_RCU_FANOUT_EXACT is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_CGROUPS is not set +# CONFIG_SYSFS_DEPRECATED_V2 is not set +# CONFIG_RELAY is not set +# CONFIG_NAMESPACES is not set +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_EXPERT=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +# CONFIG_HOTPLUG is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y + +# +# Kernel Performance Events And Counters +# +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +CONFIG_COMPAT_BRK=y +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set + +# +# GCOV-based kernel profiling +# +# CONFIG_SLOW_WORK is not set +# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +# CONFIG_MODULES is not set +CONFIG_BLOCK=y +CONFIG_LBDAF=y +CONFIG_BLK_DEV_BSG=y +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_DEADLINE is not set +# CONFIG_IOSCHED_CFQ is not set +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +CONFIG_DEFAULT_NOOP=y +CONFIG_DEFAULT_IOSCHED="noop" +# CONFIG_INLINE_SPIN_TRYLOCK is not set +# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK is not set +# CONFIG_INLINE_SPIN_LOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK_IRQ is not set +# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set +# CONFIG_UNINLINE_SPIN_UNLOCK is not set +# CONFIG_INLINE_SPIN_UNLOCK_BH is not set +CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_READ_TRYLOCK is not set +# CONFIG_INLINE_READ_LOCK is not set +# CONFIG_INLINE_READ_LOCK_BH is not set +# CONFIG_INLINE_READ_LOCK_IRQ is not set +# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set +CONFIG_INLINE_READ_UNLOCK=y +# CONFIG_INLINE_READ_UNLOCK_BH is not set +CONFIG_INLINE_READ_UNLOCK_IRQ=y +# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_WRITE_TRYLOCK is not set +# CONFIG_INLINE_WRITE_LOCK is not set +# CONFIG_INLINE_WRITE_LOCK_BH is not set +# CONFIG_INLINE_WRITE_LOCK_IRQ is not set +# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set +CONFIG_INLINE_WRITE_UNLOCK=y +# CONFIG_INLINE_WRITE_UNLOCK_BH is not set +CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set +# CONFIG_MUTEX_SPIN_ON_OWNER is not set +# CONFIG_FREEZER is not set +CONFIG_MMU=y +# CONFIG_VARIANT_IRQ_SWITCH is not set + +# +# Processor type and features +# +CONFIG_XTENSA_VARIANT_FSF=y +# CONFIG_XTENSA_VARIANT_DC232B is not set +# CONFIG_XTENSA_VARIANT_S6000 is not set +# CONFIG_XTENSA_UNALIGNED_USER is not set +# CONFIG_PREEMPT is not set +# CONFIG_MATH_EMULATION is not set +CONFIG_XTENSA_CALIBRATE_CCOUNT=y +CONFIG_SERIAL_CONSOLE=y +CONFIG_XTENSA_ISS_NETWORK=y + +# +# Bus options +# +# CONFIG_PCI is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set + +# +# Platform options +# +CONFIG_XTENSA_PLATFORM_ISS=y +# CONFIG_XTENSA_PLATFORM_XT2000 is not set +# CONFIG_XTENSA_PLATFORM_S6105 is not set +# CONFIG_GENERIC_CALIBRATE_DELAY is not set +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="console=ttyS0,38400 eth0=tuntap,,tap0 ip=192.168.168.5:192.168.168.1 root=nfs nfsroot=192.168.168.1:/opt/montavista/pro/devkit/xtensa/linux_be/target" +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +# CONFIG_KSM is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 + +# +# Executable file formats +# +CONFIG_KCORE_ELF=y +CONFIG_BINFMT_ELF=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_HAVE_AOUT is not set +# CONFIG_BINFMT_MISC is not set +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +# 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_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_LRO=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_NET_DSA 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_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set +# CONFIG_NET_SCHED is not set +# CONFIG_DCB is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +CONFIG_WIRELESS=y +# CONFIG_CFG80211 is not set +# CONFIG_LIB80211 is not set + +# +# CFG80211 needs to be enabled for MAC80211 +# +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +# CONFIG_STANDALONE is not set +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_CONNECTOR is not set +# CONFIG_MTD is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_LOOP is not set + +# +# DRBD disabled because PROC_FS, INET or CONNECTOR not selected +# +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_MISC_DEVICES=y +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_93CX6 is not set +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_DMA is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +# CONFIG_NETDEVICES is not set +# CONFIG_ISDN is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_DEVKMEM=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_TIMBERDALE is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_I2C is not set +# CONFIG_SPI is not set + +# +# PPS support +# +# CONFIG_PPS is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_THERMAL is not set +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_NOWAYOUT=y + +# +# Watchdog Device Drivers +# +CONFIG_SOFT_WATCHDOG=y +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_REGULATOR is not set +# CONFIG_MEDIA_SUPPORT is not set + +# +# Graphics support +# +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +# CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +# CONFIG_SOUND is not set +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +# CONFIG_HIDRAW is not set +# CONFIG_HID_PID is not set + +# +# Special HID drivers +# +CONFIG_USB_SUPPORT=y +# CONFIG_USB_ARCH_HAS_HCD is not set +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set + +# +# Enable Host or Gadget support to see Inventra options +# + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# +# CONFIG_USB_GADGET is not set + +# +# OTG and related infrastructure +# +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_RTC_CLASS is not set +# CONFIG_DMADEVICES is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_UIO is not set + +# +# TI VLYNQ +# +# CONFIG_STAGING is not set + +# +# File systems +# +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +# CONFIG_DNOTIFY is not set +# CONFIG_INOTIFY is not set +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_CONFIGFS_FS is not set +CONFIG_MISC_FILESYSTEMS=y +# 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_LOGFS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +# CONFIG_NFS_FS is not set +# CONFIG_NFSD is not set +# CONFIG_SMB_FS is not set +# CONFIG_CEPH_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 +# CONFIG_NLS is not set +# CONFIG_DLM is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=1024 +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +CONFIG_DETECT_HUNG_TASK=y +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_CPU_STALL_DETECTOR=y +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_SYSCTL_SYSCALL_CHECK is not set +# CONFIG_PAGE_POISONING is not set +# CONFIG_SAMPLES is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +# CONFIG_DEFAULT_SECURITY_SELINUX is not set +# CONFIG_DEFAULT_SECURITY_SMACK is not set +# CONFIG_DEFAULT_SECURITY_TOMOYO is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_SECURITY="" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +# CONFIG_CRYPTO_FIPS is not set +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +# CONFIG_CRYPTO_MANAGER is not set +# CONFIG_CRYPTO_MANAGER2 is not set +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_AUTHENC is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +# CONFIG_CRYPTO_CBC is not set +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +# CONFIG_CRYPTO_ECB is not set +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_GHASH is not set +# CONFIG_CRYPTO_MD4 is not set +# CONFIG_CRYPTO_MD5 is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TWOFISH is not set + +# +# Compression +# +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_ZLIB is not set +# CONFIG_CRYPTO_LZO is not set + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_HW=y +# CONFIG_BINARY_PRINTF is not set + +# +# Library routines +# +CONFIG_GENERIC_FIND_LAST_BIT=y +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +# CONFIG_CRC32 is not set +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +CONFIG_HAS_IOMEM=y +CONFIG_HAS_DMA=y +CONFIG_NLATTR=y diff --git a/arch/xtensa/configs/s6105_defconfig b/arch/xtensa/configs/s6105_defconfig new file mode 100644 index 00000000..550e8ed5 --- /dev/null +++ b/arch/xtensa/configs/s6105_defconfig @@ -0,0 +1,624 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.29-rc7-s6 +# Tue Mar 10 11:09:26 2009 +# +# CONFIG_FRAME_POINTER is not set +CONFIG_ZONE_DMA=y +CONFIG_XTENSA=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_GPIO=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_NO_IOPORT=y +CONFIG_HZ=100 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_AUDIT is not set + +# +# RCU Subsystem +# +# CONFIG_CLASSIC_RCU is not set +# CONFIG_TREE_RCU is not set +CONFIG_PREEMPT_RCU=y +# CONFIG_RCU_TRACE is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_PREEMPT_RCU_TRACE is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=16 +# CONFIG_GROUP_SCHED is not set +# CONFIG_CGROUPS is not set +# CONFIG_SYSFS_DEPRECATED_V2 is not set +# CONFIG_RELAY is not set +# CONFIG_NAMESPACES is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_EXPERT=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +# CONFIG_HOTPLUG is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +# CONFIG_COMPAT_BRK is not set +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_AIO=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +# CONFIG_MODULES is not set +CONFIG_BLOCK=y +# CONFIG_LBD is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +# CONFIG_IOSCHED_DEADLINE is not set +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +# CONFIG_FREEZER is not set +# CONFIG_MMU is not set +CONFIG_VARIANT_IRQ_SWITCH=y + +# +# Processor type and features +# +# CONFIG_XTENSA_VARIANT_FSF is not set +# CONFIG_XTENSA_VARIANT_DC232B is not set +CONFIG_XTENSA_VARIANT_S6000=y +# CONFIG_XTENSA_UNALIGNED_USER is not set +CONFIG_PREEMPT=y +# CONFIG_MATH_EMULATION is not set +# CONFIG_HIGHMEM is not set +CONFIG_XTENSA_CALIBRATE_CCOUNT=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_XTENSA_ISS_NETWORK is not set + +# +# Bus options +# +# CONFIG_PCI is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set + +# +# Platform options +# +# CONFIG_XTENSA_PLATFORM_ISS is not set +# CONFIG_XTENSA_PLATFORM_XT2000 is not set +CONFIG_XTENSA_PLATFORM_S6105=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="console=ttyS1,38400 debug bootmem_debug loglevel=7" +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_VIRT_TO_BUS=y + +# +# Executable file formats +# +CONFIG_KCORE_ELF=y +CONFIG_BINFMT_FLAT=y +# CONFIG_BINFMT_ZFLAT is not set +# CONFIG_BINFMT_SHARED_FLAT is not set +# CONFIG_HAVE_AOUT is not set +# CONFIG_BINFMT_MISC is not set +CONFIG_NET=y + +# +# Networking options +# +CONFIG_COMPAT_NET_DEV_OPS=y +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP 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_FIB_HASH=y +# CONFIG_IP_PNP 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_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +# CONFIG_INET_DIAG is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_NET_DSA 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_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_SCHED is not set +# CONFIG_DCB is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_PHONET is not set +# CONFIG_WIRELESS is not set +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_CONNECTOR is not set +# CONFIG_MTD is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_BLK_DEV_HD is not set +# CONFIG_MISC_DEVICES is not set +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_DMA is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_VETH is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +CONFIG_SMSC_PHY=y +# CONFIG_BROADCOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_FIXED_PHY is not set +# CONFIG_MDIO_BITBANG is not set +# CONFIG_NET_ETHERNET is not set +CONFIG_NETDEV_1000=y +CONFIG_S6GMAC=y +# CONFIG_NETDEV_10000 is not set + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set +# CONFIG_IWLWIFI_LEDS is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_ISDN is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +# CONFIG_INPUT is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_DEVKMEM is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=2 +CONFIG_SERIAL_8250_RUNTIME_UARTS=2 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_I2C is not set +# CONFIG_SPI is not set +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +# CONFIG_DEBUG_GPIO is not set +# CONFIG_GPIO_SYSFS is not set + +# +# Memory mapped GPIO expanders: +# + +# +# I2C GPIO expanders: +# + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set +# CONFIG_THERMAL is not set +# CONFIG_THERMAL_HWMON is not set +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_REGULATOR is not set + +# +# Multimedia devices +# + +# +# Multimedia core support +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DVB_CORE is not set +# CONFIG_VIDEO_MEDIA is not set + +# +# Multimedia drivers +# +# CONFIG_DAB is not set + +# +# Graphics support +# +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +# CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_SOUND is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_ACCESSIBILITY is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +# CONFIG_RTC_INTF_SYSFS is not set +# CONFIG_RTC_INTF_PROC is not set +# CONFIG_RTC_INTF_DEV is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +CONFIG_RTC_DRV_M41T80=y +# CONFIG_RTC_DRV_M41T80_WDT is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set + +# +# SPI RTC drivers +# + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +# CONFIG_DMADEVICES is not set +# CONFIG_UIO is not set +# CONFIG_STAGING is not set + +# +# File systems +# +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +CONFIG_FILE_LOCKING=y +# CONFIG_XFS_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_DNOTIFY is not set +# CONFIG_INOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_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_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +# CONFIG_TMPFS is not set +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_CONFIGFS_FS is not set +# CONFIG_MISC_FILESYSTEMS is not set +# CONFIG_NETWORK_FILESYSTEMS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_NLS is not set +# CONFIG_DLM is not set + +# +# Xtensa initrd options +# +# CONFIG_EMBEDDED_RAMDISK is not set + +# +# Kernel hacking +# +CONFIG_PRINTK_TIME=y +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_FRAME_WARN=1024 +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_SHIRQ=y +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +# CONFIG_SCHED_DEBUG is not set +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_MUTEXES=y +CONFIG_DEBUG_SPINLOCK_SLEEP=y +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_VM is not set +CONFIG_DEBUG_NOMMU_REGIONS=y +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_SYSCTL_SYSCALL_CHECK is not set + +# +# Tracers +# +# CONFIG_PREEMPT_TRACER is not set +# CONFIG_SCHED_TRACER is not set +# CONFIG_CONTEXT_SWITCH_TRACER is not set +# CONFIG_BOOT_TRACER is not set +# CONFIG_TRACE_BRANCH_PROFILING is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_SAMPLES is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +# CONFIG_SECURITY_FILE_CAPABILITIES is not set +# CONFIG_CRYPTO is not set + +# +# Library routines +# +CONFIG_GENERIC_FIND_LAST_BIT=y +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +# CONFIG_CRC32 is not set +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_DMA=y diff --git a/arch/xtensa/include/asm/Kbuild b/arch/xtensa/include/asm/Kbuild new file mode 100644 index 00000000..c68e1680 --- /dev/null +++ b/arch/xtensa/include/asm/Kbuild @@ -0,0 +1 @@ +include include/asm-generic/Kbuild.asm diff --git a/arch/xtensa/include/asm/asm-offsets.h b/arch/xtensa/include/asm/asm-offsets.h new file mode 100644 index 00000000..d370ee36 --- /dev/null +++ b/arch/xtensa/include/asm/asm-offsets.h @@ -0,0 +1 @@ +#include <generated/asm-offsets.h> diff --git a/arch/xtensa/include/asm/asmmacro.h b/arch/xtensa/include/asm/asmmacro.h new file mode 100644 index 00000000..755320f6 --- /dev/null +++ b/arch/xtensa/include/asm/asmmacro.h @@ -0,0 +1,153 @@ +/* + * include/asm-xtensa/asmmacro.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_ASMMACRO_H +#define _XTENSA_ASMMACRO_H + +#include <variant/core.h> + +/* + * Some little helpers for loops. Use zero-overhead-loops + * where applicable and if supported by the processor. + * + * __loopi ar, at, size, inc + * ar register initialized with the start address + * at scratch register used by macro + * size size immediate value + * inc increment + * + * __loops ar, as, at, inc_log2[, mask_log2][, cond][, ncond] + * ar register initialized with the start address + * as register initialized with the size + * at scratch register use by macro + * inc_log2 increment [in log2] + * mask_log2 mask [in log2] + * cond true condition (used in loop'cond') + * ncond false condition (used in b'ncond') + * + * __loop as + * restart loop. 'as' register must not have been modified! + * + * __endla ar, at, incr + * ar start address (modified) + * as scratch register used by macro + * inc increment + */ + +/* + * loop for given size as immediate + */ + + .macro __loopi ar, at, size, incr + +#if XCHAL_HAVE_LOOPS + movi \at, ((\size + \incr - 1) / (\incr)) + loop \at, 99f +#else + addi \at, \ar, \size + 98: +#endif + + .endm + +/* + * loop for given size in register + */ + + .macro __loops ar, as, at, incr_log2, mask_log2, cond, ncond + +#if XCHAL_HAVE_LOOPS + .ifgt \incr_log2 - 1 + addi \at, \as, (1 << \incr_log2) - 1 + .ifnc \mask_log2, + extui \at, \at, \incr_log2, \mask_log2 + .else + srli \at, \at, \incr_log2 + .endif + .endif + loop\cond \at, 99f +#else + .ifnc \mask_log2, + extui \at, \as, \incr_log2, \mask_log2 + .else + .ifnc \ncond, + srli \at, \as, \incr_log2 + .endif + .endif + .ifnc \ncond, + b\ncond \at, 99f + + .endif + .ifnc \mask_log2, + slli \at, \at, \incr_log2 + add \at, \ar, \at + .else + add \at, \ar, \as + .endif +#endif + 98: + + .endm + +/* + * loop from ar to ax + */ + + .macro __loopt ar, as, at, incr_log2 + +#if XCHAL_HAVE_LOOPS + sub \at, \as, \ar + .ifgt \incr_log2 - 1 + addi \at, \at, (1 << \incr_log2) - 1 + srli \at, \at, \incr_log2 + .endif + loop \at, 99f +#else + 98: +#endif + + .endm + +/* + * restart loop. registers must be unchanged + */ + + .macro __loop as + +#if XCHAL_HAVE_LOOPS + loop \as, 99f +#else + 98: +#endif + + .endm + +/* + * end of loop with no increment of the address. + */ + + .macro __endl ar, as +#if !XCHAL_HAVE_LOOPS + bltu \ar, \as, 98b +#endif + 99: + .endm + +/* + * end of loop with increment of the address. + */ + + .macro __endla ar, as, incr + addi \ar, \ar, \incr + __endl \ar \as + .endm + + +#endif /* _XTENSA_ASMMACRO_H */ diff --git a/arch/xtensa/include/asm/atomic.h b/arch/xtensa/include/asm/atomic.h new file mode 100644 index 00000000..b4098930 --- /dev/null +++ b/arch/xtensa/include/asm/atomic.h @@ -0,0 +1,297 @@ +/* + * include/asm-xtensa/atomic.h + * + * Atomic operations that C can't guarantee us. Useful for resource counting.. + * + * 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) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_ATOMIC_H +#define _XTENSA_ATOMIC_H + +#include <linux/stringify.h> +#include <linux/types.h> + +#ifdef __KERNEL__ +#include <asm/processor.h> +#include <asm/cmpxchg.h> + +#define ATOMIC_INIT(i) { (i) } + +/* + * This Xtensa implementation assumes that the right mechanism + * for exclusion is for locking interrupts to level 1. + * + * Locking interrupts looks like this: + * + * rsil a15, 1 + * <code> + * wsr a15, PS + * rsync + * + * Note that a15 is used here because the register allocation + * done by the compiler is not guaranteed and a window overflow + * may not occur between the rsil and wsr instructions. By using + * a15 in the rsil, the machine is guaranteed to be in a state + * where no register reference will cause an overflow. + */ + +/** + * atomic_read - read atomic variable + * @v: pointer of type atomic_t + * + * Atomically reads the value of @v. + */ +#define atomic_read(v) (*(volatile int *)&(v)->counter) + +/** + * atomic_set - set atomic variable + * @v: pointer of type atomic_t + * @i: required value + * + * Atomically sets the value of @v to @i. + */ +#define atomic_set(v,i) ((v)->counter = (i)) + +/** + * atomic_add - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type atomic_t + * + * Atomically adds @i to @v. + */ +static inline void atomic_add(int i, atomic_t * v) +{ + unsigned int vval; + + __asm__ __volatile__( + "rsil a15, "__stringify(LOCKLEVEL)"\n\t" + "l32i %0, %2, 0 \n\t" + "add %0, %0, %1 \n\t" + "s32i %0, %2, 0 \n\t" + "wsr a15, "__stringify(PS)" \n\t" + "rsync \n" + : "=&a" (vval) + : "a" (i), "a" (v) + : "a15", "memory" + ); +} + +/** + * atomic_sub - subtract the atomic variable + * @i: integer value to subtract + * @v: pointer of type atomic_t + * + * Atomically subtracts @i from @v. + */ +static inline void atomic_sub(int i, atomic_t *v) +{ + unsigned int vval; + + __asm__ __volatile__( + "rsil a15, "__stringify(LOCKLEVEL)"\n\t" + "l32i %0, %2, 0 \n\t" + "sub %0, %0, %1 \n\t" + "s32i %0, %2, 0 \n\t" + "wsr a15, "__stringify(PS)" \n\t" + "rsync \n" + : "=&a" (vval) + : "a" (i), "a" (v) + : "a15", "memory" + ); +} + +/* + * We use atomic_{add|sub}_return to define other functions. + */ + +static inline int atomic_add_return(int i, atomic_t * v) +{ + unsigned int vval; + + __asm__ __volatile__( + "rsil a15,"__stringify(LOCKLEVEL)"\n\t" + "l32i %0, %2, 0 \n\t" + "add %0, %0, %1 \n\t" + "s32i %0, %2, 0 \n\t" + "wsr a15, "__stringify(PS)" \n\t" + "rsync \n" + : "=&a" (vval) + : "a" (i), "a" (v) + : "a15", "memory" + ); + + return vval; +} + +static inline int atomic_sub_return(int i, atomic_t * v) +{ + unsigned int vval; + + __asm__ __volatile__( + "rsil a15,"__stringify(LOCKLEVEL)"\n\t" + "l32i %0, %2, 0 \n\t" + "sub %0, %0, %1 \n\t" + "s32i %0, %2, 0 \n\t" + "wsr a15, "__stringify(PS)" \n\t" + "rsync \n" + : "=&a" (vval) + : "a" (i), "a" (v) + : "a15", "memory" + ); + + return vval; +} + +/** + * atomic_sub_and_test - subtract value from variable and test result + * @i: integer value to subtract + * @v: pointer of type atomic_t + * + * Atomically subtracts @i from @v and returns + * true if the result is zero, or false for all + * other cases. + */ +#define atomic_sub_and_test(i,v) (atomic_sub_return((i),(v)) == 0) + +/** + * atomic_inc - increment atomic variable + * @v: pointer of type atomic_t + * + * Atomically increments @v by 1. + */ +#define atomic_inc(v) atomic_add(1,(v)) + +/** + * atomic_inc - increment atomic variable + * @v: pointer of type atomic_t + * + * Atomically increments @v by 1. + */ +#define atomic_inc_return(v) atomic_add_return(1,(v)) + +/** + * atomic_dec - decrement atomic variable + * @v: pointer of type atomic_t + * + * Atomically decrements @v by 1. + */ +#define atomic_dec(v) atomic_sub(1,(v)) + +/** + * atomic_dec_return - decrement atomic variable + * @v: pointer of type atomic_t + * + * Atomically decrements @v by 1. + */ +#define atomic_dec_return(v) atomic_sub_return(1,(v)) + +/** + * atomic_dec_and_test - decrement and test + * @v: pointer of type atomic_t + * + * Atomically decrements @v by 1 and + * returns true if the result is 0, or false for all other + * cases. + */ +#define atomic_dec_and_test(v) (atomic_sub_return(1,(v)) == 0) + +/** + * 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_add_return(1,(v)) == 0) + +/** + * atomic_add_negative - add and test if negative + * @v: pointer of type atomic_t + * @i: integer value to add + * + * Atomically adds @i to @v and returns true + * if the result is negative, or false when + * result is greater than or equal to zero. + */ +#define atomic_add_negative(i,v) (atomic_add_return((i),(v)) < 0) + +#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n))) +#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) + +/** + * __atomic_add_unless - add unless the number is a given value + * @v: pointer of type atomic_t + * @a: the amount to add to v... + * @u: ...unless v is equal to u. + * + * Atomically adds @a to @v, so long as it was not @u. + * Returns the old value of @v. + */ +static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) +{ + int c, old; + c = atomic_read(v); + for (;;) { + if (unlikely(c == (u))) + break; + old = atomic_cmpxchg((v), c, c + (a)); + if (likely(old == c)) + break; + c = old; + } + return c; +} + + +static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) +{ + unsigned int all_f = -1; + unsigned int vval; + + __asm__ __volatile__( + "rsil a15,"__stringify(LOCKLEVEL)"\n\t" + "l32i %0, %2, 0 \n\t" + "xor %1, %4, %3 \n\t" + "and %0, %0, %4 \n\t" + "s32i %0, %2, 0 \n\t" + "wsr a15, "__stringify(PS)" \n\t" + "rsync \n" + : "=&a" (vval), "=a" (mask) + : "a" (v), "a" (all_f), "1" (mask) + : "a15", "memory" + ); +} + +static inline void atomic_set_mask(unsigned int mask, atomic_t *v) +{ + unsigned int vval; + + __asm__ __volatile__( + "rsil a15,"__stringify(LOCKLEVEL)"\n\t" + "l32i %0, %2, 0 \n\t" + "or %0, %0, %1 \n\t" + "s32i %0, %2, 0 \n\t" + "wsr a15, "__stringify(PS)" \n\t" + "rsync \n" + : "=&a" (vval) + : "a" (mask), "a" (v) + : "a15", "memory" + ); +} + +/* Atomic operations are already serializing */ +#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 /* __KERNEL__ */ + +#endif /* _XTENSA_ATOMIC_H */ + diff --git a/arch/xtensa/include/asm/auxvec.h b/arch/xtensa/include/asm/auxvec.h new file mode 100644 index 00000000..257dec75 --- /dev/null +++ b/arch/xtensa/include/asm/auxvec.h @@ -0,0 +1,4 @@ +#ifndef __XTENSA_AUXVEC_H +#define __XTENSA_AUXVEC_H + +#endif diff --git a/arch/xtensa/include/asm/barrier.h b/arch/xtensa/include/asm/barrier.h new file mode 100644 index 00000000..55707a80 --- /dev/null +++ b/arch/xtensa/include/asm/barrier.h @@ -0,0 +1,29 @@ +/* + * 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) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_SYSTEM_H +#define _XTENSA_SYSTEM_H + +#define smp_read_barrier_depends() do { } while(0) +#define read_barrier_depends() do { } while(0) + +#define mb() barrier() +#define rmb() mb() +#define wmb() mb() + +#ifdef CONFIG_SMP +#error smp_* not defined +#else +#define smp_mb() barrier() +#define smp_rmb() barrier() +#define smp_wmb() barrier() +#endif + +#define set_mb(var, value) do { var = value; mb(); } while (0) + +#endif /* _XTENSA_SYSTEM_H */ diff --git a/arch/xtensa/include/asm/bitops.h b/arch/xtensa/include/asm/bitops.h new file mode 100644 index 00000000..5270197d --- /dev/null +++ b/arch/xtensa/include/asm/bitops.h @@ -0,0 +1,118 @@ +/* + * include/asm-xtensa/bitops.h + * + * Atomic operations that C can't guarantee us.Useful for resource counting etc. + * + * 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) 2001 - 2007 Tensilica Inc. + */ + +#ifndef _XTENSA_BITOPS_H +#define _XTENSA_BITOPS_H + +#ifdef __KERNEL__ + +#ifndef _LINUX_BITOPS_H +#error only <linux/bitops.h> can be included directly +#endif + +#include <asm/processor.h> +#include <asm/byteorder.h> + +#ifdef CONFIG_SMP +# error SMP not supported on this architecture +#endif + +#define smp_mb__before_clear_bit() barrier() +#define smp_mb__after_clear_bit() barrier() + +#include <asm-generic/bitops/atomic.h> +#include <asm-generic/bitops/non-atomic.h> + +#if XCHAL_HAVE_NSA + +static inline unsigned long __cntlz (unsigned long x) +{ + int lz; + asm ("nsau %0, %1" : "=r" (lz) : "r" (x)); + return lz; +} + +/* + * ffz: Find first zero in word. Undefined if no zero exists. + * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1). + */ + +static inline int ffz(unsigned long x) +{ + return 31 - __cntlz(~x & -~x); +} + +/* + * __ffs: Find first bit set in word. Return 0 for bit 0 + */ + +static inline int __ffs(unsigned long x) +{ + return 31 - __cntlz(x & -x); +} + +/* + * ffs: Find first bit set in word. This is defined the same way as + * the libc and compiler builtin ffs routines, therefore + * differs in spirit from the above ffz (man ffs). + */ + +static inline int ffs(unsigned long x) +{ + return 32 - __cntlz(x & -x); +} + +/* + * fls: Find last (most-significant) bit set in word. + * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. + */ + +static inline int fls (unsigned int x) +{ + return 32 - __cntlz(x); +} + +/** + * __fls - find last (most-significant) set bit in a long word + * @word: the word to search + * + * Undefined if no set bit exists, so code should check against 0 first. + */ +static inline unsigned long __fls(unsigned long word) +{ + return 31 - __cntlz(word); +} +#else + +/* Use the generic implementation if we don't have the nsa/nsau instructions. */ + +# include <asm-generic/bitops/ffs.h> +# include <asm-generic/bitops/__ffs.h> +# include <asm-generic/bitops/ffz.h> +# include <asm-generic/bitops/fls.h> +# include <asm-generic/bitops/__fls.h> + +#endif + +#include <asm-generic/bitops/fls64.h> +#include <asm-generic/bitops/find.h> +#include <asm-generic/bitops/le.h> + +#include <asm-generic/bitops/ext2-atomic-setbit.h> + +#include <asm-generic/bitops/hweight.h> +#include <asm-generic/bitops/lock.h> +#include <asm-generic/bitops/sched.h> + +#endif /* __KERNEL__ */ + +#endif /* _XTENSA_BITOPS_H */ diff --git a/arch/xtensa/include/asm/bitsperlong.h b/arch/xtensa/include/asm/bitsperlong.h new file mode 100644 index 00000000..6dc0bb0c --- /dev/null +++ b/arch/xtensa/include/asm/bitsperlong.h @@ -0,0 +1 @@ +#include <asm-generic/bitsperlong.h> diff --git a/arch/xtensa/include/asm/bootparam.h b/arch/xtensa/include/asm/bootparam.h new file mode 100644 index 00000000..9983f2c1 --- /dev/null +++ b/arch/xtensa/include/asm/bootparam.h @@ -0,0 +1,61 @@ +/* + * include/asm-xtensa/bootparam.h + * + * Definition of the Linux/Xtensa boot parameter structure + * + * 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) 2001 - 2005 Tensilica Inc. + * + * (Concept borrowed from the 68K port) + */ + +#ifndef _XTENSA_BOOTPARAM_H +#define _XTENSA_BOOTPARAM_H + +#define BP_VERSION 0x0001 + +#define BP_TAG_COMMAND_LINE 0x1001 /* command line (0-terminated string)*/ +#define BP_TAG_INITRD 0x1002 /* ramdisk addr and size (bp_meminfo) */ +#define BP_TAG_MEMORY 0x1003 /* memory addr and size (bp_meminfo) */ +#define BP_TAG_SERIAL_BAUSRATE 0x1004 /* baud rate of current console. */ +#define BP_TAG_SERIAL_PORT 0x1005 /* serial device of current console */ + +#define BP_TAG_FIRST 0x7B0B /* first tag with a version number */ +#define BP_TAG_LAST 0x7E0B /* last tag */ + +#ifndef __ASSEMBLY__ + +/* All records are aligned to 4 bytes */ + +typedef struct bp_tag { + unsigned short id; /* tag id */ + unsigned short size; /* size of this record excluding the structure*/ + unsigned long data[0]; /* data */ +} bp_tag_t; + +typedef struct meminfo { + unsigned long type; + unsigned long start; + unsigned long end; +} meminfo_t; + +#define SYSMEM_BANKS_MAX 5 + +#define MEMORY_TYPE_CONVENTIONAL 0x1000 +#define MEMORY_TYPE_NONE 0x2000 + +typedef struct sysmem_info { + int nr_banks; + meminfo_t bank[SYSMEM_BANKS_MAX]; +} sysmem_info_t; + +extern sysmem_info_t sysmem; + +#endif +#endif + + + diff --git a/arch/xtensa/include/asm/bug.h b/arch/xtensa/include/asm/bug.h new file mode 100644 index 00000000..3e52d727 --- /dev/null +++ b/arch/xtensa/include/asm/bug.h @@ -0,0 +1,18 @@ +/* + * include/asm-xtensa/bug.h + * + * Macros to cause a 'bug' message. + * + * 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) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_BUG_H +#define _XTENSA_BUG_H + +#include <asm-generic/bug.h> + +#endif /* _XTENSA_BUG_H */ diff --git a/arch/xtensa/include/asm/bugs.h b/arch/xtensa/include/asm/bugs.h new file mode 100644 index 00000000..69b29d19 --- /dev/null +++ b/arch/xtensa/include/asm/bugs.h @@ -0,0 +1,18 @@ +/* + * include/asm-xtensa/bugs.h + * + * This is included by init/main.c to check for architecture-dependent bugs. + * + * Xtensa processors don't have any bugs. :) + * + * 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 _XTENSA_BUGS_H +#define _XTENSA_BUGS_H + +static void check_bugs(void) { } + +#endif /* _XTENSA_BUGS_H */ diff --git a/arch/xtensa/include/asm/byteorder.h b/arch/xtensa/include/asm/byteorder.h new file mode 100644 index 00000000..54eb6315 --- /dev/null +++ b/arch/xtensa/include/asm/byteorder.h @@ -0,0 +1,12 @@ +#ifndef _XTENSA_BYTEORDER_H +#define _XTENSA_BYTEORDER_H + +#ifdef __XTENSA_EL__ +#include <linux/byteorder/little_endian.h> +#elif defined(__XTENSA_EB__) +#include <linux/byteorder/big_endian.h> +#else +# error processor byte order undefined! +#endif + +#endif /* _XTENSA_BYTEORDER_H */ diff --git a/arch/xtensa/include/asm/cache.h b/arch/xtensa/include/asm/cache.h new file mode 100644 index 00000000..d2fd932f --- /dev/null +++ b/arch/xtensa/include/asm/cache.h @@ -0,0 +1,34 @@ +/* + * include/asm-xtensa/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. + * + * (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_CACHE_H +#define _XTENSA_CACHE_H + +#include <variant/core.h> + +#define L1_CACHE_SHIFT XCHAL_DCACHE_LINEWIDTH +#define L1_CACHE_BYTES XCHAL_DCACHE_LINESIZE +#define SMP_CACHE_BYTES L1_CACHE_BYTES + +#define DCACHE_WAY_SIZE (XCHAL_DCACHE_SIZE/XCHAL_DCACHE_WAYS) +#define ICACHE_WAY_SIZE (XCHAL_ICACHE_SIZE/XCHAL_ICACHE_WAYS) +#define DCACHE_WAY_SHIFT (XCHAL_DCACHE_SETWIDTH + XCHAL_DCACHE_LINEWIDTH) +#define ICACHE_WAY_SHIFT (XCHAL_ICACHE_SETWIDTH + XCHAL_ICACHE_LINEWIDTH) + +/* Maximum cache size per way. */ +#if DCACHE_WAY_SIZE >= ICACHE_WAY_SIZE +# define CACHE_WAY_SIZE DCACHE_WAY_SIZE +#else +# define CACHE_WAY_SIZE ICACHE_WAY_SIZE +#endif + +#define ARCH_DMA_MINALIGN L1_CACHE_BYTES + +#endif /* _XTENSA_CACHE_H */ diff --git a/arch/xtensa/include/asm/cacheasm.h b/arch/xtensa/include/asm/cacheasm.h new file mode 100644 index 00000000..2c20a58f --- /dev/null +++ b/arch/xtensa/include/asm/cacheasm.h @@ -0,0 +1,177 @@ +/* + * include/asm-xtensa/cacheasm.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2006 Tensilica Inc. + */ + +#include <asm/cache.h> +#include <asm/asmmacro.h> +#include <linux/stringify.h> + +/* + * Define cache functions as macros here so that they can be used + * by the kernel and boot loader. We should consider moving them to a + * library that can be linked by both. + * + * Locking + * + * ___unlock_dcache_all + * ___unlock_icache_all + * + * Flush and invaldating + * + * ___flush_invalidate_dcache_{all|range|page} + * ___flush_dcache_{all|range|page} + * ___invalidate_dcache_{all|range|page} + * ___invalidate_icache_{all|range|page} + * + */ + + .macro __loop_cache_all ar at insn size line_width + + movi \ar, 0 + + __loopi \ar, \at, \size, (4 << (\line_width)) + \insn \ar, 0 << (\line_width) + \insn \ar, 1 << (\line_width) + \insn \ar, 2 << (\line_width) + \insn \ar, 3 << (\line_width) + __endla \ar, \at, 4 << (\line_width) + + .endm + + + .macro __loop_cache_range ar as at insn line_width + + extui \at, \ar, 0, \line_width + add \as, \as, \at + + __loops \ar, \as, \at, \line_width + \insn \ar, 0 + __endla \ar, \at, (1 << (\line_width)) + + .endm + + + .macro __loop_cache_page ar at insn line_width + + __loopi \ar, \at, PAGE_SIZE, 4 << (\line_width) + \insn \ar, 0 << (\line_width) + \insn \ar, 1 << (\line_width) + \insn \ar, 2 << (\line_width) + \insn \ar, 3 << (\line_width) + __endla \ar, \at, 4 << (\line_width) + + .endm + + +#if XCHAL_DCACHE_LINE_LOCKABLE + + .macro ___unlock_dcache_all ar at + + __loop_cache_all \ar \at diu XCHAL_DCACHE_SIZE XCHAL_DCACHE_LINEWIDTH + + .endm + +#endif + +#if XCHAL_ICACHE_LINE_LOCKABLE + + .macro ___unlock_icache_all ar at + + __loop_cache_all \ar \at iiu XCHAL_ICACHE_SIZE XCHAL_ICACHE_LINEWIDTH + + .endm +#endif + + .macro ___flush_invalidate_dcache_all ar at + + __loop_cache_all \ar \at diwbi XCHAL_DCACHE_SIZE XCHAL_DCACHE_LINEWIDTH + + .endm + + + .macro ___flush_dcache_all ar at + + __loop_cache_all \ar \at diwb XCHAL_DCACHE_SIZE XCHAL_DCACHE_LINEWIDTH + + .endm + + + .macro ___invalidate_dcache_all ar at + + __loop_cache_all \ar \at dii __stringify(DCACHE_WAY_SIZE) \ + XCHAL_DCACHE_LINEWIDTH + + .endm + + + .macro ___invalidate_icache_all ar at + + __loop_cache_all \ar \at iii __stringify(ICACHE_WAY_SIZE) \ + XCHAL_ICACHE_LINEWIDTH + + .endm + + + + .macro ___flush_invalidate_dcache_range ar as at + + __loop_cache_range \ar \as \at dhwbi XCHAL_DCACHE_LINEWIDTH + + .endm + + + .macro ___flush_dcache_range ar as at + + __loop_cache_range \ar \as \at dhwb XCHAL_DCACHE_LINEWIDTH + + .endm + + + .macro ___invalidate_dcache_range ar as at + + __loop_cache_range \ar \as \at dhi XCHAL_DCACHE_LINEWIDTH + + .endm + + + .macro ___invalidate_icache_range ar as at + + __loop_cache_range \ar \as \at ihi XCHAL_ICACHE_LINEWIDTH + + .endm + + + + .macro ___flush_invalidate_dcache_page ar as + + __loop_cache_page \ar \as dhwbi XCHAL_DCACHE_LINEWIDTH + + .endm + + + .macro ___flush_dcache_page ar as + + __loop_cache_page \ar \as dhwb XCHAL_DCACHE_LINEWIDTH + + .endm + + + .macro ___invalidate_dcache_page ar as + + __loop_cache_page \ar \as dhi XCHAL_DCACHE_LINEWIDTH + + .endm + + + .macro ___invalidate_icache_page ar as + + __loop_cache_page \ar \as ihi XCHAL_ICACHE_LINEWIDTH + + .endm + diff --git a/arch/xtensa/include/asm/cacheflush.h b/arch/xtensa/include/asm/cacheflush.h new file mode 100644 index 00000000..376cd9d5 --- /dev/null +++ b/arch/xtensa/include/asm/cacheflush.h @@ -0,0 +1,256 @@ +/* + * include/asm-xtensa/cacheflush.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. + * + * (C) 2001 - 2007 Tensilica Inc. + */ + +#ifndef _XTENSA_CACHEFLUSH_H +#define _XTENSA_CACHEFLUSH_H + +#ifdef __KERNEL__ + +#include <linux/mm.h> +#include <asm/processor.h> +#include <asm/page.h> + +/* + * Lo-level routines for cache flushing. + * + * invalidate data or instruction cache: + * + * __invalidate_icache_all() + * __invalidate_icache_page(adr) + * __invalidate_dcache_page(adr) + * __invalidate_icache_range(from,size) + * __invalidate_dcache_range(from,size) + * + * flush data cache: + * + * __flush_dcache_page(adr) + * + * flush and invalidate data cache: + * + * __flush_invalidate_dcache_all() + * __flush_invalidate_dcache_page(adr) + * __flush_invalidate_dcache_range(from,size) + * + * specials for cache aliasing: + * + * __flush_invalidate_dcache_page_alias(vaddr,paddr) + * __invalidate_icache_page_alias(vaddr,paddr) + */ + +extern void __invalidate_dcache_all(void); +extern void __invalidate_icache_all(void); +extern void __invalidate_dcache_page(unsigned long); +extern void __invalidate_icache_page(unsigned long); +extern void __invalidate_icache_range(unsigned long, unsigned long); +extern void __invalidate_dcache_range(unsigned long, unsigned long); + + +#if XCHAL_DCACHE_IS_WRITEBACK +extern void __flush_invalidate_dcache_all(void); +extern void __flush_dcache_page(unsigned long); +extern void __flush_dcache_range(unsigned long, unsigned long); +extern void __flush_invalidate_dcache_page(unsigned long); +extern void __flush_invalidate_dcache_range(unsigned long, unsigned long); +#else +# define __flush_dcache_range(p,s) do { } while(0) +# define __flush_dcache_page(p) do { } while(0) +# define __flush_invalidate_dcache_page(p) __invalidate_dcache_page(p) +# define __flush_invalidate_dcache_range(p,s) __invalidate_dcache_range(p,s) +#endif + +#if defined(CONFIG_MMU) && (DCACHE_WAY_SIZE > PAGE_SIZE) +extern void __flush_invalidate_dcache_page_alias(unsigned long, unsigned long); +#else +static inline void __flush_invalidate_dcache_page_alias(unsigned long virt, + unsigned long phys) { } +#endif +#if defined(CONFIG_MMU) && (ICACHE_WAY_SIZE > PAGE_SIZE) +extern void __invalidate_icache_page_alias(unsigned long, unsigned long); +#else +static inline void __invalidate_icache_page_alias(unsigned long virt, + unsigned long phys) { } +#endif + +/* + * We have physically tagged caches - nothing to do here - + * unless we have cache aliasing. + * + * Pages can get remapped. Because this might change the 'color' of that page, + * we have to flush the cache before the PTE is changed. + * (see also Documentation/cachetlb.txt) + */ + +#if (DCACHE_WAY_SIZE > PAGE_SIZE) + +#define flush_cache_all() \ + do { \ + __flush_invalidate_dcache_all(); \ + __invalidate_icache_all(); \ + } while (0) + +#define flush_cache_mm(mm) flush_cache_all() +#define flush_cache_dup_mm(mm) flush_cache_mm(mm) + +#define flush_cache_vmap(start,end) flush_cache_all() +#define flush_cache_vunmap(start,end) flush_cache_all() + +#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1 +extern void flush_dcache_page(struct page*); +extern void flush_cache_range(struct vm_area_struct*, ulong, ulong); +extern void flush_cache_page(struct vm_area_struct*, unsigned long, unsigned long); + +#else + +#define flush_cache_all() do { } while (0) +#define flush_cache_mm(mm) do { } while (0) +#define flush_cache_dup_mm(mm) do { } while (0) + +#define flush_cache_vmap(start,end) do { } while (0) +#define flush_cache_vunmap(start,end) do { } while (0) + +#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0 +#define flush_dcache_page(page) do { } while (0) + +#define flush_cache_page(vma,addr,pfn) do { } while (0) +#define flush_cache_range(vma,start,end) do { } while (0) + +#endif + +/* Ensure consistency between data and instruction cache. */ +#define flush_icache_range(start,end) \ + do { \ + __flush_dcache_range(start, (end) - (start)); \ + __invalidate_icache_range(start,(end) - (start)); \ + } while (0) + +/* This is not required, see Documentation/cachetlb.txt */ +#define flush_icache_page(vma,page) do { } while (0) + +#define flush_dcache_mmap_lock(mapping) do { } while (0) +#define flush_dcache_mmap_unlock(mapping) do { } while (0) + +#if (DCACHE_WAY_SIZE > PAGE_SIZE) + +extern void copy_to_user_page(struct vm_area_struct*, struct page*, + unsigned long, void*, const void*, unsigned long); +extern void copy_from_user_page(struct vm_area_struct*, struct page*, + unsigned long, void*, const void*, unsigned long); + +#else + +#define copy_to_user_page(vma, page, vaddr, dst, src, len) \ + do { \ + memcpy(dst, src, len); \ + __flush_dcache_range((unsigned long) dst, len); \ + __invalidate_icache_range((unsigned long) dst, len); \ + } while (0) + +#define copy_from_user_page(vma, page, vaddr, dst, src, len) \ + memcpy(dst, src, len) + +#endif + +#define XTENSA_CACHEBLK_LOG2 29 +#define XTENSA_CACHEBLK_SIZE (1 << XTENSA_CACHEBLK_LOG2) +#define XTENSA_CACHEBLK_MASK (7 << XTENSA_CACHEBLK_LOG2) + +#if XCHAL_HAVE_CACHEATTR +static inline u32 xtensa_get_cacheattr(void) +{ + u32 r; + asm volatile(" rsr %0, CACHEATTR" : "=a"(r)); + return r; +} + +static inline u32 xtensa_get_dtlb1(u32 addr) +{ + u32 r = addr & XTENSA_CACHEBLK_MASK; + return r | ((xtensa_get_cacheattr() >> (r >> (XTENSA_CACHEBLK_LOG2-2))) + & 0xF); +} +#else +static inline u32 xtensa_get_dtlb1(u32 addr) +{ + u32 r; + asm volatile(" rdtlb1 %0, %1" : "=a"(r) : "a"(addr)); + asm volatile(" dsync"); + return r; +} + +static inline u32 xtensa_get_cacheattr(void) +{ + u32 r = 0; + u32 a = 0; + do { + a -= XTENSA_CACHEBLK_SIZE; + r = (r << 4) | (xtensa_get_dtlb1(a) & 0xF); + } while (a); + return r; +} +#endif + +static inline int xtensa_need_flush_dma_source(u32 addr) +{ + return (xtensa_get_dtlb1(addr) & ((1 << XCHAL_CA_BITS) - 1)) >= 4; +} + +static inline int xtensa_need_invalidate_dma_destination(u32 addr) +{ + return (xtensa_get_dtlb1(addr) & ((1 << XCHAL_CA_BITS) - 1)) != 2; +} + +static inline void flush_dcache_unaligned(u32 addr, u32 size) +{ + u32 cnt; + if (size) { + cnt = (size + ((XCHAL_DCACHE_LINESIZE - 1) & addr) + + XCHAL_DCACHE_LINESIZE - 1) / XCHAL_DCACHE_LINESIZE; + while (cnt--) { + asm volatile(" dhwb %0, 0" : : "a"(addr)); + addr += XCHAL_DCACHE_LINESIZE; + } + asm volatile(" dsync"); + } +} + +static inline void invalidate_dcache_unaligned(u32 addr, u32 size) +{ + int cnt; + if (size) { + asm volatile(" dhwbi %0, 0 ;" : : "a"(addr)); + cnt = (size + ((XCHAL_DCACHE_LINESIZE - 1) & addr) + - XCHAL_DCACHE_LINESIZE - 1) / XCHAL_DCACHE_LINESIZE; + while (cnt-- > 0) { + asm volatile(" dhi %0, %1" : : "a"(addr), + "n"(XCHAL_DCACHE_LINESIZE)); + addr += XCHAL_DCACHE_LINESIZE; + } + asm volatile(" dhwbi %0, %1" : : "a"(addr), + "n"(XCHAL_DCACHE_LINESIZE)); + asm volatile(" dsync"); + } +} + +static inline void flush_invalidate_dcache_unaligned(u32 addr, u32 size) +{ + u32 cnt; + if (size) { + cnt = (size + ((XCHAL_DCACHE_LINESIZE - 1) & addr) + + XCHAL_DCACHE_LINESIZE - 1) / XCHAL_DCACHE_LINESIZE; + while (cnt--) { + asm volatile(" dhwbi %0, 0" : : "a"(addr)); + addr += XCHAL_DCACHE_LINESIZE; + } + asm volatile(" dsync"); + } +} + +#endif /* __KERNEL__ */ +#endif /* _XTENSA_CACHEFLUSH_H */ diff --git a/arch/xtensa/include/asm/checksum.h b/arch/xtensa/include/asm/checksum.h new file mode 100644 index 00000000..e4d831a3 --- /dev/null +++ b/arch/xtensa/include/asm/checksum.h @@ -0,0 +1,252 @@ +/* + * include/asm-xtensa/checksum.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_CHECKSUM_H +#define _XTENSA_CHECKSUM_H + +#include <linux/in6.h> +#include <variant/core.h> + +/* + * 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 __wsum csum_partial(const void *buff, int len, __wsum sum); + +/* + * the same as csum_partial, but copies from src while it + * checksums, and handles user-space pointer exceptions correctly, when needed. + * + * here even more important to align src and dst on a 32-bit (or even + * better 64-bit) boundary + */ + +asmlinkage __wsum csum_partial_copy_generic(const void *src, void *dst, int len, __wsum sum, + int *src_err_ptr, int *dst_err_ptr); + +/* + * 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 access_ok(). + */ +static inline +__wsum csum_partial_copy_nocheck(const void *src, void *dst, + int len, __wsum sum) +{ + return csum_partial_copy_generic(src, dst, len, sum, NULL, NULL); +} + +static inline +__wsum csum_partial_copy_from_user(const void __user *src, void *dst, + int len, __wsum sum, int *err_ptr) +{ + return csum_partial_copy_generic((__force const void *)src, dst, + len, sum, err_ptr, NULL); +} + +/* + * Fold a partial checksum + */ + +static __inline__ __sum16 csum_fold(__wsum sum) +{ + unsigned int __dummy; + __asm__("extui %1, %0, 16, 16\n\t" + "extui %0 ,%0, 0, 16\n\t" + "add %0, %0, %1\n\t" + "slli %1, %0, 16\n\t" + "add %0, %0, %1\n\t" + "extui %0, %0, 16, 16\n\t" + "neg %0, %0\n\t" + "addi %0, %0, -1\n\t" + "extui %0, %0, 0, 16\n\t" + : "=r" (sum), "=&r" (__dummy) + : "0" (sum)); + return (__force __sum16)sum; +} + +/* + * This is a version of ip_compute_csum() optimized for IP headers, + * which always checksum on 4 octet boundaries. + */ +static __inline__ __sum16 ip_fast_csum(const void *iph, unsigned int ihl) +{ + unsigned int sum, tmp, endaddr; + + __asm__ __volatile__( + "sub %0, %0, %0\n\t" +#if XCHAL_HAVE_LOOPS + "loopgtz %2, 2f\n\t" +#else + "beqz %2, 2f\n\t" + "slli %4, %2, 2\n\t" + "add %4, %4, %1\n\t" + "0:\t" +#endif + "l32i %3, %1, 0\n\t" + "add %0, %0, %3\n\t" + "bgeu %0, %3, 1f\n\t" + "addi %0, %0, 1\n\t" + "1:\t" + "addi %1, %1, 4\n\t" +#if !XCHAL_HAVE_LOOPS + "blt %1, %4, 0b\n\t" +#endif + "2:\t" + /* Since the input registers which are loaded with iph and ihl + are modified, we must also specify them as outputs, or gcc + will assume they contain their original values. */ + : "=r" (sum), "=r" (iph), "=r" (ihl), "=&r" (tmp), "=&r" (endaddr) + : "1" (iph), "2" (ihl) + : "memory"); + + return csum_fold(sum); +} + +static __inline__ __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr, + unsigned short len, + unsigned short proto, + __wsum sum) +{ + +#ifdef __XTENSA_EL__ + unsigned long len_proto = (len + proto) << 8; +#elif defined(__XTENSA_EB__) + unsigned long len_proto = len + proto; +#else +# error processor byte order undefined! +#endif + __asm__("add %0, %0, %1\n\t" + "bgeu %0, %1, 1f\n\t" + "addi %0, %0, 1\n\t" + "1:\t" + "add %0, %0, %2\n\t" + "bgeu %0, %2, 1f\n\t" + "addi %0, %0, 1\n\t" + "1:\t" + "add %0, %0, %3\n\t" + "bgeu %0, %3, 1f\n\t" + "addi %0, %0, 1\n\t" + "1:\t" + : "=r" (sum), "=r" (len_proto) + : "r" (daddr), "r" (saddr), "1" (len_proto), "0" (sum)); + return sum; +} + +/* + * computes the checksum of the TCP/UDP pseudo-header + * returns a 16-bit checksum, already complemented + */ +static __inline__ __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, + unsigned short len, + unsigned short proto, + __wsum 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__ __sum16 ip_compute_csum(const void *buff, int len) +{ + return csum_fold (csum_partial(buff, len, 0)); +} + +#define _HAVE_ARCH_IPV6_CSUM +static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr, + const struct in6_addr *daddr, + __u32 len, unsigned short proto, + __wsum sum) +{ + unsigned int __dummy; + __asm__("l32i %1, %2, 0\n\t" + "add %0, %0, %1\n\t" + "bgeu %0, %1, 1f\n\t" + "addi %0, %0, 1\n\t" + "1:\t" + "l32i %1, %2, 4\n\t" + "add %0, %0, %1\n\t" + "bgeu %0, %1, 1f\n\t" + "addi %0, %0, 1\n\t" + "1:\t" + "l32i %1, %2, 8\n\t" + "add %0, %0, %1\n\t" + "bgeu %0, %1, 1f\n\t" + "addi %0, %0, 1\n\t" + "1:\t" + "l32i %1, %2, 12\n\t" + "add %0, %0, %1\n\t" + "bgeu %0, %1, 1f\n\t" + "addi %0, %0, 1\n\t" + "1:\t" + "l32i %1, %3, 0\n\t" + "add %0, %0, %1\n\t" + "bgeu %0, %1, 1f\n\t" + "addi %0, %0, 1\n\t" + "1:\t" + "l32i %1, %3, 4\n\t" + "add %0, %0, %1\n\t" + "bgeu %0, %1, 1f\n\t" + "addi %0, %0, 1\n\t" + "1:\t" + "l32i %1, %3, 8\n\t" + "add %0, %0, %1\n\t" + "bgeu %0, %1, 1f\n\t" + "addi %0, %0, 1\n\t" + "1:\t" + "l32i %1, %3, 12\n\t" + "add %0, %0, %1\n\t" + "bgeu %0, %1, 1f\n\t" + "addi %0, %0, 1\n\t" + "1:\t" + "add %0, %0, %4\n\t" + "bgeu %0, %4, 1f\n\t" + "addi %0, %0, 1\n\t" + "1:\t" + "add %0, %0, %5\n\t" + "bgeu %0, %5, 1f\n\t" + "addi %0, %0, 1\n\t" + "1:\t" + : "=r" (sum), "=&r" (__dummy) + : "r" (saddr), "r" (daddr), + "r" (htonl(len)), "r" (htonl(proto)), "0" (sum) + : "memory"); + + return csum_fold(sum); +} + +/* + * Copy and checksum to user + */ +#define HAVE_CSUM_COPY_USER +static __inline__ __wsum csum_and_copy_to_user(const void *src, void __user *dst, + int len, __wsum sum, int *err_ptr) +{ + if (access_ok(VERIFY_WRITE, dst, len)) + return csum_partial_copy_generic(src, dst, len, sum, NULL, err_ptr); + + if (len) + *err_ptr = -EFAULT; + + return (__force __wsum)-1; /* invalid checksum */ +} +#endif diff --git a/arch/xtensa/include/asm/cmpxchg.h b/arch/xtensa/include/asm/cmpxchg.h new file mode 100644 index 00000000..e3214906 --- /dev/null +++ b/arch/xtensa/include/asm/cmpxchg.h @@ -0,0 +1,131 @@ +/* + * Atomic xchg and cmpxchg operations. + * + * 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) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_CMPXCHG_H +#define _XTENSA_CMPXCHG_H + +#ifndef __ASSEMBLY__ + +#include <linux/stringify.h> + +/* + * cmpxchg + */ + +static inline unsigned long +__cmpxchg_u32(volatile int *p, int old, int new) +{ + __asm__ __volatile__("rsil a15, "__stringify(LOCKLEVEL)"\n\t" + "l32i %0, %1, 0 \n\t" + "bne %0, %2, 1f \n\t" + "s32i %3, %1, 0 \n\t" + "1: \n\t" + "wsr a15, "__stringify(PS)" \n\t" + "rsync \n\t" + : "=&a" (old) + : "a" (p), "a" (old), "r" (new) + : "a15", "memory"); + return old; +} +/* This function doesn't exist, so you'll get a linker error + * if something tries to do an invalid cmpxchg(). */ + +extern void __cmpxchg_called_with_bad_pointer(void); + +static __inline__ unsigned long +__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) +{ + switch (size) { + case 4: return __cmpxchg_u32(ptr, old, new); + default: __cmpxchg_called_with_bad_pointer(); + return old; + } +} + +#define cmpxchg(ptr,o,n) \ + ({ __typeof__(*(ptr)) _o_ = (o); \ + __typeof__(*(ptr)) _n_ = (n); \ + (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_, \ + (unsigned long)_n_, sizeof (*(ptr))); \ + }) + +#include <asm-generic/cmpxchg-local.h> + +static inline unsigned long __cmpxchg_local(volatile void *ptr, + unsigned long old, + unsigned long new, int size) +{ + switch (size) { + case 4: + return __cmpxchg_u32(ptr, old, new); + default: + return __cmpxchg_local_generic(ptr, old, new, size); + } + + return old; +} + +/* + * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make + * them available. + */ +#define cmpxchg_local(ptr, o, n) \ + ((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\ + (unsigned long)(n), sizeof(*(ptr)))) +#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n)) + +/* + * xchg_u32 + * + * Note that a15 is used here because the register allocation + * done by the compiler is not guaranteed and a window overflow + * may not occur between the rsil and wsr instructions. By using + * a15 in the rsil, the machine is guaranteed to be in a state + * where no register reference will cause an overflow. + */ + +static inline unsigned long xchg_u32(volatile int * m, unsigned long val) +{ + unsigned long tmp; + __asm__ __volatile__("rsil a15, "__stringify(LOCKLEVEL)"\n\t" + "l32i %0, %1, 0 \n\t" + "s32i %2, %1, 0 \n\t" + "wsr a15, "__stringify(PS)" \n\t" + "rsync \n\t" + : "=&a" (tmp) + : "a" (m), "a" (val) + : "a15", "memory"); + return tmp; +} + +#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) + +/* + * This only works if the compiler isn't horribly bad at optimizing. + * gcc-2.5.8 reportedly can't handle this, but I define that one to + * be dead anyway. + */ + +extern void __xchg_called_with_bad_pointer(void); + +static __inline__ unsigned long +__xchg(unsigned long x, volatile void * ptr, int size) +{ + switch (size) { + case 4: + return xchg_u32(ptr, x); + } + __xchg_called_with_bad_pointer(); + return x; +} + +#endif /* __ASSEMBLY__ */ + +#endif /* _XTENSA_CMPXCHG_H */ diff --git a/arch/xtensa/include/asm/coprocessor.h b/arch/xtensa/include/asm/coprocessor.h new file mode 100644 index 00000000..75c94a16 --- /dev/null +++ b/arch/xtensa/include/asm/coprocessor.h @@ -0,0 +1,178 @@ +/* + * include/asm-xtensa/coprocessor.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2003 - 2007 Tensilica Inc. + */ + + +#ifndef _XTENSA_COPROCESSOR_H +#define _XTENSA_COPROCESSOR_H + +#include <linux/stringify.h> +#include <variant/core.h> +#include <variant/tie.h> +#include <asm/types.h> + +#ifdef __ASSEMBLY__ +# include <variant/tie-asm.h> + +.macro xchal_sa_start a b + .set .Lxchal_pofs_, 0 + .set .Lxchal_ofs_, 0 +.endm + +.macro xchal_sa_align ptr minofs maxofs ofsalign totalign + .set .Lxchal_ofs_, .Lxchal_ofs_ + .Lxchal_pofs_ + \totalign - 1 + .set .Lxchal_ofs_, (.Lxchal_ofs_ & -\totalign) - .Lxchal_pofs_ +.endm + +#define _SELECT ( XTHAL_SAS_TIE | XTHAL_SAS_OPT \ + | XTHAL_SAS_CC \ + | XTHAL_SAS_CALR | XTHAL_SAS_CALE ) + +.macro save_xtregs_opt ptr clb at1 at2 at3 at4 offset + .if XTREGS_OPT_SIZE > 0 + addi \clb, \ptr, \offset + xchal_ncp_store \clb \at1 \at2 \at3 \at4 select=_SELECT + .endif +.endm + +.macro load_xtregs_opt ptr clb at1 at2 at3 at4 offset + .if XTREGS_OPT_SIZE > 0 + addi \clb, \ptr, \offset + xchal_ncp_load \clb \at1 \at2 \at3 \at4 select=_SELECT + .endif +.endm +#undef _SELECT + +#define _SELECT ( XTHAL_SAS_TIE | XTHAL_SAS_OPT \ + | XTHAL_SAS_NOCC \ + | XTHAL_SAS_CALR | XTHAL_SAS_CALE | XTHAL_SAS_GLOB ) + +.macro save_xtregs_user ptr clb at1 at2 at3 at4 offset + .if XTREGS_USER_SIZE > 0 + addi \clb, \ptr, \offset + xchal_ncp_store \clb \at1 \at2 \at3 \at4 select=_SELECT + .endif +.endm + +.macro load_xtregs_user ptr clb at1 at2 at3 at4 offset + .if XTREGS_USER_SIZE > 0 + addi \clb, \ptr, \offset + xchal_ncp_load \clb \at1 \at2 \at3 \at4 select=_SELECT + .endif +.endm +#undef _SELECT + + + +#endif /* __ASSEMBLY__ */ + +/* + * XTENSA_HAVE_COPROCESSOR(x) returns 1 if coprocessor x is configured. + * + * XTENSA_HAVE_IO_PORT(x) returns 1 if io-port x is configured. + * + */ + +#define XTENSA_HAVE_COPROCESSOR(x) \ + ((XCHAL_CP_MASK ^ XCHAL_CP_PORT_MASK) & (1 << (x))) +#define XTENSA_HAVE_COPROCESSORS \ + (XCHAL_CP_MASK ^ XCHAL_CP_PORT_MASK) +#define XTENSA_HAVE_IO_PORT(x) \ + (XCHAL_CP_PORT_MASK & (1 << (x))) +#define XTENSA_HAVE_IO_PORTS \ + XCHAL_CP_PORT_MASK + +#ifndef __ASSEMBLY__ + + +#if XCHAL_HAVE_CP + +#define RSR_CPENABLE(x) do { \ + __asm__ __volatile__("rsr %0," __stringify(CPENABLE) : "=a" (x)); \ + } while(0); +#define WSR_CPENABLE(x) do { \ + __asm__ __volatile__("wsr %0," __stringify(CPENABLE) "; rsync" \ + :: "a" (x)); \ + } while(0); + +#endif /* XCHAL_HAVE_CP */ + + +/* + * Additional registers. + * We define three types of additional registers: + * ext: extra registers that are used by the compiler + * cpn: optional registers that can be used by a user application + * cpX: coprocessor registers that can only be used if the corresponding + * CPENABLE bit is set. + */ + +#define XCHAL_SA_REG(list,cc,abi,type,y,name,z,align,size,...) \ + __REG ## list (cc, abi, type, name, size, align) + +#define __REG0(cc,abi,t,name,s,a) __REG0_ ## cc (abi,name) +#define __REG1(cc,abi,t,name,s,a) __REG1_ ## cc (name) +#define __REG2(cc,abi,type,...) __REG2_ ## type (__VA_ARGS__) + +#define __REG0_0(abi,name) +#define __REG0_1(abi,name) __REG0_1 ## abi (name) +#define __REG0_10(name) __u32 name; +#define __REG0_11(name) __u32 name; +#define __REG0_12(name) + +#define __REG1_0(name) __u32 name; +#define __REG1_1(name) + +#define __REG2_0(n,s,a) __u32 name; +#define __REG2_1(n,s,a) unsigned char n[s] __attribute__ ((aligned(a))); +#define __REG2_2(n,s,a) unsigned char n[s] __attribute__ ((aligned(a))); + +typedef struct { XCHAL_NCP_SA_LIST(0) } xtregs_opt_t + __attribute__ ((aligned (XCHAL_NCP_SA_ALIGN))); +typedef struct { XCHAL_NCP_SA_LIST(1) } xtregs_user_t + __attribute__ ((aligned (XCHAL_NCP_SA_ALIGN))); + +#if XTENSA_HAVE_COPROCESSORS + +typedef struct { XCHAL_CP0_SA_LIST(2) } xtregs_cp0_t + __attribute__ ((aligned (XCHAL_CP0_SA_ALIGN))); +typedef struct { XCHAL_CP1_SA_LIST(2) } xtregs_cp1_t + __attribute__ ((aligned (XCHAL_CP1_SA_ALIGN))); +typedef struct { XCHAL_CP2_SA_LIST(2) } xtregs_cp2_t + __attribute__ ((aligned (XCHAL_CP2_SA_ALIGN))); +typedef struct { XCHAL_CP3_SA_LIST(2) } xtregs_cp3_t + __attribute__ ((aligned (XCHAL_CP3_SA_ALIGN))); +typedef struct { XCHAL_CP4_SA_LIST(2) } xtregs_cp4_t + __attribute__ ((aligned (XCHAL_CP4_SA_ALIGN))); +typedef struct { XCHAL_CP5_SA_LIST(2) } xtregs_cp5_t + __attribute__ ((aligned (XCHAL_CP5_SA_ALIGN))); +typedef struct { XCHAL_CP6_SA_LIST(2) } xtregs_cp6_t + __attribute__ ((aligned (XCHAL_CP6_SA_ALIGN))); +typedef struct { XCHAL_CP7_SA_LIST(2) } xtregs_cp7_t + __attribute__ ((aligned (XCHAL_CP7_SA_ALIGN))); + +extern struct thread_info* coprocessor_owner[XCHAL_CP_MAX]; +extern void coprocessor_save(void*, int); +extern void coprocessor_load(void*, int); +extern void coprocessor_flush(struct thread_info*, int); +extern void coprocessor_restore(struct thread_info*, int); + +extern void coprocessor_release_all(struct thread_info*); +extern void coprocessor_flush_all(struct thread_info*); + +static inline void coprocessor_clear_cpenable(void) +{ + unsigned long i = 0; + WSR_CPENABLE(i); +} + +#endif /* XTENSA_HAVE_COPROCESSORS */ + +#endif /* !__ASSEMBLY__ */ +#endif /* _XTENSA_COPROCESSOR_H */ diff --git a/arch/xtensa/include/asm/cpumask.h b/arch/xtensa/include/asm/cpumask.h new file mode 100644 index 00000000..ebeede39 --- /dev/null +++ b/arch/xtensa/include/asm/cpumask.h @@ -0,0 +1,16 @@ +/* + * include/asm-xtensa/cpumask.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_CPUMASK_H +#define _XTENSA_CPUMASK_H + +#include <asm-generic/cpumask.h> + +#endif /* _XTENSA_CPUMASK_H */ diff --git a/arch/xtensa/include/asm/cputime.h b/arch/xtensa/include/asm/cputime.h new file mode 100644 index 00000000..a7fb864a --- /dev/null +++ b/arch/xtensa/include/asm/cputime.h @@ -0,0 +1,6 @@ +#ifndef _XTENSA_CPUTIME_H +#define _XTENSA_CPUTIME_H + +#include <asm-generic/cputime.h> + +#endif /* _XTENSA_CPUTIME_H */ diff --git a/arch/xtensa/include/asm/current.h b/arch/xtensa/include/asm/current.h new file mode 100644 index 00000000..8d1eb5d7 --- /dev/null +++ b/arch/xtensa/include/asm/current.h @@ -0,0 +1,38 @@ +/* + * include/asm-xtensa/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. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_CURRENT_H +#define _XTENSA_CURRENT_H + +#ifndef __ASSEMBLY__ + +#include <linux/thread_info.h> + +struct task_struct; + +static inline struct task_struct *get_current(void) +{ + return current_thread_info()->task; +} + +#define current get_current() + +#else + +#define CURRENT_SHIFT 13 + +#define GET_CURRENT(reg,sp) \ + GET_THREAD_INFO(reg,sp); \ + l32i reg, reg, TI_TASK \ + +#endif + + +#endif /* XTENSA_CURRENT_H */ diff --git a/arch/xtensa/include/asm/delay.h b/arch/xtensa/include/asm/delay.h new file mode 100644 index 00000000..e1d8c9e0 --- /dev/null +++ b/arch/xtensa/include/asm/delay.h @@ -0,0 +1,49 @@ +/* + * include/asm-xtensa/delay.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + * + */ + +#ifndef _XTENSA_DELAY_H +#define _XTENSA_DELAY_H + +#include <asm/processor.h> +#include <asm/param.h> + +extern unsigned long loops_per_jiffy; + +static inline void __delay(unsigned long loops) +{ + /* 2 cycles per loop. */ + __asm__ __volatile__ ("1: addi %0, %0, -2; bgeui %0, 2, 1b" + : "=r" (loops) : "0" (loops)); +} + +static __inline__ u32 xtensa_get_ccount(void) +{ + u32 ccount; + asm volatile ("rsr %0, 234; # CCOUNT\n" : "=r" (ccount)); + return ccount; +} + +/* For SMP/NUMA systems, change boot_cpu_data to something like + * local_cpu_data->... where local_cpu_data points to the current + * cpu. */ + +static __inline__ void udelay (unsigned long usecs) +{ + unsigned long start = xtensa_get_ccount(); + unsigned long cycles = usecs * (loops_per_jiffy / (1000000UL / HZ)); + + /* Note: all variables are unsigned (can wrap around)! */ + while (((unsigned long)xtensa_get_ccount()) - start < cycles) + ; +} + +#endif + diff --git a/arch/xtensa/include/asm/device.h b/arch/xtensa/include/asm/device.h new file mode 100644 index 00000000..d8f9872b --- /dev/null +++ b/arch/xtensa/include/asm/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include <asm-generic/device.h> + diff --git a/arch/xtensa/include/asm/div64.h b/arch/xtensa/include/asm/div64.h new file mode 100644 index 00000000..f35678cb --- /dev/null +++ b/arch/xtensa/include/asm/div64.h @@ -0,0 +1,16 @@ +/* + * include/asm-xtensa/div64.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001 - 2007 Tensilica Inc. + */ + +#ifndef _XTENSA_DIV64_H +#define _XTENSA_DIV64_H + +#include <asm-generic/div64.h> + +#endif /* _XTENSA_DIV64_H */ diff --git a/arch/xtensa/include/asm/dma-mapping.h b/arch/xtensa/include/asm/dma-mapping.h new file mode 100644 index 00000000..492c9579 --- /dev/null +++ b/arch/xtensa/include/asm/dma-mapping.h @@ -0,0 +1,171 @@ +/* + * include/asm-xtensa/dma-mapping.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2003 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_DMA_MAPPING_H +#define _XTENSA_DMA_MAPPING_H + +#include <asm/cache.h> +#include <asm/io.h> +#include <linux/mm.h> +#include <linux/scatterlist.h> + +/* + * DMA-consistent mapping functions. + */ + +extern void *consistent_alloc(int, size_t, dma_addr_t, unsigned long); +extern void consistent_free(void*, size_t, dma_addr_t); +extern void consistent_sync(void*, size_t, int); + +#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) +#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) + +void *dma_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t flag); + +void dma_free_coherent(struct device *dev, size_t size, + void *vaddr, dma_addr_t dma_handle); + +static inline dma_addr_t +dma_map_single(struct device *dev, void *ptr, size_t size, + enum dma_data_direction direction) +{ + BUG_ON(direction == DMA_NONE); + consistent_sync(ptr, size, direction); + return virt_to_phys(ptr); +} + +static inline void +dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, + enum dma_data_direction direction) +{ + BUG_ON(direction == DMA_NONE); +} + +static inline int +dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction direction) +{ + int i; + + BUG_ON(direction == DMA_NONE); + + for (i = 0; i < nents; i++, sg++ ) { + BUG_ON(!sg_page(sg)); + + sg->dma_address = sg_phys(sg); + consistent_sync(sg_virt(sg), sg->length, direction); + } + + return nents; +} + +static inline dma_addr_t +dma_map_page(struct device *dev, struct page *page, unsigned long offset, + size_t size, enum dma_data_direction direction) +{ + BUG_ON(direction == DMA_NONE); + return (dma_addr_t)(page_to_pfn(page)) * PAGE_SIZE + offset; +} + +static inline void +dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, + enum dma_data_direction direction) +{ + BUG_ON(direction == DMA_NONE); +} + + +static inline void +dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, + enum dma_data_direction direction) +{ + BUG_ON(direction == DMA_NONE); +} + +static inline void +dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction) +{ + consistent_sync((void *)bus_to_virt(dma_handle), size, direction); +} + +static inline void +dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction) +{ + consistent_sync((void *)bus_to_virt(dma_handle), size, direction); +} + +static inline void +dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle, + unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + + consistent_sync((void *)bus_to_virt(dma_handle)+offset,size,direction); +} + +static inline void +dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle, + unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + + consistent_sync((void *)bus_to_virt(dma_handle)+offset,size,direction); +} +static inline void +dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, + enum dma_data_direction dir) +{ + int i; + for (i = 0; i < nelems; i++, sg++) + consistent_sync(sg_virt(sg), sg->length, dir); +} + +static inline void +dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, + enum dma_data_direction dir) +{ + int i; + for (i = 0; i < nelems; i++, sg++) + consistent_sync(sg_virt(sg), sg->length, dir); +} +static inline int +dma_mapping_error(struct device *dev, dma_addr_t dma_addr) +{ + return 0; +} + +static inline int +dma_supported(struct device *dev, u64 mask) +{ + return 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_cache_sync(struct device *dev, void *vaddr, size_t size, + enum dma_data_direction direction) +{ + consistent_sync(vaddr, size, direction); +} + +#endif /* _XTENSA_DMA_MAPPING_H */ diff --git a/arch/xtensa/include/asm/dma.h b/arch/xtensa/include/asm/dma.h new file mode 100644 index 00000000..bb099a37 --- /dev/null +++ b/arch/xtensa/include/asm/dma.h @@ -0,0 +1,62 @@ +/* + * include/asm-xtensa/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. + * + * Copyright (C) 2003 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_DMA_H +#define _XTENSA_DMA_H + +#include <asm/io.h> /* need byte IO */ + +/* + * This is only to be defined if we have PC-like DMA. + * By default this is not true on an Xtensa processor, + * however on boards with a PCI bus, such functionality + * might be emulated externally. + * + * NOTE: there still exists driver code that assumes + * this is defined, eg. drivers/sound/soundcard.c (as of 2.4). + */ +#define MAX_DMA_CHANNELS 8 + +/* + * The maximum virtual address to which DMA transfers + * can be performed on this platform. + * + * NOTE: This is board (platform) specific, not processor-specific! + * + * NOTE: This assumes DMA transfers can only be performed on + * the section of physical memory contiguously mapped in virtual + * space for the kernel. For the Xtensa architecture, this + * means the maximum possible size of this DMA area is + * the size of the statically mapped kernel segment + * (XCHAL_KSEG_{CACHED,BYPASS}_SIZE), ie. 128 MB. + * + * NOTE: When the entire KSEG area is DMA capable, we subtract + * one from the max address so that the virt_to_phys() macro + * works correctly on the address (otherwise the address + * enters another area, and virt_to_phys() may not return + * the value desired). + */ + +#ifndef MAX_DMA_ADDRESS +#define MAX_DMA_ADDRESS (PAGE_OFFSET + XCHAL_KIO_SIZE - 1) +#endif + +/* Reserve and release a DMA channel */ +extern int request_dma(unsigned int dmanr, const char * device_id); +extern void free_dma(unsigned int dmanr); + +#ifdef CONFIG_PCI +extern int isa_dma_bridge_buggy; +#else +#define isa_dma_bridge_buggy (0) +#endif + + +#endif diff --git a/arch/xtensa/include/asm/elf.h b/arch/xtensa/include/asm/elf.h new file mode 100644 index 00000000..6e65eada --- /dev/null +++ b/arch/xtensa/include/asm/elf.h @@ -0,0 +1,205 @@ +/* + * include/asm-xtensa/elf.h + * + * ELF register definitions + * + * 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) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_ELF_H +#define _XTENSA_ELF_H + +#include <asm/ptrace.h> +#include <asm/coprocessor.h> + +/* Xtensa processor ELF architecture-magic number */ + +#define EM_XTENSA 94 +#define EM_XTENSA_OLD 0xABC7 + +/* Xtensa relocations defined by the ABIs */ + +#define R_XTENSA_NONE 0 +#define R_XTENSA_32 1 +#define R_XTENSA_RTLD 2 +#define R_XTENSA_GLOB_DAT 3 +#define R_XTENSA_JMP_SLOT 4 +#define R_XTENSA_RELATIVE 5 +#define R_XTENSA_PLT 6 +#define R_XTENSA_OP0 8 +#define R_XTENSA_OP1 9 +#define R_XTENSA_OP2 10 +#define R_XTENSA_ASM_EXPAND 11 +#define R_XTENSA_ASM_SIMPLIFY 12 +#define R_XTENSA_GNU_VTINHERIT 15 +#define R_XTENSA_GNU_VTENTRY 16 +#define R_XTENSA_DIFF8 17 +#define R_XTENSA_DIFF16 18 +#define R_XTENSA_DIFF32 19 +#define R_XTENSA_SLOT0_OP 20 +#define R_XTENSA_SLOT1_OP 21 +#define R_XTENSA_SLOT2_OP 22 +#define R_XTENSA_SLOT3_OP 23 +#define R_XTENSA_SLOT4_OP 24 +#define R_XTENSA_SLOT5_OP 25 +#define R_XTENSA_SLOT6_OP 26 +#define R_XTENSA_SLOT7_OP 27 +#define R_XTENSA_SLOT8_OP 28 +#define R_XTENSA_SLOT9_OP 29 +#define R_XTENSA_SLOT10_OP 30 +#define R_XTENSA_SLOT11_OP 31 +#define R_XTENSA_SLOT12_OP 32 +#define R_XTENSA_SLOT13_OP 33 +#define R_XTENSA_SLOT14_OP 34 +#define R_XTENSA_SLOT0_ALT 35 +#define R_XTENSA_SLOT1_ALT 36 +#define R_XTENSA_SLOT2_ALT 37 +#define R_XTENSA_SLOT3_ALT 38 +#define R_XTENSA_SLOT4_ALT 39 +#define R_XTENSA_SLOT5_ALT 40 +#define R_XTENSA_SLOT6_ALT 41 +#define R_XTENSA_SLOT7_ALT 42 +#define R_XTENSA_SLOT8_ALT 43 +#define R_XTENSA_SLOT9_ALT 44 +#define R_XTENSA_SLOT10_ALT 45 +#define R_XTENSA_SLOT11_ALT 46 +#define R_XTENSA_SLOT12_ALT 47 +#define R_XTENSA_SLOT13_ALT 48 +#define R_XTENSA_SLOT14_ALT 49 + +/* ELF register definitions. This is needed for core dump support. */ + +typedef unsigned long elf_greg_t; + +typedef struct { + elf_greg_t pc; + elf_greg_t ps; + elf_greg_t lbeg; + elf_greg_t lend; + elf_greg_t lcount; + elf_greg_t sar; + elf_greg_t windowstart; + elf_greg_t windowbase; + elf_greg_t reserved[8+48]; + elf_greg_t a[64]; +} xtensa_gregset_t; + +#define ELF_NGREG (sizeof(xtensa_gregset_t) / sizeof(elf_greg_t)) + +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +#define ELF_NFPREG 18 + +typedef unsigned int elf_fpreg_t; +typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; + +#define ELF_CORE_COPY_REGS(_eregs, _pregs) \ + xtensa_elf_core_copy_regs ((xtensa_gregset_t*)&(_eregs), _pregs); + +extern void xtensa_elf_core_copy_regs (xtensa_gregset_t *, struct pt_regs *); + +/* + * This is used to ensure we don't load something for the wrong architecture. + */ + +#define elf_check_arch(x) ( ( (x)->e_machine == EM_XTENSA ) || \ + ( (x)->e_machine == EM_XTENSA_OLD ) ) + +/* + * These are used to set parameters in the core dumps. + */ + +#ifdef __XTENSA_EL__ +# define ELF_DATA ELFDATA2LSB +#elif defined(__XTENSA_EB__) +# define ELF_DATA ELFDATA2MSB +#else +# error processor byte order undefined! +#endif + +#define ELF_CLASS ELFCLASS32 +#define ELF_ARCH EM_XTENSA + +#define ELF_EXEC_PAGESIZE PAGE_SIZE + +/* + * 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) + +/* + * 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) + +/* + * The Xtensa processor ABI says that when the program starts, a2 + * contains a pointer to a function which might be registered using + * `atexit'. This provides a mean for the dynamic linker to call + * DT_FINI functions for shared libraries that have been loaded before + * the code runs. + * + * A value of 0 tells we have no such handler. + * + * We might as well make sure everything else is cleared too (except + * for the stack pointer in a1), just to make things more + * deterministic. Also, clearing a0 terminates debugger backtraces. + */ + +#define ELF_PLAT_INIT(_r, load_addr) \ + do { _r->areg[0]=0; /*_r->areg[1]=0;*/ _r->areg[2]=0; _r->areg[3]=0; \ + _r->areg[4]=0; _r->areg[5]=0; _r->areg[6]=0; _r->areg[7]=0; \ + _r->areg[8]=0; _r->areg[9]=0; _r->areg[10]=0; _r->areg[11]=0; \ + _r->areg[12]=0; _r->areg[13]=0; _r->areg[14]=0; _r->areg[15]=0; \ + } while (0) + +typedef struct { + xtregs_opt_t opt; + xtregs_user_t user; +#if XTENSA_HAVE_COPROCESSORS + xtregs_cp0_t cp0; + xtregs_cp1_t cp1; + xtregs_cp2_t cp2; + xtregs_cp3_t cp3; + xtregs_cp4_t cp4; + xtregs_cp5_t cp5; + xtregs_cp6_t cp6; + xtregs_cp7_t cp7; +#endif +} elf_xtregs_t; + +#define SET_PERSONALITY(ex) set_personality(PER_LINUX_32BIT) + +struct task_struct; + +extern void do_copy_regs (xtensa_gregset_t*, struct pt_regs*, + struct task_struct*); +extern void do_restore_regs (xtensa_gregset_t*, struct pt_regs*, + struct task_struct*); +extern void do_save_fpregs (elf_fpregset_t*, struct pt_regs*, + struct task_struct*); +extern int do_restore_fpregs (elf_fpregset_t*, struct pt_regs*, + struct task_struct*); + +#endif /* _XTENSA_ELF_H */ diff --git a/arch/xtensa/include/asm/emergency-restart.h b/arch/xtensa/include/asm/emergency-restart.h new file mode 100644 index 00000000..108d8c48 --- /dev/null +++ b/arch/xtensa/include/asm/emergency-restart.h @@ -0,0 +1,6 @@ +#ifndef _ASM_EMERGENCY_RESTART_H +#define _ASM_EMERGENCY_RESTART_H + +#include <asm-generic/emergency-restart.h> + +#endif /* _ASM_EMERGENCY_RESTART_H */ diff --git a/arch/xtensa/include/asm/errno.h b/arch/xtensa/include/asm/errno.h new file mode 100644 index 00000000..a0f3b96b --- /dev/null +++ b/arch/xtensa/include/asm/errno.h @@ -0,0 +1,16 @@ +/* + * include/asm-xtensa/errno.h + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of + * this archive for more details. + * + * Copyright (C) 2002 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_ERRNO_H +#define _XTENSA_ERRNO_H + +#include <asm-generic/errno.h> + +#endif /* _XTENSA_ERRNO_H */ diff --git a/arch/xtensa/include/asm/exec.h b/arch/xtensa/include/asm/exec.h new file mode 100644 index 00000000..af949e28 --- /dev/null +++ b/arch/xtensa/include/asm/exec.h @@ -0,0 +1,14 @@ +/* + * 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) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_EXEC_H +#define _XTENSA_EXEC_H + +#define arch_align_stack(x) (x) + +#endif /* _XTENSA_EXEC_H */ diff --git a/arch/xtensa/include/asm/fb.h b/arch/xtensa/include/asm/fb.h new file mode 100644 index 00000000..c7df3803 --- /dev/null +++ b/arch/xtensa/include/asm/fb.h @@ -0,0 +1,12 @@ +#ifndef _ASM_FB_H_ +#define _ASM_FB_H_ +#include <linux/fb.h> + +#define fb_pgprotect(...) do {} while (0) + +static inline int fb_is_primary_device(struct fb_info *info) +{ + return 0; +} + +#endif /* _ASM_FB_H_ */ diff --git a/arch/xtensa/include/asm/fcntl.h b/arch/xtensa/include/asm/fcntl.h new file mode 100644 index 00000000..46ab12db --- /dev/null +++ b/arch/xtensa/include/asm/fcntl.h @@ -0,0 +1 @@ +#include <asm-generic/fcntl.h> diff --git a/arch/xtensa/include/asm/flat.h b/arch/xtensa/include/asm/flat.h new file mode 100644 index 00000000..94c44abf --- /dev/null +++ b/arch/xtensa/include/asm/flat.h @@ -0,0 +1,12 @@ +#ifndef __ASM_XTENSA_FLAT_H +#define __ASM_XTENSA_FLAT_H + +#define flat_argvp_envp_on_stack() 0 +#define flat_old_ram_flag(flags) (flags) +#define flat_reloc_valid(reloc, size) ((reloc) <= (size)) +#define flat_get_addr_from_rp(rp, relval, flags, p) get_unaligned(rp) +#define flat_put_addr_at_rp(rp, val, relval ) put_unaligned(val, rp) +#define flat_get_relocate_addr(rel) (rel) +#define flat_set_persistent(relval, p) 0 + +#endif /* __ASM_XTENSA_FLAT_H */ diff --git a/arch/xtensa/include/asm/ftrace.h b/arch/xtensa/include/asm/ftrace.h new file mode 100644 index 00000000..40a8c178 --- /dev/null +++ b/arch/xtensa/include/asm/ftrace.h @@ -0,0 +1 @@ +/* empty */ diff --git a/arch/xtensa/include/asm/futex.h b/arch/xtensa/include/asm/futex.h new file mode 100644 index 00000000..0b745828 --- /dev/null +++ b/arch/xtensa/include/asm/futex.h @@ -0,0 +1 @@ +#include <asm-generic/futex.h> diff --git a/arch/xtensa/include/asm/gpio.h b/arch/xtensa/include/asm/gpio.h new file mode 100644 index 00000000..a8c9fc46 --- /dev/null +++ b/arch/xtensa/include/asm/gpio.h @@ -0,0 +1,56 @@ +/* + * Generic GPIO API implementation for xtensa. + * + * Stolen from x86, which is derived from the generic GPIO API for powerpc: + * + * Copyright (c) 2007-2008 MontaVista Software, Inc. + * + * Author: Anton Vorontsov <avorontsov@ru.mvista.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef _ASM_XTENSA_GPIO_H +#define _ASM_XTENSA_GPIO_H + +#include <asm-generic/gpio.h> + +#ifdef CONFIG_GPIOLIB + +/* + * Just call gpiolib. + */ +static inline int gpio_get_value(unsigned int gpio) +{ + return __gpio_get_value(gpio); +} + +static inline void gpio_set_value(unsigned int gpio, int value) +{ + __gpio_set_value(gpio, value); +} + +static inline int gpio_cansleep(unsigned int gpio) +{ + return __gpio_cansleep(gpio); +} + +static inline int gpio_to_irq(unsigned int gpio) +{ + return __gpio_to_irq(gpio); +} + +/* + * Not implemented, yet. + */ +static inline int irq_to_gpio(unsigned int irq) +{ + return -EINVAL; +} + +#endif /* CONFIG_GPIOLIB */ + +#endif /* _ASM_XTENSA_GPIO_H */ diff --git a/arch/xtensa/include/asm/hardirq.h b/arch/xtensa/include/asm/hardirq.h new file mode 100644 index 00000000..91695a13 --- /dev/null +++ b/arch/xtensa/include/asm/hardirq.h @@ -0,0 +1,16 @@ +/* + * include/asm-xtensa/hardirq.h + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of + * this archive for more details. + * + * Copyright (C) 2002 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_HARDIRQ_H +#define _XTENSA_HARDIRQ_H + +#include <asm-generic/hardirq.h> + +#endif /* _XTENSA_HARDIRQ_H */ diff --git a/arch/xtensa/include/asm/highmem.h b/arch/xtensa/include/asm/highmem.h new file mode 100644 index 00000000..0a046ca5 --- /dev/null +++ b/arch/xtensa/include/asm/highmem.h @@ -0,0 +1,17 @@ +/* + * include/asm-xtensa/highmem.h + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of + * this archive for more details. + * + * Copyright (C) 2003 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_HIGHMEM_H +#define _XTENSA_HIGHMEM_H + +extern void flush_cache_kmaps(void); + +#endif + diff --git a/arch/xtensa/include/asm/hw_irq.h b/arch/xtensa/include/asm/hw_irq.h new file mode 100644 index 00000000..3ddbea75 --- /dev/null +++ b/arch/xtensa/include/asm/hw_irq.h @@ -0,0 +1,14 @@ +/* + * include/asm-xtensa/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. + * + * Copyright (C) 2002 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_HW_IRQ_H +#define _XTENSA_HW_IRQ_H + +#endif diff --git a/arch/xtensa/include/asm/io.h b/arch/xtensa/include/asm/io.h new file mode 100644 index 00000000..4beb43c0 --- /dev/null +++ b/arch/xtensa/include/asm/io.h @@ -0,0 +1,208 @@ +/* + * include/asm-xtensa/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. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_IO_H +#define _XTENSA_IO_H + +#ifdef __KERNEL__ +#include <asm/byteorder.h> +#include <asm/page.h> +#include <linux/bug.h> +#include <linux/kernel.h> + +#include <linux/types.h> + +#define XCHAL_KIO_CACHED_VADDR 0xe0000000 +#define XCHAL_KIO_BYPASS_VADDR 0xf0000000 +#define XCHAL_KIO_PADDR 0xf0000000 +#define XCHAL_KIO_SIZE 0x10000000 + +#define IOADDR(x) (XCHAL_KIO_BYPASS_VADDR + (x)) + +/* + * swap functions to change byte order from little-endian to big-endian and + * vice versa. + */ + +static inline unsigned short _swapw (unsigned short v) +{ + return (v << 8) | (v >> 8); +} + +static inline unsigned int _swapl (unsigned int v) +{ + return (v << 24) | ((v & 0xff00) << 8) | ((v >> 8) & 0xff00) | (v >> 24); +} + +/* + * Change virtual addresses to physical addresses and vv. + * These are trivial on the 1:1 Linux/Xtensa mapping + */ + +static inline unsigned long virt_to_phys(volatile void * address) +{ + return __pa(address); +} + +static inline void * phys_to_virt(unsigned long address) +{ + return __va(address); +} + +/* + * virt_to_bus and bus_to_virt are deprecated. + */ + +#define virt_to_bus(x) virt_to_phys(x) +#define bus_to_virt(x) phys_to_virt(x) + +/* + * Return the virtual (cached) address for the specified bus memory. + * Note that we currently don't support any address outside the KIO segment. + */ + +static inline void *ioremap(unsigned long offset, unsigned long size) +{ +#ifdef CONFIG_MMU + if (offset >= XCHAL_KIO_PADDR + && offset < XCHAL_KIO_PADDR + XCHAL_KIO_SIZE) + return (void*)(offset-XCHAL_KIO_PADDR+XCHAL_KIO_BYPASS_VADDR); + else + BUG(); +#else + return (void *)offset; +#endif +} + +static inline void *ioremap_nocache(unsigned long offset, unsigned long size) +{ +#ifdef CONFIG_MMU + if (offset >= XCHAL_KIO_PADDR + && offset < XCHAL_KIO_PADDR + XCHAL_KIO_SIZE) + return (void*)(offset-XCHAL_KIO_PADDR+XCHAL_KIO_CACHED_VADDR); + else + BUG(); +#else + return (void *)offset; +#endif +} + +static inline void iounmap(void *addr) +{ +} + +/* + * Generic I/O + */ + +#define readb(addr) \ + ({ unsigned char __v = (*(volatile unsigned char *)(addr)); __v; }) +#define readw(addr) \ + ({ unsigned short __v = (*(volatile unsigned short *)(addr)); __v; }) +#define readl(addr) \ + ({ unsigned int __v = (*(volatile unsigned int *)(addr)); __v; }) +#define writeb(b, addr) (void)((*(volatile unsigned char *)(addr)) = (b)) +#define writew(b, addr) (void)((*(volatile unsigned short *)(addr)) = (b)) +#define writel(b, addr) (void)((*(volatile unsigned int *)(addr)) = (b)) + +static inline __u8 __raw_readb(const volatile void __iomem *addr) +{ + return *(__force volatile __u8 *)(addr); +} +static inline __u16 __raw_readw(const volatile void __iomem *addr) +{ + return *(__force volatile __u16 *)(addr); +} +static inline __u32 __raw_readl(const volatile void __iomem *addr) +{ + return *(__force volatile __u32 *)(addr); +} +static inline void __raw_writeb(__u8 b, volatile void __iomem *addr) +{ + *(__force volatile __u8 *)(addr) = b; +} +static inline void __raw_writew(__u16 b, volatile void __iomem *addr) +{ + *(__force volatile __u16 *)(addr) = b; +} +static inline void __raw_writel(__u32 b, volatile void __iomem *addr) +{ + *(__force volatile __u32 *)(addr) = b; +} + +/* These are the definitions for the x86 IO instructions + * inb/inw/inl/outb/outw/outl, the "string" versions + * insb/insw/insl/outsb/outsw/outsl, and the "pausing" versions + * inb_p/inw_p/... + * The macros don't do byte-swapping. + */ + +#define inb(port) readb((u8 *)((port))) +#define outb(val, port) writeb((val),(u8 *)((unsigned long)(port))) +#define inw(port) readw((u16 *)((port))) +#define outw(val, port) writew((val),(u16 *)((unsigned long)(port))) +#define inl(port) readl((u32 *)((port))) +#define outl(val, port) writel((val),(u32 *)((unsigned long)(port))) + +#define inb_p(port) inb((port)) +#define outb_p(val, port) outb((val), (port)) +#define inw_p(port) inw((port)) +#define outw_p(val, port) outw((val), (port)) +#define inl_p(port) inl((port)) +#define outl_p(val, port) outl((val), (port)) + +extern void insb (unsigned long port, void *dst, unsigned long count); +extern void insw (unsigned long port, void *dst, unsigned long count); +extern void insl (unsigned long port, void *dst, unsigned long count); +extern void outsb (unsigned long port, const void *src, unsigned long count); +extern void outsw (unsigned long port, const void *src, unsigned long count); +extern void outsl (unsigned long port, const void *src, unsigned long count); + +#define IO_SPACE_LIMIT ~0 + +#define memset_io(a,b,c) memset((void *)(a),(b),(c)) +#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c)) +#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c)) + +/* At this point the Xtensa doesn't provide byte swap instructions */ + +#ifdef __XTENSA_EB__ +# define in_8(addr) (*(u8*)(addr)) +# define in_le16(addr) _swapw(*(u16*)(addr)) +# define in_le32(addr) _swapl(*(u32*)(addr)) +# define out_8(b, addr) *(u8*)(addr) = (b) +# define out_le16(b, addr) *(u16*)(addr) = _swapw(b) +# define out_le32(b, addr) *(u32*)(addr) = _swapl(b) +#elif defined(__XTENSA_EL__) +# define in_8(addr) (*(u8*)(addr)) +# define in_le16(addr) (*(u16*)(addr)) +# define in_le32(addr) (*(u32*)(addr)) +# define out_8(b, addr) *(u8*)(addr) = (b) +# define out_le16(b, addr) *(u16*)(addr) = (b) +# define out_le32(b, addr) *(u32*)(addr) = (b) +#else +# error processor byte order undefined! +#endif + + +/* + * Convert a physical pointer to a virtual kernel pointer for /dev/mem access + */ +#define xlate_dev_mem_ptr(p) __va(p) + +/* + * Convert a virtual cached pointer to an uncached pointer + */ +#define xlate_dev_kmem_ptr(p) p + + +#endif /* __KERNEL__ */ + +#endif /* _XTENSA_IO_H */ diff --git a/arch/xtensa/include/asm/ioctl.h b/arch/xtensa/include/asm/ioctl.h new file mode 100644 index 00000000..b279fe06 --- /dev/null +++ b/arch/xtensa/include/asm/ioctl.h @@ -0,0 +1 @@ +#include <asm-generic/ioctl.h> diff --git a/arch/xtensa/include/asm/ioctls.h b/arch/xtensa/include/asm/ioctls.h new file mode 100644 index 00000000..fd1d1369 --- /dev/null +++ b/arch/xtensa/include/asm/ioctls.h @@ -0,0 +1,120 @@ +/* + * include/asm-xtensa/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. + * + * Copyright (C) 2003 - 2005 Tensilica Inc. + * + * Derived from "include/asm-i386/ioctls.h" + */ + +#ifndef _XTENSA_IOCTLS_H +#define _XTENSA_IOCTLS_H + +#include <asm/ioctl.h> + +#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) +#define TIOCNXCL _IO('T', 13) +#define TIOCSCTTY _IO('T', 14) + +#define TIOCSTI _IOW('T', 18, char) +#define TIOCMGET _IOR('T', 21, unsigned int) +#define TIOCMBIS _IOW('T', 22, unsigned int) +#define TIOCMBIC _IOW('T', 23, unsigned int) +#define TIOCMSET _IOW('T', 24, unsigned int) +# 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) +#define TIOCSSOFTCAR _IOW('T', 26, unsigned int) +#define TIOCLINUX _IOW('T', 28, char) +#define TIOCCONS _IO('T', 29) +#define TIOCGSERIAL _IOR('T', 30, struct serial_struct) +#define TIOCSSERIAL _IOW('T', 31, struct serial_struct) +#define TIOCPKT _IOW('T', 32, int) +# 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 TIOCPKT_IOCTL 64 + + +#define TIOCNOTTY _IO('T', 34) +#define TIOCSETD _IOW('T', 35, int) +#define TIOCGETD _IOR('T', 36, int) +#define TCSBRKP _IOW('T', 37, int) /* Needed for POSIX tcsendbreak()*/ +#define TIOCTTYGSTRUCT _IOR('T', 38, struct tty_struct) /* For debugging only*/ +#define TIOCSBRK _IO('T', 39) /* BSD compatibility */ +#define TIOCCBRK _IO('T', 40) /* BSD compatibility */ +#define TIOCGSID _IOR('T', 41, pid_t) /* Return the session ID of FD*/ +#define TCGETS2 _IOR('T', 42, struct termios2) +#define TCSETS2 _IOW('T', 43, struct termios2) +#define TCSETSW2 _IOW('T', 44, struct termios2) +#define TCSETSF2 _IOW('T', 45, struct termios2) +#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get primary device node of /dev/console */ +#define TIOCSIG _IOW('T',0x36, int) /* Generate signal on Pty slave */ +#define TIOCVHANGUP _IO('T', 0x37) + +#define TIOCSERCONFIG _IO('T', 83) +#define TIOCSERGWILD _IOR('T', 84, int) +#define TIOCSERSWILD _IOW('T', 85, int) +#define TIOCGLCKTRMIOS 0x5456 +#define TIOCSLCKTRMIOS 0x5457 +#define TIOCSERGSTRUCT 0x5458 /* For debugging only */ +#define TIOCSERGETLSR _IOR('T', 89, unsigned int) /* Get line status reg. */ + /* 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) /* Get multiport config */ +#define TIOCSERSETMULTI _IOW('T', 91, struct serial_multiport_struct) /* Set multiport config */ + +#define TIOCMIWAIT _IO('T', 92) /* wait for a change on serial input line(s) */ +#define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ + +#endif /* _XTENSA_IOCTLS_H */ diff --git a/arch/xtensa/include/asm/ipcbuf.h b/arch/xtensa/include/asm/ipcbuf.h new file mode 100644 index 00000000..c33aa6a4 --- /dev/null +++ b/arch/xtensa/include/asm/ipcbuf.h @@ -0,0 +1,37 @@ +/* + * include/asm-xtensa/ipcbuf.h + * + * The ipc64_perm structure for the Xtensa architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_IPCBUF_H +#define _XTENSA_IPCBUF_H + +/* + * Pad space is left for: + * - 32-bit mode_t and seq + * - 2 miscellaneous 32-bit values + * + * 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. + */ + +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 long seq; + unsigned long __unused1; + unsigned long __unused2; +}; + +#endif /* _XTENSA_IPCBUF_H */ diff --git a/arch/xtensa/include/asm/irq.h b/arch/xtensa/include/asm/irq.h new file mode 100644 index 00000000..4c0ccc9c --- /dev/null +++ b/arch/xtensa/include/asm/irq.h @@ -0,0 +1,47 @@ +/* + * include/asm-xtensa/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. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_IRQ_H +#define _XTENSA_IRQ_H + +#include <linux/init.h> +#include <platform/hardware.h> +#include <variant/core.h> + +#ifdef CONFIG_VARIANT_IRQ_SWITCH +#include <variant/irq.h> +#else +static inline void variant_irq_enable(unsigned int irq) { } +static inline void variant_irq_disable(unsigned int irq) { } +#endif + +#ifndef VARIANT_NR_IRQS +# define VARIANT_NR_IRQS 0 +#endif +#ifndef PLATFORM_NR_IRQS +# define PLATFORM_NR_IRQS 0 +#endif +#define XTENSA_NR_IRQS XCHAL_NUM_INTERRUPTS +#define NR_IRQS (XTENSA_NR_IRQS + VARIANT_NR_IRQS + PLATFORM_NR_IRQS) + +#if VARIANT_NR_IRQS == 0 +static inline void variant_init_irq(void) { } +#else +void variant_init_irq(void) __init; +#endif + +static __inline__ int irq_canonicalize(int irq) +{ + return (irq); +} + +struct irqaction; + +#endif /* _XTENSA_IRQ_H */ diff --git a/arch/xtensa/include/asm/irq_regs.h b/arch/xtensa/include/asm/irq_regs.h new file mode 100644 index 00000000..3dd9c0b7 --- /dev/null +++ b/arch/xtensa/include/asm/irq_regs.h @@ -0,0 +1 @@ +#include <asm-generic/irq_regs.h> diff --git a/arch/xtensa/include/asm/irqflags.h b/arch/xtensa/include/asm/irqflags.h new file mode 100644 index 00000000..dae9a8bd --- /dev/null +++ b/arch/xtensa/include/asm/irqflags.h @@ -0,0 +1,58 @@ +/* + * Xtensa IRQ flags handling functions + * + * 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) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_IRQFLAGS_H +#define _XTENSA_IRQFLAGS_H + +#include <linux/types.h> + +static inline unsigned long arch_local_save_flags(void) +{ + unsigned long flags; + asm volatile("rsr %0,"__stringify(PS) : "=a" (flags)); + return flags; +} + +static inline unsigned long arch_local_irq_save(void) +{ + unsigned long flags; + asm volatile("rsil %0, "__stringify(LOCKLEVEL) + : "=a" (flags) :: "memory"); + return flags; +} + +static inline void arch_local_irq_disable(void) +{ + arch_local_irq_save(); +} + +static inline void arch_local_irq_enable(void) +{ + unsigned long flags; + asm volatile("rsil %0, 0" : "=a" (flags) :: "memory"); +} + +static inline void arch_local_irq_restore(unsigned long flags) +{ + asm volatile("wsr %0, "__stringify(PS)" ; rsync" + :: "a" (flags) : "memory"); +} + +static inline bool arch_irqs_disabled_flags(unsigned long flags) +{ + return (flags & 0xf) != 0; +} + +static inline bool arch_irqs_disabled(void) +{ + return arch_irqs_disabled_flags(arch_local_save_flags()); +} + +#endif /* _XTENSA_IRQFLAGS_H */ diff --git a/arch/xtensa/include/asm/kdebug.h b/arch/xtensa/include/asm/kdebug.h new file mode 100644 index 00000000..6ece1b03 --- /dev/null +++ b/arch/xtensa/include/asm/kdebug.h @@ -0,0 +1 @@ +#include <asm-generic/kdebug.h> diff --git a/arch/xtensa/include/asm/kmap_types.h b/arch/xtensa/include/asm/kmap_types.h new file mode 100644 index 00000000..11c687e5 --- /dev/null +++ b/arch/xtensa/include/asm/kmap_types.h @@ -0,0 +1,6 @@ +#ifndef _XTENSA_KMAP_TYPES_H +#define _XTENSA_KMAP_TYPES_H + +#include <asm-generic/kmap_types.h> + +#endif /* _XTENSA_KMAP_TYPES_H */ diff --git a/arch/xtensa/include/asm/linkage.h b/arch/xtensa/include/asm/linkage.h new file mode 100644 index 00000000..bf2128a9 --- /dev/null +++ b/arch/xtensa/include/asm/linkage.h @@ -0,0 +1,16 @@ +/* + * include/asm-xtensa/linkage.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_LINKAGE_H +#define _XTENSA_LINKAGE_H + +/* Nothing to do here ... */ + +#endif /* _XTENSA_LINKAGE_H */ diff --git a/arch/xtensa/include/asm/local.h b/arch/xtensa/include/asm/local.h new file mode 100644 index 00000000..48723e55 --- /dev/null +++ b/arch/xtensa/include/asm/local.h @@ -0,0 +1,16 @@ +/* + * include/asm-xtensa/local.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_LOCAL_H +#define _XTENSA_LOCAL_H + +#include <asm-generic/local.h> + +#endif /* _XTENSA_LOCAL_H */ diff --git a/arch/xtensa/include/asm/local64.h b/arch/xtensa/include/asm/local64.h new file mode 100644 index 00000000..36c93b5c --- /dev/null +++ b/arch/xtensa/include/asm/local64.h @@ -0,0 +1 @@ +#include <asm-generic/local64.h> diff --git a/arch/xtensa/include/asm/mman.h b/arch/xtensa/include/asm/mman.h new file mode 100644 index 00000000..25bc6c13 --- /dev/null +++ b/arch/xtensa/include/asm/mman.h @@ -0,0 +1,96 @@ +/* + * include/asm-xtensa/mman.h + * + * Xtensa Processor memory-manager definitions + * + * 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 Ralf Baechle + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_MMAN_H +#define _XTENSA_MMAN_H + +/* + * Protections are chosen from these bits, OR'd together. The + * implementation does not necessarily support PROT_EXEC or PROT_WRITE + * without PROT_READ. The only guarantees are that no writing will be + * allowed without PROT_WRITE and no access will be allowed for PROT_NONE. + */ + +#define PROT_NONE 0x0 /* page can not be accessed */ +#define PROT_READ 0x1 /* page can be read */ +#define PROT_WRITE 0x2 /* page can be written */ +#define PROT_EXEC 0x4 /* page can be executed */ + +#define PROT_SEM 0x10 /* page may be used for atomic ops */ +#define PROT_GROWSDOWN 0x01000000 /* mprotect flag: extend change to start of growsdown vma */ +#define PROT_GROWSUP 0x02000000 /* mprotect flag: extend change to end fo growsup vma */ + +/* + * Flags for mmap + */ +#define MAP_SHARED 0x001 /* Share changes */ +#define MAP_PRIVATE 0x002 /* Changes are private */ +#define MAP_TYPE 0x00f /* Mask for type of mapping */ +#define MAP_FIXED 0x010 /* Interpret addr exactly */ + +/* not used by linux, but here to make sure we don't clash with ABI defines */ +#define MAP_RENAME 0x020 /* Assign page to file */ +#define MAP_AUTOGROW 0x040 /* File may grow by writing */ +#define MAP_LOCAL 0x080 /* Copy on fork/sproc */ +#define MAP_AUTORSRV 0x100 /* Logical swap reserved on demand */ + +/* These are linux-specific */ +#define MAP_NORESERVE 0x0400 /* don't check for reservations */ +#define MAP_ANONYMOUS 0x0800 /* don't use a file */ +#define MAP_GROWSDOWN 0x1000 /* stack-like segment */ +#define MAP_DENYWRITE 0x2000 /* ETXTBSY */ +#define MAP_EXECUTABLE 0x4000 /* mark it as an executable */ +#define MAP_LOCKED 0x8000 /* pages are locked */ +#define MAP_POPULATE 0x10000 /* populate (prefault) pagetables */ +#define MAP_NONBLOCK 0x20000 /* do not block on IO */ +#define MAP_STACK 0x40000 /* give out an address that is best suited for process/thread stacks */ +#define MAP_HUGETLB 0x80000 /* create a huge page mapping */ + +/* + * Flags for msync + */ +#define MS_ASYNC 0x0001 /* sync memory asynchronously */ +#define MS_INVALIDATE 0x0002 /* invalidate mappings & caches */ +#define MS_SYNC 0x0004 /* synchronous memory sync */ + +/* + * Flags for mlockall + */ +#define MCL_CURRENT 1 /* lock all current mappings */ +#define MCL_FUTURE 2 /* lock all future mappings */ + +#define MADV_NORMAL 0 /* no further special treatment */ +#define MADV_RANDOM 1 /* expect random page references */ +#define MADV_SEQUENTIAL 2 /* expect sequential page references */ +#define MADV_WILLNEED 3 /* will need these pages */ +#define MADV_DONTNEED 4 /* don't need these pages */ + +/* common parameters: try to keep these consistent across architectures */ +#define MADV_REMOVE 9 /* remove these pages & resources */ +#define MADV_DONTFORK 10 /* don't inherit across fork */ +#define MADV_DOFORK 11 /* do inherit across fork */ + +#define MADV_MERGEABLE 12 /* KSM may merge identical pages */ +#define MADV_UNMERGEABLE 13 /* KSM may not merge identical pages */ + +#define MADV_HUGEPAGE 14 /* Worth backing with hugepages */ +#define MADV_NOHUGEPAGE 15 /* Not worth backing with hugepages */ + +#define MADV_DONTDUMP 16 /* Explicity exclude from the core dump, + overrides the coredump filter bits */ +#define MADV_DODUMP 17 /* Clear the MADV_NODUMP flag */ + +/* compatibility flags */ +#define MAP_FILE 0 + +#endif /* _XTENSA_MMAN_H */ diff --git a/arch/xtensa/include/asm/mmu.h b/arch/xtensa/include/asm/mmu.h new file mode 100644 index 00000000..04890d6e --- /dev/null +++ b/arch/xtensa/include/asm/mmu.h @@ -0,0 +1,22 @@ +/* + * include/asm-xtensa/mmu.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_MMU_H +#define _XTENSA_MMU_H + +#ifndef CONFIG_MMU +#include <asm/nommu.h> +#else + +/* Default "unsigned long" context */ +typedef unsigned long mm_context_t; + +#endif /* CONFIG_MMU */ +#endif /* _XTENSA_MMU_H */ diff --git a/arch/xtensa/include/asm/mmu_context.h b/arch/xtensa/include/asm/mmu_context.h new file mode 100644 index 00000000..dbd8731a --- /dev/null +++ b/arch/xtensa/include/asm/mmu_context.h @@ -0,0 +1,141 @@ +/* + * include/asm-xtensa/mmu_context.h + * + * Switch an MMU context. + * + * 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) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_MMU_CONTEXT_H +#define _XTENSA_MMU_CONTEXT_H + +#ifndef CONFIG_MMU +#include <asm/nommu_context.h> +#else + +#include <linux/stringify.h> +#include <linux/sched.h> + +#include <variant/core.h> + +#include <asm/pgtable.h> +#include <asm/cacheflush.h> +#include <asm/tlbflush.h> +#include <asm-generic/mm_hooks.h> + +#if (XCHAL_HAVE_TLBS != 1) +# error "Linux must have an MMU!" +#endif + +extern unsigned long asid_cache; + +/* + * NO_CONTEXT is the invalid ASID value that we don't ever assign to + * any user or kernel context. + * + * 0 invalid + * 1 kernel + * 2 reserved + * 3 reserved + * 4...255 available + */ + +#define NO_CONTEXT 0 +#define ASID_USER_FIRST 4 +#define ASID_MASK ((1 << XCHAL_MMU_ASID_BITS) - 1) +#define ASID_INSERT(x) (0x03020001 | (((x) & ASID_MASK) << 8)) + +static inline void set_rasid_register (unsigned long val) +{ + __asm__ __volatile__ (" wsr %0, "__stringify(RASID)"\n\t" + " isync\n" : : "a" (val)); +} + +static inline unsigned long get_rasid_register (void) +{ + unsigned long tmp; + __asm__ __volatile__ (" rsr %0,"__stringify(RASID)"\n\t" : "=a" (tmp)); + return tmp; +} + +static inline void +__get_new_mmu_context(struct mm_struct *mm) +{ + extern void flush_tlb_all(void); + if (! (++asid_cache & ASID_MASK) ) { + flush_tlb_all(); /* start new asid cycle */ + asid_cache += ASID_USER_FIRST; + } + mm->context = asid_cache; +} + +static inline void +__load_mmu_context(struct mm_struct *mm) +{ + set_rasid_register(ASID_INSERT(mm->context)); + invalidate_page_directory(); +} + +/* + * 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; +} + +/* + * After we have set current->mm to a new value, this activates + * the context for the new mm so we see the new mappings. + */ +static inline void +activate_mm(struct mm_struct *prev, struct mm_struct *next) +{ + /* Unconditionally get a new ASID. */ + + __get_new_mmu_context(next); + __load_mmu_context(next); +} + + +static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, + struct task_struct *tsk) +{ + unsigned long asid = asid_cache; + + /* Check if our ASID is of an older version and thus invalid */ + + if (next->context == NO_CONTEXT || ((next->context^asid) & ~ASID_MASK)) + __get_new_mmu_context(next); + + __load_mmu_context(next); +} + +#define deactivate_mm(tsk, mm) do { } while(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) +{ + invalidate_page_directory(); +} + + +static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) +{ + /* Nothing to do. */ + +} + +#endif /* CONFIG_MMU */ +#endif /* _XTENSA_MMU_CONTEXT_H */ diff --git a/arch/xtensa/include/asm/module.h b/arch/xtensa/include/asm/module.h new file mode 100644 index 00000000..d9b34bee --- /dev/null +++ b/arch/xtensa/include/asm/module.h @@ -0,0 +1,27 @@ +/* + * include/asm-xtensa/module.h + * + * This file contains the module code specific to the Xtensa architecture. + * + * 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) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_MODULE_H +#define _XTENSA_MODULE_H + +struct mod_arch_specific +{ + /* No special elements, yet. */ +}; + +#define MODULE_ARCH_VERMAGIC "xtensa-" __stringify(XCHAL_CORE_ID) " " + +#define Elf_Shdr Elf32_Shdr +#define Elf_Sym Elf32_Sym +#define Elf_Ehdr Elf32_Ehdr + +#endif /* _XTENSA_MODULE_H */ diff --git a/arch/xtensa/include/asm/msgbuf.h b/arch/xtensa/include/asm/msgbuf.h new file mode 100644 index 00000000..693c9675 --- /dev/null +++ b/arch/xtensa/include/asm/msgbuf.h @@ -0,0 +1,48 @@ +/* + * include/asm-xtensa/msgbuf.h + * + * The msqid64_ds structure for the Xtensa 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 + * + * 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 _XTENSA_MSGBUF_H +#define _XTENSA_MSGBUF_H + +struct msqid64_ds { + struct ipc64_perm msg_perm; +#ifdef __XTENSA_EB__ + unsigned int __unused1; + __kernel_time_t msg_stime; /* last msgsnd time */ + unsigned int __unused2; + __kernel_time_t msg_rtime; /* last msgrcv time */ + unsigned int __unused3; + __kernel_time_t msg_ctime; /* last change time */ +#elif defined(__XTENSA_EL__) + __kernel_time_t msg_stime; /* last msgsnd time */ + unsigned int __unused1; + __kernel_time_t msg_rtime; /* last msgrcv time */ + unsigned int __unused2; + __kernel_time_t msg_ctime; /* last change time */ + unsigned int __unused3; +#else +# error processor byte order undefined! +#endif + 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 /* _XTENSA_MSGBUF_H */ diff --git a/arch/xtensa/include/asm/mutex.h b/arch/xtensa/include/asm/mutex.h new file mode 100644 index 00000000..458c1f7f --- /dev/null +++ b/arch/xtensa/include/asm/mutex.h @@ -0,0 +1,9 @@ +/* + * Pull in the generic implementation for the mutex fastpath. + * + * TODO: implement optimized primitives instead, or leave the generic + * implementation in place, or pick the atomic_xchg() based generic + * implementation. (see asm-generic/mutex-xchg.h for details) + */ + +#include <asm-generic/mutex-dec.h> diff --git a/arch/xtensa/include/asm/nommu.h b/arch/xtensa/include/asm/nommu.h new file mode 100644 index 00000000..dce2c438 --- /dev/null +++ b/arch/xtensa/include/asm/nommu.h @@ -0,0 +1,3 @@ +typedef struct { + unsigned long end_brk; +} mm_context_t; diff --git a/arch/xtensa/include/asm/nommu_context.h b/arch/xtensa/include/asm/nommu_context.h new file mode 100644 index 00000000..599e7a2e --- /dev/null +++ b/arch/xtensa/include/asm/nommu_context.h @@ -0,0 +1,25 @@ +static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) +{ +} + +static inline int init_new_context(struct task_struct *tsk, struct mm_struct *mm) +{ + return 0; +} + +static inline void destroy_context(struct mm_struct *mm) +{ +} + +static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next) +{ +} + +static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, + struct task_struct *tsk) +{ +} + +static inline void deactivate_mm(struct task_struct *tsk, struct mm_struct *mm) +{ +} diff --git a/arch/xtensa/include/asm/page.h b/arch/xtensa/include/asm/page.h new file mode 100644 index 00000000..7a5591a7 --- /dev/null +++ b/arch/xtensa/include/asm/page.h @@ -0,0 +1,180 @@ +/* + * include/asm-xtensa/page.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version2 as + * published by the Free Software Foundation. + * + * Copyright (C) 2001 - 2007 Tensilica Inc. + */ + +#ifndef _XTENSA_PAGE_H +#define _XTENSA_PAGE_H + +#include <asm/processor.h> +#include <asm/types.h> +#include <asm/cache.h> +#include <platform/hardware.h> + +/* + * Fixed TLB translations in the processor. + */ + +#define XCHAL_KSEG_CACHED_VADDR 0xd0000000 +#define XCHAL_KSEG_BYPASS_VADDR 0xd8000000 +#define XCHAL_KSEG_PADDR 0x00000000 +#define XCHAL_KSEG_SIZE 0x08000000 + +/* + * PAGE_SHIFT determines the page size + */ + +#define PAGE_SHIFT 12 +#define PAGE_SIZE (__XTENSA_UL_CONST(1) << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE-1)) + +#ifdef CONFIG_MMU +#define PAGE_OFFSET XCHAL_KSEG_CACHED_VADDR +#define MAX_MEM_PFN XCHAL_KSEG_SIZE +#else +#define PAGE_OFFSET 0 +#define MAX_MEM_PFN (PLATFORM_DEFAULT_MEM_START + PLATFORM_DEFAULT_MEM_SIZE) +#endif + +#define PGTABLE_START 0x80000000 + +/* + * Cache aliasing: + * + * If the cache size for one way is greater than the page size, we have to + * deal with cache aliasing. The cache index is wider than the page size: + * + * | |cache| cache index + * | pfn |off| virtual address + * |xxxx:X|zzz| + * | : | | + * | \ / | | + * |trans.| | + * | / \ | | + * |yyyy:Y|zzz| physical address + * + * When the page number is translated to the physical page address, the lowest + * bit(s) (X) that are part of the cache index are also translated (Y). + * If this translation changes bit(s) (X), the cache index is also afected, + * thus resulting in a different cache line than before. + * The kernel does not provide a mechanism to ensure that the page color + * (represented by this bit) remains the same when allocated or when pages + * are remapped. When user pages are mapped into kernel space, the color of + * the page might also change. + * + * We use the address space VMALLOC_END ... VMALLOC_END + DCACHE_WAY_SIZE * 2 + * to temporarily map a patch so we can match the color. + */ + +#if DCACHE_WAY_SIZE > PAGE_SIZE +# define DCACHE_ALIAS_ORDER (DCACHE_WAY_SHIFT - PAGE_SHIFT) +# define DCACHE_ALIAS_MASK (PAGE_MASK & (DCACHE_WAY_SIZE - 1)) +# define DCACHE_ALIAS(a) (((a) & DCACHE_ALIAS_MASK) >> PAGE_SHIFT) +# define DCACHE_ALIAS_EQ(a,b) ((((a) ^ (b)) & DCACHE_ALIAS_MASK) == 0) +#else +# define DCACHE_ALIAS_ORDER 0 +#endif + +#if ICACHE_WAY_SIZE > PAGE_SIZE +# define ICACHE_ALIAS_ORDER (ICACHE_WAY_SHIFT - PAGE_SHIFT) +# define ICACHE_ALIAS_MASK (PAGE_MASK & (ICACHE_WAY_SIZE - 1)) +# define ICACHE_ALIAS(a) (((a) & ICACHE_ALIAS_MASK) >> PAGE_SHIFT) +# define ICACHE_ALIAS_EQ(a,b) ((((a) ^ (b)) & ICACHE_ALIAS_MASK) == 0) +#else +# define ICACHE_ALIAS_ORDER 0 +#endif + + +#ifdef __ASSEMBLY__ + +#define __pgprot(x) (x) + +#else + +/* + * These are used to make use of C type-checking.. + */ + +typedef struct { unsigned long pte; } pte_t; /* page table entry */ +typedef struct { unsigned long pgd; } pgd_t; /* PGD table entry */ +typedef struct { unsigned long pgprot; } pgprot_t; +typedef struct page *pgtable_t; + +#define pte_val(x) ((x).pte) +#define pgd_val(x) ((x).pgd) +#define pgprot_val(x) ((x).pgprot) + +#define __pte(x) ((pte_t) { (x) } ) +#define __pgd(x) ((pgd_t) { (x) } ) +#define __pgprot(x) ((pgprot_t) { (x) } ) + +/* + * Pure 2^n version of get_order + * Use 'nsau' instructions if supported by the processor or the generic version. + */ + +#if XCHAL_HAVE_NSA + +static inline __attribute_const__ int get_order(unsigned long size) +{ + int lz; + asm ("nsau %0, %1" : "=r" (lz) : "r" ((size - 1) >> PAGE_SHIFT)); + return 32 - lz; +} + +#else + +# include <asm-generic/getorder.h> + +#endif + +struct page; +extern void clear_page(void *page); +extern void copy_page(void *to, void *from); + +/* + * If we have cache aliasing and writeback caches, we might have to do + * some extra work + */ + +#if DCACHE_WAY_SIZE > PAGE_SIZE +extern void clear_user_page(void*, unsigned long, struct page*); +extern void copy_user_page(void*, void*, unsigned long, struct page*); +#else +# define clear_user_page(page, vaddr, pg) clear_page(page) +# define copy_user_page(to, from, vaddr, pg) copy_page(to, from) +#endif + +/* + * This handles the memory map. We handle pages at + * XCHAL_KSEG_CACHED_VADDR for kernels with 32 bit address space. + * These macros are for conversion of kernel address, not user + * addresses. + */ + +#define ARCH_PFN_OFFSET (PLATFORM_DEFAULT_MEM_START >> PAGE_SHIFT) + +#define __pa(x) ((unsigned long) (x) - PAGE_OFFSET) +#define __va(x) ((void *)((unsigned long) (x) + PAGE_OFFSET)) +#define pfn_valid(pfn) ((pfn) >= ARCH_PFN_OFFSET && ((pfn) - ARCH_PFN_OFFSET) < max_mapnr) +#ifdef CONFIG_DISCONTIGMEM +# error CONFIG_DISCONTIGMEM not supported +#endif + +#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) +#define page_to_virt(page) __va(page_to_pfn(page) << PAGE_SHIFT) +#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) +#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) + +#endif /* __ASSEMBLY__ */ + +#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ + VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) + +#include <asm-generic/memory_model.h> +#endif /* _XTENSA_PAGE_H */ diff --git a/arch/xtensa/include/asm/param.h b/arch/xtensa/include/asm/param.h new file mode 100644 index 00000000..ba03d5ae --- /dev/null +++ b/arch/xtensa/include/asm/param.h @@ -0,0 +1,34 @@ +/* + * include/asm-xtensa/param.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_PARAM_H +#define _XTENSA_PARAM_H + +#ifdef __KERNEL__ +# define HZ CONFIG_HZ /* internal timer frequency */ +# define USER_HZ 100 /* for user interfaces in "ticks" */ +# define CLOCKS_PER_SEC (USER_HZ) /* frequnzy at which times() counts */ +#else +# 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 /* _XTENSA_PARAM_H */ diff --git a/arch/xtensa/include/asm/pci-bridge.h b/arch/xtensa/include/asm/pci-bridge.h new file mode 100644 index 00000000..00fcbd7c --- /dev/null +++ b/arch/xtensa/include/asm/pci-bridge.h @@ -0,0 +1,88 @@ +/* + * include/asm-xtensa/pci-bridge.h + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of + * this archive for more details. + * + * Copyright (C) 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_PCI_BRIDGE_H +#define _XTENSA_PCI_BRIDGE_H + +#ifdef __KERNEL__ + +struct device_node; +struct pci_controller; + +/* + * pciauto_bus_scan() enumerates the pci space. + */ + +extern int pciauto_bus_scan(struct pci_controller *, int); + +struct pci_space { + unsigned long start; + unsigned long end; + unsigned long base; +}; + +/* + * Structure of a PCI controller (host bridge) + */ + +struct pci_controller { + int index; /* used for pci_controller_num */ + struct pci_controller *next; + struct pci_bus *bus; + void *arch_data; + + int first_busno; + int last_busno; + + struct pci_ops *ops; + volatile unsigned int *cfg_addr; + volatile unsigned char *cfg_data; + + /* Currently, we limit ourselves to 1 IO range and 3 mem + * ranges since the common pci_bus structure can't handle more + */ + struct resource io_resource; + struct resource mem_resources[3]; + int mem_resource_count; + + /* Host bridge I/O and Memory space + * Used for BAR placement algorithms + */ + struct pci_space io_space; + struct pci_space mem_space; + + /* Return the interrupt number fo a device. */ + int (*map_irq)(struct pci_dev*, u8, u8); + +}; + +static inline void pcibios_init_resource(struct resource *res, + unsigned long start, unsigned long end, int flags, char *name) +{ + res->start = start; + res->end = end; + res->flags = flags; + res->name = name; + res->parent = NULL; + res->sibling = NULL; + res->child = NULL; +} + + +/* These are used for config access before all the PCI probing has been done. */ +int early_read_config_byte(struct pci_controller*, int, int, int, u8*); +int early_read_config_word(struct pci_controller*, int, int, int, u16*); +int early_read_config_dword(struct pci_controller*, int, int, int, u32*); +int early_write_config_byte(struct pci_controller*, int, int, int, u8); +int early_write_config_word(struct pci_controller*, int, int, int, u16); +int early_write_config_dword(struct pci_controller*, int, int, int, u32); + +#endif /* __KERNEL__ */ +#endif /* _XTENSA_PCI_BRIDGE_H */ diff --git a/arch/xtensa/include/asm/pci.h b/arch/xtensa/include/asm/pci.h new file mode 100644 index 00000000..05244f07 --- /dev/null +++ b/arch/xtensa/include/asm/pci.h @@ -0,0 +1,69 @@ +/* + * linux/include/asm-xtensa/pci.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_PCI_H +#define _XTENSA_PCI_H + +#ifdef __KERNEL__ + +/* 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() 0 + +extern struct pci_controller* pcibios_alloc_controller(void); + +static inline void pcibios_penalize_isa_irq(int irq) +{ + /* We don't do dynamic PCI IRQ allocation */ +} + +/* Assume some values. (We should revise them, if necessary) */ + +#define PCIBIOS_MIN_IO 0x2000 +#define PCIBIOS_MIN_MEM 0x10000000 + +/* Dynamic DMA mapping stuff. + * Xtensa has everything mapped statically like x86. + */ + +#include <linux/types.h> +#include <linux/slab.h> +#include <asm/scatterlist.h> +#include <linux/string.h> +#include <asm/io.h> + +struct pci_dev; + +/* 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) + +/* Map a range of PCI memory or I/O space for a device into user space */ +int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma, + enum pci_mmap_state mmap_state, int write_combine); + +/* Tell drivers/pci/proc.c that we have pci_mmap_page_range() */ +#define HAVE_PCI_MMAP 1 + +#endif /* __KERNEL__ */ + +/* Implement the pci_ DMA API in terms of the generic device dma_ one */ +#include <asm-generic/pci-dma-compat.h> + +/* Generic PCI */ +#include <asm-generic/pci.h> + +#endif /* _XTENSA_PCI_H */ diff --git a/arch/xtensa/include/asm/percpu.h b/arch/xtensa/include/asm/percpu.h new file mode 100644 index 00000000..6d2bc2ad --- /dev/null +++ b/arch/xtensa/include/asm/percpu.h @@ -0,0 +1,16 @@ +/* + * linux/include/asm-xtensa/percpu.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_PERCPU__ +#define _XTENSA_PERCPU__ + +#include <asm-generic/percpu.h> + +#endif /* _XTENSA_PERCPU__ */ diff --git a/arch/xtensa/include/asm/pgalloc.h b/arch/xtensa/include/asm/pgalloc.h new file mode 100644 index 00000000..40cf9bce --- /dev/null +++ b/arch/xtensa/include/asm/pgalloc.h @@ -0,0 +1,74 @@ +/* + * include/asm-xtensa/pgalloc.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Copyright (C) 2001-2007 Tensilica Inc. + */ + +#ifndef _XTENSA_PGALLOC_H +#define _XTENSA_PGALLOC_H + +#ifdef __KERNEL__ + +#include <linux/highmem.h> +#include <linux/slab.h> + +/* + * Allocating and freeing a pmd is trivial: the 1-entry pmd is + * inside the pgd, so has no extra memory associated with it. + */ + +#define pmd_populate_kernel(mm, pmdp, ptep) \ + (pmd_val(*(pmdp)) = ((unsigned long)ptep)) +#define pmd_populate(mm, pmdp, page) \ + (pmd_val(*(pmdp)) = ((unsigned long)page_to_virt(page))) +#define pmd_pgtable(pmd) pmd_page(pmd) + +static inline pgd_t* +pgd_alloc(struct mm_struct *mm) +{ + return (pgd_t*) __get_free_pages(GFP_KERNEL | __GFP_ZERO, PGD_ORDER); +} + +static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd) +{ + free_page((unsigned long)pgd); +} + +/* Use a slab cache for the pte pages (see also sparc64 implementation) */ + +extern struct kmem_cache *pgtable_cache; + +static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, + unsigned long address) +{ + return kmem_cache_alloc(pgtable_cache, GFP_KERNEL|__GFP_REPEAT); +} + +static inline pgtable_t pte_alloc_one(struct mm_struct *mm, + unsigned long addr) +{ + struct page *page; + + page = virt_to_page(pte_alloc_one_kernel(mm, addr)); + pgtable_page_ctor(page); + return page; +} + +static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte) +{ + kmem_cache_free(pgtable_cache, pte); +} + +static inline void pte_free(struct mm_struct *mm, pgtable_t pte) +{ + pgtable_page_dtor(pte); + kmem_cache_free(pgtable_cache, page_address(pte)); +} +#define pmd_pgtable(pmd) pmd_page(pmd) + +#endif /* __KERNEL__ */ +#endif /* _XTENSA_PGALLOC_H */ diff --git a/arch/xtensa/include/asm/pgtable.h b/arch/xtensa/include/asm/pgtable.h new file mode 100644 index 00000000..b03c043c --- /dev/null +++ b/arch/xtensa/include/asm/pgtable.h @@ -0,0 +1,416 @@ +/* + * include/asm-xtensa/pgtable.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Copyright (C) 2001 - 2007 Tensilica Inc. + */ + +#ifndef _XTENSA_PGTABLE_H +#define _XTENSA_PGTABLE_H + +#include <asm-generic/pgtable-nopmd.h> +#include <asm/page.h> + +/* + * We only use two ring levels, user and kernel space. + */ + +#define USER_RING 1 /* user ring level */ +#define KERNEL_RING 0 /* kernel ring level */ + +/* + * The Xtensa architecture port of Linux has a two-level page table system, + * i.e. the logical three-level Linux page table layout is folded. + * Each task has the following memory page tables: + * + * PGD table (page directory), ie. 3rd-level page table: + * One page (4 kB) of 1024 (PTRS_PER_PGD) pointers to PTE tables + * (Architectures that don't have the PMD folded point to the PMD tables) + * + * The pointer to the PGD table for a given task can be retrieved from + * the task structure (struct task_struct*) t, e.g. current(): + * (t->mm ? t->mm : t->active_mm)->pgd + * + * PMD tables (page middle-directory), ie. 2nd-level page tables: + * Absent for the Xtensa architecture (folded, PTRS_PER_PMD == 1). + * + * PTE tables (page table entry), ie. 1st-level page tables: + * One page (4 kB) of 1024 (PTRS_PER_PTE) PTEs with a special PTE + * invalid_pte_table for absent mappings. + * + * The individual pages are 4 kB big with special pages for the empty_zero_page. + */ + +#define PGDIR_SHIFT 22 +#define PGDIR_SIZE (1UL << PGDIR_SHIFT) +#define PGDIR_MASK (~(PGDIR_SIZE-1)) + +/* + * Entries per page directory level: we use two-level, so + * we don't really have any PMD directory physically. + */ +#define PTRS_PER_PTE 1024 +#define PTRS_PER_PTE_SHIFT 10 +#define PTRS_PER_PGD 1024 +#define PGD_ORDER 0 +#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE) +#define FIRST_USER_ADDRESS 0 +#define FIRST_USER_PGD_NR (FIRST_USER_ADDRESS >> PGDIR_SHIFT) + +/* + * Virtual memory area. We keep a distance to other memory regions to be + * on the safe side. We also use this area for cache aliasing. + */ + +#define VMALLOC_START 0xC0000000 +#define VMALLOC_END 0xC7FEFFFF +#define TLBTEMP_BASE_1 0xC7FF0000 +#define TLBTEMP_BASE_2 0xC7FF8000 + +/* + * Xtensa Linux config PTE layout (when present): + * 31-12: PPN + * 11-6: Software + * 5-4: RING + * 3-0: CA + * + * Similar to the Alpha and MIPS ports, we need to keep track of the ref + * and mod bits in software. We have a software "you can read + * from this page" bit, and a hardware one which actually lets the + * process read from the page. On the same token we have a software + * writable bit and the real hardware one which actually lets the + * process write to the page. + * + * See further below for PTE layout for swapped-out pages. + */ + +#define _PAGE_HW_EXEC (1<<0) /* hardware: page is executable */ +#define _PAGE_HW_WRITE (1<<1) /* hardware: page is writable */ + +#define _PAGE_FILE (1<<1) /* non-linear mapping, if !present */ +#define _PAGE_PROTNONE (3<<0) /* special case for VM_PROT_NONE */ + +/* None of these cache modes include MP coherency: */ +#define _PAGE_CA_BYPASS (0<<2) /* bypass, non-speculative */ +#define _PAGE_CA_WB (1<<2) /* write-back */ +#define _PAGE_CA_WT (2<<2) /* write-through */ +#define _PAGE_CA_MASK (3<<2) +#define _PAGE_INVALID (3<<2) + +#define _PAGE_USER (1<<4) /* user access (ring=1) */ + +/* Software */ +#define _PAGE_WRITABLE_BIT 6 +#define _PAGE_WRITABLE (1<<6) /* software: page writable */ +#define _PAGE_DIRTY (1<<7) /* software: page dirty */ +#define _PAGE_ACCESSED (1<<8) /* software: page accessed (read) */ + +/* On older HW revisions, we always have to set bit 0 */ +#if XCHAL_HW_VERSION_MAJOR < 2000 +# define _PAGE_VALID (1<<0) +#else +# define _PAGE_VALID 0 +#endif + +#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY) +#define _PAGE_PRESENT (_PAGE_VALID | _PAGE_CA_WB | _PAGE_ACCESSED) + +#ifdef CONFIG_MMU + +#define PAGE_NONE __pgprot(_PAGE_INVALID | _PAGE_USER | _PAGE_PROTNONE) +#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER) +#define PAGE_COPY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_HW_EXEC) +#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER) +#define PAGE_READONLY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_HW_EXEC) +#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_WRITABLE) +#define PAGE_SHARED_EXEC \ + __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_WRITABLE | _PAGE_HW_EXEC) +#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_HW_WRITE) +#define PAGE_KERNEL_EXEC __pgprot(_PAGE_PRESENT|_PAGE_HW_WRITE|_PAGE_HW_EXEC) + +#if (DCACHE_WAY_SIZE > PAGE_SIZE) +# define _PAGE_DIRECTORY (_PAGE_VALID | _PAGE_ACCESSED) +#else +# define _PAGE_DIRECTORY (_PAGE_VALID | _PAGE_ACCESSED | _PAGE_CA_WB) +#endif + +#else /* no mmu */ + +# define PAGE_NONE __pgprot(0) +# define PAGE_SHARED __pgprot(0) +# define PAGE_COPY __pgprot(0) +# define PAGE_READONLY __pgprot(0) +# define PAGE_KERNEL __pgprot(0) + +#endif + +/* + * On certain configurations of Xtensa MMUs (eg. the initial Linux config), + * the MMU can't do page protection for execute, and considers that the same as + * read. Also, write permissions may imply read permissions. + * What follows is the closest we can get by reasonable means.. + * See linux/mm/mmap.c for protection_map[] array that uses these definitions. + */ +#define __P000 PAGE_NONE /* private --- */ +#define __P001 PAGE_READONLY /* private --r */ +#define __P010 PAGE_COPY /* private -w- */ +#define __P011 PAGE_COPY /* private -wr */ +#define __P100 PAGE_READONLY_EXEC /* private x-- */ +#define __P101 PAGE_READONLY_EXEC /* private x-r */ +#define __P110 PAGE_COPY_EXEC /* private xw- */ +#define __P111 PAGE_COPY_EXEC /* private xwr */ + +#define __S000 PAGE_NONE /* shared --- */ +#define __S001 PAGE_READONLY /* shared --r */ +#define __S010 PAGE_SHARED /* shared -w- */ +#define __S011 PAGE_SHARED /* shared -wr */ +#define __S100 PAGE_READONLY_EXEC /* shared x-- */ +#define __S101 PAGE_READONLY_EXEC /* shared x-r */ +#define __S110 PAGE_SHARED_EXEC /* shared xw- */ +#define __S111 PAGE_SHARED_EXEC /* shared xwr */ + +#ifndef __ASSEMBLY__ + +#define pte_ERROR(e) \ + printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e)) +#define pgd_ERROR(e) \ + printk("%s:%d: bad pgd entry %08lx.\n", __FILE__, __LINE__, pgd_val(e)) + +extern unsigned long empty_zero_page[1024]; + +#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) + +#ifdef CONFIG_MMU +extern pgd_t swapper_pg_dir[PAGE_SIZE/sizeof(pgd_t)]; +extern void paging_init(void); +extern void pgtable_cache_init(void); +#else +# define swapper_pg_dir NULL +static inline void paging_init(void) { } +static inline void pgtable_cache_init(void) { } +#endif + +/* + * The pmd contains the kernel virtual address of the pte page. + */ +#define pmd_page_vaddr(pmd) ((unsigned long)(pmd_val(pmd) & PAGE_MASK)) +#define pmd_page(pmd) virt_to_page(pmd_val(pmd)) + +/* + * pte status. + */ +#define pte_none(pte) (pte_val(pte) == _PAGE_INVALID) +#define pte_present(pte) \ + (((pte_val(pte) & _PAGE_CA_MASK) != _PAGE_INVALID) \ + || ((pte_val(pte) & _PAGE_PROTNONE) == _PAGE_PROTNONE)) +#define pte_clear(mm,addr,ptep) \ + do { update_pte(ptep, __pte(_PAGE_INVALID)); } while(0) + +#define pmd_none(pmd) (!pmd_val(pmd)) +#define pmd_present(pmd) (pmd_val(pmd) & PAGE_MASK) +#define pmd_bad(pmd) (pmd_val(pmd) & ~PAGE_MASK) +#define pmd_clear(pmdp) do { set_pmd(pmdp, __pmd(0)); } while (0) + +static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITABLE; } +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_special(pte_t pte) { return 0; } + +static inline pte_t pte_wrprotect(pte_t pte) + { pte_val(pte) &= ~(_PAGE_WRITABLE | _PAGE_HW_WRITE); return pte; } +static inline pte_t pte_mkclean(pte_t pte) + { pte_val(pte) &= ~(_PAGE_DIRTY | _PAGE_HW_WRITE); return pte; } +static inline pte_t pte_mkold(pte_t pte) + { pte_val(pte) &= ~_PAGE_ACCESSED; return pte; } +static inline pte_t pte_mkdirty(pte_t pte) + { pte_val(pte) |= _PAGE_DIRTY; return pte; } +static inline pte_t pte_mkyoung(pte_t pte) + { pte_val(pte) |= _PAGE_ACCESSED; return pte; } +static inline pte_t pte_mkwrite(pte_t pte) + { pte_val(pte) |= _PAGE_WRITABLE; return pte; } +static inline pte_t pte_mkspecial(pte_t pte) + { return pte; } + +/* + * Conversion functions: convert a page and protection to a page entry, + * and a page entry and page directory to the page they refer to. + */ + +#define pte_pfn(pte) (pte_val(pte) >> PAGE_SHIFT) +#define pte_same(a,b) (pte_val(a) == pte_val(b)) +#define pte_page(x) pfn_to_page(pte_pfn(x)) +#define pfn_pte(pfn, prot) __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot)) +#define mk_pte(page, prot) pfn_pte(page_to_pfn(page), prot) + +static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) +{ + return __pte((pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot)); +} + +/* + * Certain architectures need to do special things when pte's + * within a page table are directly modified. Thus, the following + * hook is made available. + */ +static inline void update_pte(pte_t *ptep, pte_t pteval) +{ + *ptep = pteval; +#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK + __asm__ __volatile__ ("dhwb %0, 0" :: "a" (ptep)); +#endif + +} + +struct mm_struct; + +static inline void +set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pteval) +{ + update_pte(ptep, pteval); +} + + +static inline void +set_pmd(pmd_t *pmdp, pmd_t pmdval) +{ + *pmdp = pmdval; +} + +struct vm_area_struct; + +static inline int +ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, + pte_t *ptep) +{ + pte_t pte = *ptep; + if (!pte_young(pte)) + return 0; + update_pte(ptep, pte_mkold(pte)); + return 1; +} + +static inline pte_t +ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) +{ + pte_t pte = *ptep; + pte_clear(mm, addr, ptep); + return pte; +} + +static inline void +ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep) +{ + pte_t pte = *ptep; + update_pte(ptep, pte_wrprotect(pte)); +} + +/* to find an entry in a kernel page-table-directory */ +#define pgd_offset_k(address) pgd_offset(&init_mm, address) + +/* to find an entry in a page-table-directory */ +#define pgd_offset(mm,address) ((mm)->pgd + pgd_index(address)) + +#define pgd_index(address) ((address) >> PGDIR_SHIFT) + +/* Find an entry in the second-level page table.. */ +#define pmd_offset(dir,address) ((pmd_t*)(dir)) + +/* Find an entry in the third-level page table.. */ +#define pte_index(address) (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) +#define pte_offset_kernel(dir,addr) \ + ((pte_t*) pmd_page_vaddr(*(dir)) + pte_index(addr)) +#define pte_offset_map(dir,addr) pte_offset_kernel((dir),(addr)) +#define pte_unmap(pte) do { } while (0) + + +/* + * Encode and decode a swap entry. + * + * Format of swap pte: + * bit 0 MBZ + * bit 1 page-file (must be zero) + * bits 2 - 3 page hw access mode (must be 11: _PAGE_INVALID) + * bits 4 - 5 ring protection (must be 01: _PAGE_USER) + * bits 6 - 10 swap type (5 bits -> 32 types) + * bits 11 - 31 swap offset / PAGE_SIZE (21 bits -> 8GB) + + * Format of file pte: + * bit 0 MBZ + * bit 1 page-file (must be one: _PAGE_FILE) + * bits 2 - 3 page hw access mode (must be 11: _PAGE_INVALID) + * bits 4 - 5 ring protection (must be 01: _PAGE_USER) + * bits 6 - 31 file offset / PAGE_SIZE + */ + +#define __swp_type(entry) (((entry).val >> 6) & 0x1f) +#define __swp_offset(entry) ((entry).val >> 11) +#define __swp_entry(type,offs) \ + ((swp_entry_t) {((type) << 6) | ((offs) << 11) | _PAGE_INVALID}) +#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) +#define __swp_entry_to_pte(x) ((pte_t) { (x).val }) + +#define PTE_FILE_MAX_BITS 28 +#define pte_to_pgoff(pte) (pte_val(pte) >> 4) +#define pgoff_to_pte(off) \ + ((pte_t) { ((off) << 4) | _PAGE_INVALID | _PAGE_FILE }) + +#endif /* !defined (__ASSEMBLY__) */ + + +#ifdef __ASSEMBLY__ + +/* Assembly macro _PGD_INDEX is the same as C pgd_index(unsigned long), + * _PGD_OFFSET as C pgd_offset(struct mm_struct*, unsigned long), + * _PMD_OFFSET as C pmd_offset(pgd_t*, unsigned long) + * _PTE_OFFSET as C pte_offset(pmd_t*, unsigned long) + * + * Note: We require an additional temporary register which can be the same as + * the register that holds the address. + * + * ((pte_t*) ((unsigned long)(pmd_val(*pmd) & PAGE_MASK)) + pte_index(addr)) + * + */ +#define _PGD_INDEX(rt,rs) extui rt, rs, PGDIR_SHIFT, 32-PGDIR_SHIFT +#define _PTE_INDEX(rt,rs) extui rt, rs, PAGE_SHIFT, PTRS_PER_PTE_SHIFT + +#define _PGD_OFFSET(mm,adr,tmp) l32i mm, mm, MM_PGD; \ + _PGD_INDEX(tmp, adr); \ + addx4 mm, tmp, mm + +#define _PTE_OFFSET(pmd,adr,tmp) _PTE_INDEX(tmp, adr); \ + srli pmd, pmd, PAGE_SHIFT; \ + slli pmd, pmd, PAGE_SHIFT; \ + addx4 pmd, tmp, pmd + +#else + +#define kern_addr_valid(addr) (1) + +extern void update_mmu_cache(struct vm_area_struct * vma, + unsigned long address, pte_t *ptep); + +/* + * remap a physical page `pfn' of size `size' with page protection `prot' + * into virtual address `from' + */ + +#define io_remap_pfn_range(vma,from,pfn,size,prot) \ + remap_pfn_range(vma, from, pfn, size, prot) + +typedef pte_t *pte_addr_t; + +#endif /* !defined (__ASSEMBLY__) */ + +#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG +#define __HAVE_ARCH_PTEP_GET_AND_CLEAR +#define __HAVE_ARCH_PTEP_SET_WRPROTECT +#define __HAVE_ARCH_PTEP_MKDIRTY +#define __HAVE_ARCH_PTE_SAME + +#include <asm-generic/pgtable.h> + +#endif /* _XTENSA_PGTABLE_H */ diff --git a/arch/xtensa/include/asm/platform.h b/arch/xtensa/include/asm/platform.h new file mode 100644 index 00000000..7d936e58 --- /dev/null +++ b/arch/xtensa/include/asm/platform.h @@ -0,0 +1,78 @@ +/* + * Platform specific functions + * + * 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) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_PLATFORM_H +#define _XTENSA_PLATFORM_H + +#include <linux/types.h> +#include <linux/pci.h> + +#include <asm/bootparam.h> + +/* + * platform_init is called before the mmu is initialized to give the + * platform a early hook-up. bp_tag_t is a list of configuration tags + * passed from the boot-loader. + */ +extern void platform_init(bp_tag_t*); + +/* + * platform_setup is called from setup_arch with a pointer to the command-line + * string. + */ +extern void platform_setup (char **); + +/* + * platform_init_irq is called from init_IRQ. + */ +extern void platform_init_irq (void); + +/* + * platform_restart is called to restart the system. + */ +extern void platform_restart (void); + +/* + * platform_halt is called to stop the system and halt. + */ +extern void platform_halt (void); + +/* + * platform_power_off is called to stop the system and power it off. + */ +extern void platform_power_off (void); + +/* + * platform_idle is called from the idle function. + */ +extern void platform_idle (void); + +/* + * platform_heartbeat is called every HZ + */ +extern void platform_heartbeat (void); + +/* + * platform_pcibios_init is called to allow the platform to setup the pci bus. + */ +extern void platform_pcibios_init (void); + +/* + * platform_pcibios_fixup allows to modify the PCI configuration. + */ +extern int platform_pcibios_fixup (void); + +/* + * platform_calibrate_ccount calibrates cpu clock freq (CONFIG_XTENSA_CALIBRATE) + */ +extern void platform_calibrate_ccount (void); + +#endif /* _XTENSA_PLATFORM_H */ + diff --git a/arch/xtensa/include/asm/poll.h b/arch/xtensa/include/asm/poll.h new file mode 100644 index 00000000..9d2d5993 --- /dev/null +++ b/arch/xtensa/include/asm/poll.h @@ -0,0 +1,20 @@ +/* + * include/asm-xtensa/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. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_POLL_H +#define _XTENSA_POLL_H + +#define POLLWRNORM POLLOUT +#define POLLWRBAND 0x0100 +#define POLLREMOVE 0x0800 + +#include <asm-generic/poll.h> + +#endif /* _XTENSA_POLL_H */ diff --git a/arch/xtensa/include/asm/posix_types.h b/arch/xtensa/include/asm/posix_types.h new file mode 100644 index 00000000..6e96be0d --- /dev/null +++ b/arch/xtensa/include/asm/posix_types.h @@ -0,0 +1,39 @@ +/* + * include/asm-xtensa/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. + * + * Largely copied from include/asm-ppc/posix_types.h + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_POSIX_TYPES_H +#define _XTENSA_POSIX_TYPES_H + +/* + * 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 short __kernel_ipc_pid_t; +#define __kernel_ipc_pid_t __kernel_ipc_pid_t + +typedef unsigned int __kernel_size_t; +typedef int __kernel_ssize_t; +typedef long __kernel_ptrdiff_t; +#define __kernel_size_t __kernel_size_t + +typedef unsigned short __kernel_old_uid_t; +typedef unsigned short __kernel_old_gid_t; +#define __kernel_old_uid_t __kernel_old_uid_t + +typedef unsigned short __kernel_old_dev_t; +#define __kernel_old_dev_t __kernel_old_dev_t + +#include <asm-generic/posix_types.h> + +#endif /* _XTENSA_POSIX_TYPES_H */ diff --git a/arch/xtensa/include/asm/processor.h b/arch/xtensa/include/asm/processor.h new file mode 100644 index 00000000..3acb26e8 --- /dev/null +++ b/arch/xtensa/include/asm/processor.h @@ -0,0 +1,200 @@ +/* + * include/asm-xtensa/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. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_PROCESSOR_H +#define _XTENSA_PROCESSOR_H + +#include <variant/core.h> +#include <platform/hardware.h> + +#include <linux/compiler.h> +#include <asm/ptrace.h> +#include <asm/types.h> +#include <asm/regs.h> + +/* Assertions. */ + +#if (XCHAL_HAVE_WINDOWED != 1) +# error Linux requires the Xtensa Windowed Registers Option. +#endif + +#define ARCH_SLAB_MINALIGN XCHAL_DATA_WIDTH + +/* + * User space process size: 1 GB. + * Windowed call ABI requires caller and callee to be located within the same + * 1 GB region. The C compiler places trampoline code on the stack for sources + * that take the address of a nested C function (a feature used by glibc), so + * the 1 GB requirement applies to the stack as well. + */ + +#ifdef CONFIG_MMU +#define TASK_SIZE __XTENSA_UL_CONST(0x40000000) +#else +#define TASK_SIZE (PLATFORM_DEFAULT_MEM_START + PLATFORM_DEFAULT_MEM_SIZE) +#endif + +#define STACK_TOP TASK_SIZE +#define STACK_TOP_MAX STACK_TOP + +/* + * General exception cause assigned to debug exceptions. Debug exceptions go + * to their own vector, rather than the general exception vectors (user, + * kernel, double); and their specific causes are reported via DEBUGCAUSE + * rather than EXCCAUSE. However it is sometimes convenient to redirect debug + * exceptions to the general exception mechanism. To do this, an otherwise + * unused EXCCAUSE value was assigned to debug exceptions for this purpose. + */ + +#define EXCCAUSE_MAPPED_DEBUG 63 + +/* + * We use DEPC also as a flag to distinguish between double and regular + * exceptions. For performance reasons, DEPC might contain the value of + * EXCCAUSE for regular exceptions, so we use this definition to mark a + * valid double exception address. + * (Note: We use it in bgeui, so it should be 64, 128, or 256) + */ + +#define VALID_DOUBLE_EXCEPTION_ADDRESS 64 + +/* LOCKLEVEL defines the interrupt level that masks all + * general-purpose interrupts. + */ +#define LOCKLEVEL 1 + +/* WSBITS and WBBITS are the width of the WINDOWSTART and WINDOWBASE + * registers + */ +#define WSBITS (XCHAL_NUM_AREGS / 4) /* width of WINDOWSTART in bits */ +#define WBBITS (XCHAL_NUM_AREGS_LOG2 - 2) /* width of WINDOWBASE in bits */ + +#ifndef __ASSEMBLY__ + +/* Build a valid return address for the specified call winsize. + * winsize must be 1 (call4), 2 (call8), or 3 (call12) + */ +#define MAKE_RA_FOR_CALL(ra,ws) (((ra) & 0x3fffffff) | (ws) << 30) + +/* Convert return address to a valid pc + * Note: We assume that the stack pointer is in the same 1GB ranges as the ra + */ +#define MAKE_PC_FROM_RA(ra,sp) (((ra) & 0x3fffffff) | ((sp) & 0xc0000000)) + +typedef struct { + unsigned long seg; +} mm_segment_t; + +struct thread_struct { + + /* kernel's return address and stack pointer for context switching */ + unsigned long ra; /* kernel's a0: return address and window call size */ + unsigned long sp; /* kernel's a1: stack pointer */ + + mm_segment_t current_ds; /* see uaccess.h for example uses */ + + /* struct xtensa_cpuinfo info; */ + + unsigned long bad_vaddr; /* last user fault */ + unsigned long bad_uaddr; /* last kernel fault accessing user space */ + unsigned long error_code; + + unsigned long ibreak[XCHAL_NUM_IBREAK]; + unsigned long dbreaka[XCHAL_NUM_DBREAK]; + unsigned long dbreakc[XCHAL_NUM_DBREAK]; + + /* Make structure 16 bytes aligned. */ + int align[0] __attribute__ ((aligned(16))); +}; + + +/* + * Default implementation of macro that returns current + * instruction pointer ("program counter"). + */ +#define current_text_addr() ({ __label__ _l; _l: &&_l;}) + + +/* This decides where the kernel will search for a free chunk of vm + * space during mmap's. + */ +#define TASK_UNMAPPED_BASE (TASK_SIZE / 2) + +#define INIT_THREAD \ +{ \ + ra: 0, \ + sp: sizeof(init_stack) + (long) &init_stack, \ + current_ds: {0}, \ + /*info: {0}, */ \ + bad_vaddr: 0, \ + bad_uaddr: 0, \ + error_code: 0, \ +} + + +/* + * Do necessary setup to start up a newly executed thread. + * Note: We set-up ps as if we did a call4 to the new pc. + * set_thread_state in signal.c depends on it. + */ +#define USER_PS_VALUE ((1 << PS_WOE_BIT) | \ + (1 << PS_CALLINC_SHIFT) | \ + (USER_RING << PS_RING_SHIFT) | \ + (1 << PS_UM_BIT) | \ + (1 << PS_EXCM_BIT)) + +/* Clearing a0 terminates the backtrace. */ +#define start_thread(regs, new_pc, new_sp) \ + regs->pc = new_pc; \ + regs->ps = USER_PS_VALUE; \ + regs->areg[1] = new_sp; \ + regs->areg[0] = 0; \ + regs->wmask = 1; \ + regs->depc = 0; \ + regs->windowbase = 0; \ + regs->windowstart = 1; + +/* Forward declaration */ +struct task_struct; +struct mm_struct; + +/* Free all resources held by a thread. */ +#define release_thread(thread) do { } while(0) + +/* Prepare to copy thread state - unlazy all lazy status */ +extern void prepare_to_copy(struct task_struct*); + +/* Create a kernel thread without removing it from tasklists */ +extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); + +/* 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 thread_saved_pc(tsk) (task_pt_regs(tsk)->pc) + +extern unsigned long get_wchan(struct task_struct *p); + +#define KSTK_EIP(tsk) (task_pt_regs(tsk)->pc) +#define KSTK_ESP(tsk) (task_pt_regs(tsk)->areg[1]) + +#define cpu_relax() barrier() + +/* Special register access. */ + +#define WSR(v,sr) __asm__ __volatile__ ("wsr %0,"__stringify(sr) :: "a"(v)); +#define RSR(v,sr) __asm__ __volatile__ ("rsr %0,"__stringify(sr) : "=a"(v)); + +#define set_sr(x,sr) ({unsigned int v=(unsigned int)x; WSR(v,sr);}) +#define get_sr(sr) ({unsigned int v; RSR(v,sr); v; }) + +#endif /* __ASSEMBLY__ */ +#endif /* _XTENSA_PROCESSOR_H */ diff --git a/arch/xtensa/include/asm/ptrace.h b/arch/xtensa/include/asm/ptrace.h new file mode 100644 index 00000000..d85d38da --- /dev/null +++ b/arch/xtensa/include/asm/ptrace.h @@ -0,0 +1,137 @@ +/* + * include/asm-xtensa/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. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_PTRACE_H +#define _XTENSA_PTRACE_H + +/* + * Kernel stack + * + * +-----------------------+ -------- STACK_SIZE + * | register file | | + * +-----------------------+ | + * | struct pt_regs | | + * +-----------------------+ | ------ PT_REGS_OFFSET + * double : 16 bytes spill area : | ^ + * excetion :- - - - - - - - - - - -: | | + * frame : struct pt_regs : | | + * :- - - - - - - - - - - -: | | + * | | | | + * | memory stack | | | + * | | | | + * ~ ~ ~ ~ + * ~ ~ ~ ~ + * | | | | + * | | | | + * +-----------------------+ | | --- STACK_BIAS + * | struct task_struct | | | ^ + * current --> +-----------------------+ | | | + * | struct thread_info | | | | + * +-----------------------+ -------- + */ + +#define KERNEL_STACK_SIZE (2 * PAGE_SIZE) + +/* Offsets for exception_handlers[] (3 x 64-entries x 4-byte tables). */ + +#define EXC_TABLE_KSTK 0x004 /* Kernel Stack */ +#define EXC_TABLE_DOUBLE_SAVE 0x008 /* Double exception save area for a0 */ +#define EXC_TABLE_FIXUP 0x00c /* Fixup handler */ +#define EXC_TABLE_PARAM 0x010 /* For passing a parameter to fixup */ +#define EXC_TABLE_SYSCALL_SAVE 0x014 /* For fast syscall handler */ +#define EXC_TABLE_FAST_USER 0x100 /* Fast user exception handler */ +#define EXC_TABLE_FAST_KERNEL 0x200 /* Fast kernel exception handler */ +#define EXC_TABLE_DEFAULT 0x300 /* Default C-Handler */ +#define EXC_TABLE_SIZE 0x400 + +/* Registers used by strace */ + +#define REG_A_BASE 0x0000 +#define REG_AR_BASE 0x0100 +#define REG_PC 0x0020 +#define REG_PS 0x02e6 +#define REG_WB 0x0248 +#define REG_WS 0x0249 +#define REG_LBEG 0x0200 +#define REG_LEND 0x0201 +#define REG_LCOUNT 0x0202 +#define REG_SAR 0x0203 + +#define SYSCALL_NR 0x00ff + +/* Other PTRACE_ values defined in <linux/ptrace.h> using values 0-9,16,17,24 */ + +#define PTRACE_GETREGS 12 +#define PTRACE_SETREGS 13 +#define PTRACE_GETXTREGS 18 +#define PTRACE_SETXTREGS 19 + +#ifdef __KERNEL__ + +#ifndef __ASSEMBLY__ + +#include <asm/coprocessor.h> + +/* + * 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 pc; /* 4 */ + unsigned long ps; /* 8 */ + unsigned long depc; /* 12 */ + unsigned long exccause; /* 16 */ + unsigned long excvaddr; /* 20 */ + unsigned long debugcause; /* 24 */ + unsigned long wmask; /* 28 */ + unsigned long lbeg; /* 32 */ + unsigned long lend; /* 36 */ + unsigned long lcount; /* 40 */ + unsigned long sar; /* 44 */ + unsigned long windowbase; /* 48 */ + unsigned long windowstart; /* 52 */ + unsigned long syscall; /* 56 */ + unsigned long icountlevel; /* 60 */ + int reserved[1]; /* 64 */ + + /* Additional configurable registers that are used by the compiler. */ + xtregs_opt_t xtregs_opt; + + /* Make sure the areg field is 16 bytes aligned. */ + int align[0] __attribute__ ((aligned(16))); + + /* current register frame. + * Note: The ESF for kernel exceptions ends after 16 registers! + */ + unsigned long areg[16]; /* 128 (64) */ +}; + +#include <variant/core.h> + +# define arch_has_single_step() (1) +# define task_pt_regs(tsk) ((struct pt_regs*) \ + (task_stack_page(tsk) + KERNEL_STACK_SIZE - (XCHAL_NUM_AREGS-16)*4) - 1) +# define user_mode(regs) (((regs)->ps & 0x00000020)!=0) +# define instruction_pointer(regs) ((regs)->pc) + +# ifndef CONFIG_SMP +# define profile_pc(regs) instruction_pointer(regs) +# endif + +#else /* __ASSEMBLY__ */ + +# include <asm/asm-offsets.h> +#define PT_REGS_OFFSET (KERNEL_STACK_SIZE - PT_USER_SIZE) + +#endif /* !__ASSEMBLY__ */ + +#endif /* __KERNEL__ */ + +#endif /* _XTENSA_PTRACE_H */ diff --git a/arch/xtensa/include/asm/regs.h b/arch/xtensa/include/asm/regs.h new file mode 100644 index 00000000..d4baed24 --- /dev/null +++ b/arch/xtensa/include/asm/regs.h @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2006 Tensilica, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2.1 of the GNU Lesser General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, + * USA. + */ + +#ifndef _XTENSA_REGS_H +#define _XTENSA_REGS_H + +/* Special registers. */ + +#define LBEG 0 +#define LEND 1 +#define LCOUNT 2 +#define SAR 3 +#define BR 4 +#define SCOMPARE1 12 +#define ACCHI 16 +#define ACCLO 17 +#define MR 32 +#define WINDOWBASE 72 +#define WINDOWSTART 73 +#define PTEVADDR 83 +#define RASID 90 +#define ITLBCFG 91 +#define DTLBCFG 92 +#define IBREAKENABLE 96 +#define DDR 104 +#define IBREAKA 128 +#define DBREAKA 144 +#define DBREAKC 160 +#define EPC 176 +#define EPC_1 177 +#define DEPC 192 +#define EPS 192 +#define EPS_1 193 +#define EXCSAVE 208 +#define EXCSAVE_1 209 +#define INTERRUPT 226 +#define INTENABLE 228 +#define PS 230 +#define THREADPTR 231 +#define EXCCAUSE 232 +#define DEBUGCAUSE 233 +#define CCOUNT 234 +#define PRID 235 +#define ICOUNT 236 +#define ICOUNTLEVEL 237 +#define EXCVADDR 238 +#define CCOMPARE 240 +#define MISC 244 + +/* Special names for read-only and write-only interrupt registers. */ + +#define INTREAD 226 +#define INTSET 226 +#define INTCLEAR 227 + +/* EXCCAUSE register fields */ + +#define EXCCAUSE_EXCCAUSE_SHIFT 0 +#define EXCCAUSE_EXCCAUSE_MASK 0x3F + +#define EXCCAUSE_ILLEGAL_INSTRUCTION 0 +#define EXCCAUSE_SYSTEM_CALL 1 +#define EXCCAUSE_INSTRUCTION_FETCH_ERROR 2 +#define EXCCAUSE_LOAD_STORE_ERROR 3 +#define EXCCAUSE_LEVEL1_INTERRUPT 4 +#define EXCCAUSE_ALLOCA 5 +#define EXCCAUSE_INTEGER_DIVIDE_BY_ZERO 6 +#define EXCCAUSE_SPECULATION 7 +#define EXCCAUSE_PRIVILEGED 8 +#define EXCCAUSE_UNALIGNED 9 +#define EXCCAUSE_ITLB_MISS 16 +#define EXCCAUSE_ITLB_MULTIHIT 17 +#define EXCCAUSE_ITLB_PRIVILEGE 18 +#define EXCCAUSE_ITLB_SIZE_RESTRICTION 19 +#define EXCCAUSE_FETCH_CACHE_ATTRIBUTE 20 +#define EXCCAUSE_DTLB_MISS 24 +#define EXCCAUSE_DTLB_MULTIHIT 25 +#define EXCCAUSE_DTLB_PRIVILEGE 26 +#define EXCCAUSE_DTLB_SIZE_RESTRICTION 27 +#define EXCCAUSE_LOAD_CACHE_ATTRIBUTE 28 +#define EXCCAUSE_STORE_CACHE_ATTRIBUTE 29 +#define EXCCAUSE_COPROCESSOR0_DISABLED 32 +#define EXCCAUSE_COPROCESSOR1_DISABLED 33 +#define EXCCAUSE_COPROCESSOR2_DISABLED 34 +#define EXCCAUSE_COPROCESSOR3_DISABLED 35 +#define EXCCAUSE_COPROCESSOR4_DISABLED 36 +#define EXCCAUSE_COPROCESSOR5_DISABLED 37 +#define EXCCAUSE_COPROCESSOR6_DISABLED 38 +#define EXCCAUSE_COPROCESSOR7_DISABLED 39 + +/* PS register fields. */ + +#define PS_WOE_BIT 18 +#define PS_CALLINC_SHIFT 16 +#define PS_CALLINC_MASK 0x00030000 +#define PS_OWB_SHIFT 8 +#define PS_OWB_MASK 0x00000F00 +#define PS_RING_SHIFT 6 +#define PS_RING_MASK 0x000000C0 +#define PS_UM_BIT 5 +#define PS_EXCM_BIT 4 +#define PS_INTLEVEL_SHIFT 0 +#define PS_INTLEVEL_MASK 0x0000000F + +/* DBREAKCn register fields. */ + +#define DBREAKC_MASK_BIT 0 +#define DBREAKC_MASK_MASK 0x0000003F +#define DBREAKC_LOAD_BIT 30 +#define DBREAKC_LOAD_MASK 0x40000000 +#define DBREAKC_STOR_BIT 31 +#define DBREAKC_STOR_MASK 0x80000000 + +/* DEBUGCAUSE register fields. */ + +#define DEBUGCAUSE_DEBUGINT_BIT 5 /* External debug interrupt */ +#define DEBUGCAUSE_BREAKN_BIT 4 /* BREAK.N instruction */ +#define DEBUGCAUSE_BREAK_BIT 3 /* BREAK instruction */ +#define DEBUGCAUSE_DBREAK_BIT 2 /* DBREAK match */ +#define DEBUGCAUSE_IBREAK_BIT 1 /* IBREAK match */ +#define DEBUGCAUSE_ICOUNT_BIT 0 /* ICOUNT would incr. to zero */ + +#endif /* _XTENSA_SPECREG_H */ + diff --git a/arch/xtensa/include/asm/resource.h b/arch/xtensa/include/asm/resource.h new file mode 100644 index 00000000..17b5ab31 --- /dev/null +++ b/arch/xtensa/include/asm/resource.h @@ -0,0 +1,16 @@ +/* + * include/asm-xtensa/resource.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_RESOURCE_H +#define _XTENSA_RESOURCE_H + +#include <asm-generic/resource.h> + +#endif /* _XTENSA_RESOURCE_H */ diff --git a/arch/xtensa/include/asm/rmap.h b/arch/xtensa/include/asm/rmap.h new file mode 100644 index 00000000..649588b7 --- /dev/null +++ b/arch/xtensa/include/asm/rmap.h @@ -0,0 +1,16 @@ +/* + * include/asm-xtensa/rmap.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_RMAP_H +#define _XTENSA_RMAP_H + +#include <asm-generic/rmap.h> + +#endif diff --git a/arch/xtensa/include/asm/rwsem.h b/arch/xtensa/include/asm/rwsem.h new file mode 100644 index 00000000..249619e7 --- /dev/null +++ b/arch/xtensa/include/asm/rwsem.h @@ -0,0 +1,131 @@ +/* + * include/asm-xtensa/rwsem.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. + * + * Largely copied from include/asm-ppc/rwsem.h + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_RWSEM_H +#define _XTENSA_RWSEM_H + +#ifndef _LINUX_RWSEM_H +#error "Please don't include <asm/rwsem.h> directly, use <linux/rwsem.h> instead." +#endif + +#define RWSEM_UNLOCKED_VALUE 0x00000000 +#define RWSEM_ACTIVE_BIAS 0x00000001 +#define RWSEM_ACTIVE_MASK 0x0000ffff +#define RWSEM_WAITING_BIAS (-0x00010000) +#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS +#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) + +/* + * lock for reading + */ +static inline void __down_read(struct rw_semaphore *sem) +{ + if (atomic_add_return(1,(atomic_t *)(&sem->count)) > 0) + smp_wmb(); + else + rwsem_down_read_failed(sem); +} + +static inline int __down_read_trylock(struct rw_semaphore *sem) +{ + int tmp; + + while ((tmp = sem->count) >= 0) { + if (tmp == cmpxchg(&sem->count, tmp, + tmp + RWSEM_ACTIVE_READ_BIAS)) { + smp_wmb(); + return 1; + } + } + return 0; +} + +/* + * lock for writing + */ +static inline void __down_write(struct rw_semaphore *sem) +{ + int tmp; + + tmp = atomic_add_return(RWSEM_ACTIVE_WRITE_BIAS, + (atomic_t *)(&sem->count)); + if (tmp == RWSEM_ACTIVE_WRITE_BIAS) + smp_wmb(); + else + rwsem_down_write_failed(sem); +} + +static inline int __down_write_trylock(struct rw_semaphore *sem) +{ + int tmp; + + tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE, + RWSEM_ACTIVE_WRITE_BIAS); + smp_wmb(); + return tmp == RWSEM_UNLOCKED_VALUE; +} + +/* + * unlock after reading + */ +static inline void __up_read(struct rw_semaphore *sem) +{ + int tmp; + + smp_wmb(); + tmp = atomic_sub_return(1,(atomic_t *)(&sem->count)); + if (tmp < -1 && (tmp & RWSEM_ACTIVE_MASK) == 0) + rwsem_wake(sem); +} + +/* + * unlock after writing + */ +static inline void __up_write(struct rw_semaphore *sem) +{ + smp_wmb(); + if (atomic_sub_return(RWSEM_ACTIVE_WRITE_BIAS, + (atomic_t *)(&sem->count)) < 0) + rwsem_wake(sem); +} + +/* + * implement atomic add functionality + */ +static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem) +{ + atomic_add(delta, (atomic_t *)(&sem->count)); +} + +/* + * downgrade write lock to read lock + */ +static inline void __downgrade_write(struct rw_semaphore *sem) +{ + int tmp; + + smp_wmb(); + tmp = atomic_add_return(-RWSEM_WAITING_BIAS, (atomic_t *)(&sem->count)); + if (tmp < 0) + rwsem_downgrade_wake(sem); +} + +/* + * implement exchange and add functionality + */ +static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem) +{ + smp_mb(); + return atomic_add_return(delta, (atomic_t *)(&sem->count)); +} + +#endif /* _XTENSA_RWSEM_H */ diff --git a/arch/xtensa/include/asm/scatterlist.h b/arch/xtensa/include/asm/scatterlist.h new file mode 100644 index 00000000..a0421a61 --- /dev/null +++ b/arch/xtensa/include/asm/scatterlist.h @@ -0,0 +1,16 @@ +/* + * include/asm-xtensa/scatterlist.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_SCATTERLIST_H +#define _XTENSA_SCATTERLIST_H + +#include <asm-generic/scatterlist.h> + +#endif /* _XTENSA_SCATTERLIST_H */ diff --git a/arch/xtensa/include/asm/sections.h b/arch/xtensa/include/asm/sections.h new file mode 100644 index 00000000..40b5191b --- /dev/null +++ b/arch/xtensa/include/asm/sections.h @@ -0,0 +1,16 @@ +/* + * include/asm-xtensa/sections.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_SECTIONS_H +#define _XTENSA_SECTIONS_H + +#include <asm-generic/sections.h> + +#endif /* _XTENSA_SECTIONS_H */ diff --git a/arch/xtensa/include/asm/segment.h b/arch/xtensa/include/asm/segment.h new file mode 100644 index 00000000..a2eb547a --- /dev/null +++ b/arch/xtensa/include/asm/segment.h @@ -0,0 +1,16 @@ +/* + * include/asm-xtensa/segment.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_SEGMENT_H +#define _XTENSA_SEGMENT_H + +#include <asm/uaccess.h> + +#endif /* _XTENSA_SEGEMENT_H */ diff --git a/arch/xtensa/include/asm/sembuf.h b/arch/xtensa/include/asm/sembuf.h new file mode 100644 index 00000000..c1587049 --- /dev/null +++ b/arch/xtensa/include/asm/sembuf.h @@ -0,0 +1,44 @@ +/* + * include/asm-xtensa/sembuf.h + * + * The semid64_ds structure for Xtensa architecture. + * + * 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) 2001 - 2005 Tensilica Inc. + * + * 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 + * + */ + +#ifndef _XTENSA_SEMBUF_H +#define _XTENSA_SEMBUF_H + +#include <asm/byteorder.h> + +struct semid64_ds { + struct ipc64_perm sem_perm; /* permissions .. see ipc.h */ +#ifdef __XTENSA_EL__ + __kernel_time_t sem_otime; /* last semop time */ + unsigned long __unused1; + __kernel_time_t sem_ctime; /* last change time */ + unsigned long __unused2; +#else + unsigned long __unused1; + __kernel_time_t sem_otime; /* last semop time */ + unsigned long __unused2; + __kernel_time_t sem_ctime; /* last change time */ +#endif + unsigned long sem_nsems; /* no. of semaphores in array */ + unsigned long __unused3; + unsigned long __unused4; +}; + +#endif /* __ASM_XTENSA_SEMBUF_H */ diff --git a/arch/xtensa/include/asm/serial.h b/arch/xtensa/include/asm/serial.h new file mode 100644 index 00000000..a8a24932 --- /dev/null +++ b/arch/xtensa/include/asm/serial.h @@ -0,0 +1,18 @@ +/* + * include/asm-xtensa/serial.h + * + * Configuration details for 8250, 16450, 16550, etc. serial ports + * + * 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) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_SERIAL_H +#define _XTENSA_SERIAL_H + +#include <platform/serial.h> + +#endif /* _XTENSA_SERIAL_H */ diff --git a/arch/xtensa/include/asm/setup.h b/arch/xtensa/include/asm/setup.h new file mode 100644 index 00000000..9fa8ad97 --- /dev/null +++ b/arch/xtensa/include/asm/setup.h @@ -0,0 +1,18 @@ +/* + * include/asm-xtensa/setup.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_SETUP_H +#define _XTENSA_SETUP_H + +#define COMMAND_LINE_SIZE 256 + +extern void set_except_vector(int n, void *addr); + +#endif diff --git a/arch/xtensa/include/asm/shmbuf.h b/arch/xtensa/include/asm/shmbuf.h new file mode 100644 index 00000000..ad4b0121 --- /dev/null +++ b/arch/xtensa/include/asm/shmbuf.h @@ -0,0 +1,71 @@ +/* + * include/asm-xtensa/shmbuf.h + * + * The shmid64_ds structure for Xtensa 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 + * + * 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) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_SHMBUF_H +#define _XTENSA_SHMBUF_H + +#if defined (__XTENSA_EL__) +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; +}; +#elif defined (__XTENSA_EB__) +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; +}; +#else +# error endian order not defined +#endif + + +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 /* _XTENSA_SHMBUF_H */ diff --git a/arch/xtensa/include/asm/shmparam.h b/arch/xtensa/include/asm/shmparam.h new file mode 100644 index 00000000..c8cc16c3 --- /dev/null +++ b/arch/xtensa/include/asm/shmparam.h @@ -0,0 +1,21 @@ +/* + * include/asm-xtensa/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. + */ + +#ifndef _XTENSA_SHMPARAM_H +#define _XTENSA_SHMPARAM_H + +/* + * Xtensa can have variable size caches, and if + * the size of single way is larger than the page size, + * then we have to start worrying about cache aliasing + * problems. + */ + +#define SHMLBA ((PAGE_SIZE > DCACHE_WAY_SIZE)? PAGE_SIZE : DCACHE_WAY_SIZE) + +#endif /* _XTENSA_SHMPARAM_H */ diff --git a/arch/xtensa/include/asm/sigcontext.h b/arch/xtensa/include/asm/sigcontext.h new file mode 100644 index 00000000..03383af8 --- /dev/null +++ b/arch/xtensa/include/asm/sigcontext.h @@ -0,0 +1,28 @@ +/* + * include/asm-xtensa/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. + * + * Copyright (C) 2001 - 2007 Tensilica Inc. + */ + +#ifndef _XTENSA_SIGCONTEXT_H +#define _XTENSA_SIGCONTEXT_H + + +struct sigcontext { + unsigned long sc_pc; + unsigned long sc_ps; + unsigned long sc_lbeg; + unsigned long sc_lend; + unsigned long sc_lcount; + unsigned long sc_sar; + unsigned long sc_acclo; + unsigned long sc_acchi; + unsigned long sc_a[16]; + void *sc_xtregs; +}; + +#endif /* _XTENSA_SIGCONTEXT_H */ diff --git a/arch/xtensa/include/asm/siginfo.h b/arch/xtensa/include/asm/siginfo.h new file mode 100644 index 00000000..69162482 --- /dev/null +++ b/arch/xtensa/include/asm/siginfo.h @@ -0,0 +1,16 @@ +/* + * include/asm-xtensa/siginfo.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_SIGINFO_H +#define _XTENSA_SIGINFO_H + +#include <asm-generic/siginfo.h> + +#endif /* _XTENSA_SIGINFO_H */ diff --git a/arch/xtensa/include/asm/signal.h b/arch/xtensa/include/asm/signal.h new file mode 100644 index 00000000..633ba73b --- /dev/null +++ b/arch/xtensa/include/asm/signal.h @@ -0,0 +1,172 @@ +/* + * include/asm-xtensa/signal.h + * + * Swiped from 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) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_SIGNAL_H +#define _XTENSA_SIGNAL_H + + +#define _NSIG 64 +#define _NSIG_BPW 32 +#define _NSIG_WORDS (_NSIG / _NSIG_BPW) + +#ifndef __ASSEMBLY__ + +#include <linux/types.h> + +/* Avoid too many header ordering problems. */ +struct siginfo; +typedef unsigned long old_sigset_t; /* at least 32 bits */ +typedef struct { + unsigned long sig[_NSIG_WORDS]; +} sigset_t; + +#endif + +#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_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_RESTORER 0x04000000 + +/* + * sigaltstack controls + */ +#define SS_ONSTACK 1 +#define SS_DISABLE 2 + +#define MINSIGSTKSZ 2048 +#define SIGSTKSZ 8192 + +#ifndef __ASSEMBLY__ + +#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 <asm/sigcontext.h> +#define ptrace_signal_deliver(regs, cookie) do { } while (0) + +#endif /* __KERNEL__ */ +#endif /* __ASSEMBLY__ */ +#endif /* _XTENSA_SIGNAL_H */ diff --git a/arch/xtensa/include/asm/smp.h b/arch/xtensa/include/asm/smp.h new file mode 100644 index 00000000..83c569e3 --- /dev/null +++ b/arch/xtensa/include/asm/smp.h @@ -0,0 +1,27 @@ +/* + * include/asm-xtensa/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. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_SMP_H +#define _XTENSA_SMP_H + +extern struct xtensa_cpuinfo boot_cpu_data; + +#define cpu_data (&boot_cpu_data) +#define current_cpu_data boot_cpu_data + +struct xtensa_cpuinfo { + unsigned long *pgd_cache; + unsigned long *pte_cache; + unsigned long pgtable_cache_sz; +}; + +#define cpu_logical_map(cpu) (cpu) + +#endif /* _XTENSA_SMP_H */ diff --git a/arch/xtensa/include/asm/socket.h b/arch/xtensa/include/asm/socket.h new file mode 100644 index 00000000..e36c6818 --- /dev/null +++ b/arch/xtensa/include/asm/socket.h @@ -0,0 +1,83 @@ +/* + * include/asm-xtensa/socket.h + * + * Copied from i386. + * + * 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 _XTENSA_SOCKET_H +#define _XTENSA_SOCKET_H + +#include <asm/sockios.h> + +/* For setsockoptions(2) */ +#define SOL_SOCKET 1 + +#define SO_DEBUG 1 +#define SO_REUSEADDR 2 +#define SO_TYPE 3 +#define SO_ERROR 4 +#define SO_DONTROUTE 5 +#define SO_BROADCAST 6 +#define SO_SNDBUF 7 +#define SO_RCVBUF 8 +#define SO_SNDBUFFORCE 32 +#define SO_RCVBUFFORCE 33 +#define SO_KEEPALIVE 9 +#define SO_OOBINLINE 10 +#define SO_NO_CHECK 11 +#define SO_PRIORITY 12 +#define SO_LINGER 13 +#define SO_BSDCOMPAT 14 +/* To add :#define SO_REUSEPORT 15 */ +#define SO_PASSCRED 16 +#define SO_PEERCRED 17 +#define SO_RCVLOWAT 18 +#define SO_SNDLOWAT 19 +#define SO_RCVTIMEO 20 +#define SO_SNDTIMEO 21 + +/* Security levels - as per NRL IPv6 - don't actually do anything */ + +#define SO_SECURITY_AUTHENTICATION 22 +#define SO_SECURITY_ENCRYPTION_TRANSPORT 23 +#define SO_SECURITY_ENCRYPTION_NETWORK 24 + +#define SO_BINDTODEVICE 25 + +/* Socket filtering */ + +#define SO_ATTACH_FILTER 26 +#define SO_DETACH_FILTER 27 + +#define SO_PEERNAME 28 +#define SO_TIMESTAMP 29 +#define SCM_TIMESTAMP SO_TIMESTAMP + +#define SO_ACCEPTCONN 30 +#define SO_PEERSEC 31 +#define SO_PASSSEC 34 +#define SO_TIMESTAMPNS 35 +#define SCM_TIMESTAMPNS SO_TIMESTAMPNS + +#define SO_MARK 36 + +#define SO_TIMESTAMPING 37 +#define SCM_TIMESTAMPING SO_TIMESTAMPING + +#define SO_PROTOCOL 38 +#define SO_DOMAIN 39 + +#define SO_RXQ_OVFL 40 + +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 + +/* Instruct lower device to use last 4-bytes of skb data as FCS */ +#define SO_NOFCS 43 + +#endif /* _XTENSA_SOCKET_H */ diff --git a/arch/xtensa/include/asm/sockios.h b/arch/xtensa/include/asm/sockios.h new file mode 100644 index 00000000..efe0af37 --- /dev/null +++ b/arch/xtensa/include/asm/sockios.h @@ -0,0 +1,31 @@ +/* + * include/asm-xtensa/sockios.h + * + * Socket-level I/O control calls. Copied from MIPS. + * + * 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 Ralf Baechle + * Copyright (C) 2001 Tensilica Inc. + */ + +#ifndef _XTENSA_SOCKIOS_H +#define _XTENSA_SOCKIOS_H + +#include <asm/ioctl.h> + +/* 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 0x8906 /* Get stamp (timeval) */ +#define SIOCGSTAMPNS 0x8907 /* Get stamp (timespec) */ + +#endif /* _XTENSA_SOCKIOS_H */ diff --git a/arch/xtensa/include/asm/spinlock.h b/arch/xtensa/include/asm/spinlock.h new file mode 100644 index 00000000..8ff23649 --- /dev/null +++ b/arch/xtensa/include/asm/spinlock.h @@ -0,0 +1,16 @@ +/* + * include/asm-xtensa/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. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_SPINLOCK_H +#define _XTENSA_SPINLOCK_H + +#include <linux/spinlock.h> + +#endif /* _XTENSA_SPINLOCK_H */ diff --git a/arch/xtensa/include/asm/stat.h b/arch/xtensa/include/asm/stat.h new file mode 100644 index 00000000..c4992038 --- /dev/null +++ b/arch/xtensa/include/asm/stat.h @@ -0,0 +1,59 @@ +/* + * include/asm-xtensa/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. + * + * Copyright (C) 2001 - 2007 Tensilica Inc. + */ + +#ifndef _XTENSA_STAT_H +#define _XTENSA_STAT_H + +#define STAT_HAVE_NSEC 1 + +struct stat { + unsigned long st_dev; + unsigned long st_ino; + unsigned int st_mode; + unsigned int st_nlink; + unsigned int st_uid; + unsigned int st_gid; + unsigned long st_rdev; + 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; +}; + +struct stat64 { + unsigned long long st_dev; /* Device */ + unsigned long long st_ino; /* File serial number */ + unsigned int st_mode; /* File mode. */ + unsigned int st_nlink; /* Link count. */ + unsigned int st_uid; /* User ID of the file's owner. */ + unsigned int st_gid; /* Group ID of the file's group. */ + unsigned long long st_rdev; /* Device number, if device. */ + long long st_size; /* Size of file, in bytes. */ + unsigned long st_blksize; /* Optimal block size for I/O. */ + unsigned long __unused2; + unsigned long long st_blocks; /* Number 512-byte blocks allocated. */ + unsigned long st_atime; /* Time of last access. */ + unsigned long st_atime_nsec; + unsigned long st_mtime; /* Time of last modification. */ + unsigned long st_mtime_nsec; + unsigned long st_ctime; /* Time of last status change. */ + unsigned long st_ctime_nsec; + unsigned long __unused4; + unsigned long __unused5; +}; + +#endif /* _XTENSA_STAT_H */ diff --git a/arch/xtensa/include/asm/statfs.h b/arch/xtensa/include/asm/statfs.h new file mode 100644 index 00000000..9c3d1a21 --- /dev/null +++ b/arch/xtensa/include/asm/statfs.h @@ -0,0 +1,17 @@ +/* + * include/asm-xtensa/statfs.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_STATFS_H +#define _XTENSA_STATFS_H + +#include <asm-generic/statfs.h> + +#endif /* _XTENSA_STATFS_H */ + diff --git a/arch/xtensa/include/asm/string.h b/arch/xtensa/include/asm/string.h new file mode 100644 index 00000000..405a8c49 --- /dev/null +++ b/arch/xtensa/include/asm/string.h @@ -0,0 +1,121 @@ +/* + * include/asm-xtensa/string.h + * + * These trivial string functions are considered part of the public domain. + * + * 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) 2001 - 2005 Tensilica Inc. + */ + +/* We should optimize these. See arch/xtensa/lib/strncpy_user.S */ + +#ifndef _XTENSA_STRING_H +#define _XTENSA_STRING_H + +#define __HAVE_ARCH_STRCPY +static inline char *strcpy(char *__dest, const char *__src) +{ + register char *__xdest = __dest; + unsigned long __dummy; + + __asm__ __volatile__("1:\n\t" + "l8ui %2, %1, 0\n\t" + "s8i %2, %0, 0\n\t" + "addi %1, %1, 1\n\t" + "addi %0, %0, 1\n\t" + "bnez %2, 1b\n\t" + : "=r" (__dest), "=r" (__src), "=&r" (__dummy) + : "0" (__dest), "1" (__src) + : "memory"); + + return __xdest; +} + +#define __HAVE_ARCH_STRNCPY +static inline char *strncpy(char *__dest, const char *__src, size_t __n) +{ + register char *__xdest = __dest; + unsigned long __dummy; + + if (__n == 0) + return __xdest; + + __asm__ __volatile__( + "1:\n\t" + "l8ui %2, %1, 0\n\t" + "s8i %2, %0, 0\n\t" + "addi %1, %1, 1\n\t" + "addi %0, %0, 1\n\t" + "beqz %2, 2f\n\t" + "bne %1, %5, 1b\n" + "2:" + : "=r" (__dest), "=r" (__src), "=&r" (__dummy) + : "0" (__dest), "1" (__src), "r" (__src+__n) + : "memory"); + + return __xdest; +} + +#define __HAVE_ARCH_STRCMP +static inline int strcmp(const char *__cs, const char *__ct) +{ + register int __res; + unsigned long __dummy; + + __asm__ __volatile__( + "1:\n\t" + "l8ui %3, %1, 0\n\t" + "addi %1, %1, 1\n\t" + "l8ui %2, %0, 0\n\t" + "addi %0, %0, 1\n\t" + "beqz %2, 2f\n\t" + "beq %2, %3, 1b\n" + "2:\n\t" + "sub %2, %3, %2" + : "=r" (__cs), "=r" (__ct), "=&r" (__res), "=&r" (__dummy) + : "0" (__cs), "1" (__ct)); + + return __res; +} + +#define __HAVE_ARCH_STRNCMP +static inline int strncmp(const char *__cs, const char *__ct, size_t __n) +{ + register int __res; + unsigned long __dummy; + + __asm__ __volatile__( + "mov %2, %3\n" + "1:\n\t" + "beq %0, %6, 2f\n\t" + "l8ui %3, %1, 0\n\t" + "addi %1, %1, 1\n\t" + "l8ui %2, %0, 0\n\t" + "addi %0, %0, 1\n\t" + "beqz %2, 2f\n\t" + "beqz %3, 2f\n\t" + "beq %2, %3, 1b\n" + "2:\n\t" + "sub %2, %3, %2" + : "=r" (__cs), "=r" (__ct), "=&r" (__res), "=&r" (__dummy) + : "0" (__cs), "1" (__ct), "r" (__cs+__n)); + + return __res; +} + +#define __HAVE_ARCH_MEMSET +extern void *memset(void *__s, int __c, size_t __count); + +#define __HAVE_ARCH_MEMCPY +extern void *memcpy(void *__to, __const__ void *__from, size_t __n); + +#define __HAVE_ARCH_MEMMOVE +extern void *memmove(void *__dest, __const__ void *__src, size_t __n); + +/* Don't build bcopy at all ... */ +#define __HAVE_ARCH_BCOPY + +#endif /* _XTENSA_STRING_H */ diff --git a/arch/xtensa/include/asm/swab.h b/arch/xtensa/include/asm/swab.h new file mode 100644 index 00000000..226a3916 --- /dev/null +++ b/arch/xtensa/include/asm/swab.h @@ -0,0 +1,70 @@ +/* + * include/asm-xtensa/swab.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_SWAB_H +#define _XTENSA_SWAB_H + +#include <linux/types.h> +#include <linux/compiler.h> + +#define __SWAB_64_THRU_32__ + +static inline __attribute_const__ __u32 __arch_swab32(__u32 x) +{ + __u32 res; + /* instruction sequence from Xtensa ISA release 2/2000 */ + __asm__("ssai 8 \n\t" + "srli %0, %1, 16 \n\t" + "src %0, %0, %1 \n\t" + "src %0, %0, %0 \n\t" + "src %0, %1, %0 \n" + : "=&a" (res) + : "a" (x) + ); + return res; +} +#define __arch_swab32 __arch_swab32 + +static inline __attribute_const__ __u16 __arch_swab16(__u16 x) +{ + /* Given that 'short' values are signed (i.e., can be negative), + * we cannot assume that the upper 16-bits of the register are + * zero. We are careful to mask values after shifting. + */ + + /* There exists an anomaly between xt-gcc and xt-xcc. xt-gcc + * inserts an extui instruction after putting this function inline + * to ensure that it uses only the least-significant 16 bits of + * the result. xt-xcc doesn't use an extui, but assumes the + * __asm__ macro follows convention that the upper 16 bits of an + * 'unsigned short' result are still zero. This macro doesn't + * follow convention; indeed, it leaves garbage in the upport 16 + * bits of the register. + + * Declaring the temporary variables 'res' and 'tmp' to be 32-bit + * types while the return type of the function is a 16-bit type + * forces both compilers to insert exactly one extui instruction + * (or equivalent) to mask off the upper 16 bits. */ + + __u32 res; + __u32 tmp; + + __asm__("extui %1, %2, 8, 8\n\t" + "slli %0, %2, 8 \n\t" + "or %0, %0, %1 \n" + : "=&a" (res), "=&a" (tmp) + : "a" (x) + ); + + return res; +} +#define __arch_swab16 __arch_swab16 + +#endif /* _XTENSA_SWAB_H */ diff --git a/arch/xtensa/include/asm/switch_to.h b/arch/xtensa/include/asm/switch_to.h new file mode 100644 index 00000000..6b73bf0e --- /dev/null +++ b/arch/xtensa/include/asm/switch_to.h @@ -0,0 +1,22 @@ +/* + * 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) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_SWITCH_TO_H +#define _XTENSA_SWITCH_TO_H + +/* * switch_to(n) should switch tasks to task nr n, first + * checking that n isn't the current task, in which case it does nothing. + */ +extern void *_switch_to(void *last, void *next); + +#define switch_to(prev,next,last) \ +do { \ + (last) = _switch_to(prev, next); \ +} while(0) + +#endif /* _XTENSA_SWITCH_TO_H */ diff --git a/arch/xtensa/include/asm/syscall.h b/arch/xtensa/include/asm/syscall.h new file mode 100644 index 00000000..efcf33b9 --- /dev/null +++ b/arch/xtensa/include/asm/syscall.h @@ -0,0 +1,39 @@ +/* + * include/asm-xtensa/syscall.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001 - 2007 Tensilica Inc. + */ + +struct pt_regs; +struct sigaction; +asmlinkage long xtensa_execve(char*, char**, char**, struct pt_regs*); +asmlinkage long xtensa_clone(unsigned long, unsigned long, struct pt_regs*); +asmlinkage long xtensa_ptrace(long, long, long, long); +asmlinkage long xtensa_sigreturn(struct pt_regs*); +asmlinkage long xtensa_rt_sigreturn(struct pt_regs*); +asmlinkage long xtensa_sigsuspend(struct pt_regs*); +asmlinkage long xtensa_rt_sigsuspend(struct pt_regs*); +asmlinkage long xtensa_sigaction(int, const struct old_sigaction*, + struct old_sigaction*); +asmlinkage long xtensa_sigaltstack(struct pt_regs *regs); +asmlinkage long sys_rt_sigaction(int, + const struct sigaction __user *, + struct sigaction __user *, + size_t); +asmlinkage long xtensa_shmat(int, char __user *, int); +asmlinkage long xtensa_fadvise64_64(int, int, + unsigned long long, unsigned long long); + +/* Should probably move to linux/syscalls.h */ +struct pollfd; +asmlinkage long sys_pselect6(int n, fd_set __user *inp, fd_set __user *outp, + fd_set __user *exp, struct timespec __user *tsp, void __user *sig); +asmlinkage long sys_ppoll(struct pollfd __user *ufds, unsigned int nfds, + struct timespec __user *tsp, const sigset_t __user *sigmask, + size_t sigsetsize); + + diff --git a/arch/xtensa/include/asm/termbits.h b/arch/xtensa/include/asm/termbits.h new file mode 100644 index 00000000..0d6c8715 --- /dev/null +++ b/arch/xtensa/include/asm/termbits.h @@ -0,0 +1,220 @@ +/* + * include/asm-xtensa/termbits.h + * + * Copied from 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) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_TERMBITS_H +#define _XTENSA_TERMBITS_H + + +#include <linux/posix_types.h> + +typedef unsigned char cc_t; +typedef unsigned int speed_t; +typedef unsigned int tcflag_t; + +#define NCCS 19 +struct termios { + tcflag_t c_iflag; /* input mode flags */ + tcflag_t c_oflag; /* output mode flags */ + tcflag_t c_cflag; /* control mode flags */ + tcflag_t c_lflag; /* local mode flags */ + cc_t c_line; /* line discipline */ + cc_t c_cc[NCCS]; /* control characters */ +}; + +struct termios2 { + tcflag_t c_iflag; /* input mode flags */ + tcflag_t c_oflag; /* output mode flags */ + tcflag_t c_cflag; /* control mode flags */ + tcflag_t c_lflag; /* local mode flags */ + cc_t c_line; /* line discipline */ + cc_t c_cc[NCCS]; /* control characters */ + speed_t c_ispeed; /* input speed */ + speed_t c_ospeed; /* output speed */ +}; + +struct ktermios { + tcflag_t c_iflag; /* input mode flags */ + tcflag_t c_oflag; /* output mode flags */ + tcflag_t c_cflag; /* control mode flags */ + tcflag_t c_lflag; /* local mode flags */ + cc_t c_line; /* line discipline */ + cc_t c_cc[NCCS]; /* control characters */ + speed_t c_ispeed; /* input speed */ + speed_t c_ospeed; /* output speed */ +}; + +/* c_cc characters */ + +#define VINTR 0 +#define VQUIT 1 +#define VERASE 2 +#define VKILL 3 +#define VEOF 4 +#define VTIME 5 +#define VMIN 6 +#define VSWTC 7 +#define VSTART 8 +#define VSTOP 9 +#define VSUSP 10 +#define VEOL 11 +#define VREPRINT 12 +#define VDISCARD 13 +#define VWERASE 14 +#define VLNEXT 15 +#define VEOL2 16 + +/* c_iflag bits */ + +#define IGNBRK 0000001 +#define BRKINT 0000002 +#define IGNPAR 0000004 +#define PARMRK 0000010 +#define INPCK 0000020 +#define ISTRIP 0000040 +#define INLCR 0000100 +#define IGNCR 0000200 +#define ICRNL 0000400 +#define IUCLC 0001000 +#define IXON 0002000 +#define IXANY 0004000 +#define IXOFF 0010000 +#define IMAXBEL 0020000 +#define IUTF8 0040000 + +/* c_oflag bits */ + +#define OPOST 0000001 +#define OLCUC 0000002 +#define ONLCR 0000004 +#define OCRNL 0000010 +#define ONOCR 0000020 +#define ONLRET 0000040 +#define OFILL 0000100 +#define OFDEL 0000200 +#define NLDLY 0000400 +#define NL0 0000000 +#define NL1 0000400 +#define CRDLY 0003000 +#define CR0 0000000 +#define CR1 0001000 +#define CR2 0002000 +#define CR3 0003000 +#define TABDLY 0014000 +#define TAB0 0000000 +#define TAB1 0004000 +#define TAB2 0010000 +#define TAB3 0014000 +#define XTABS 0014000 +#define BSDLY 0020000 +#define BS0 0000000 +#define BS1 0020000 +#define VTDLY 0040000 +#define VT0 0000000 +#define VT1 0040000 +#define FFDLY 0100000 +#define FF0 0000000 +#define FF1 0100000 + +/* c_cflag bit meaning */ + +#define CBAUD 0010017 +#define B0 0000000 /* hang up */ +#define B50 0000001 +#define B75 0000002 +#define B110 0000003 +#define B134 0000004 +#define B150 0000005 +#define B200 0000006 +#define B300 0000007 +#define B600 0000010 +#define B1200 0000011 +#define B1800 0000012 +#define B2400 0000013 +#define B4800 0000014 +#define B9600 0000015 +#define B19200 0000016 +#define B38400 0000017 +#define EXTA B19200 +#define EXTB B38400 +#define CSIZE 0000060 +#define CS5 0000000 +#define CS6 0000020 +#define CS7 0000040 +#define CS8 0000060 +#define CSTOPB 0000100 +#define CREAD 0000200 +#define PARENB 0000400 +#define PARODD 0001000 +#define HUPCL 0002000 +#define CLOCAL 0004000 +#define CBAUDEX 0010000 +#define BOTHER 0010000 +#define B57600 0010001 +#define B115200 0010002 +#define B230400 0010003 +#define B460800 0010004 +#define B500000 0010005 +#define B576000 0010006 +#define B921600 0010007 +#define B1000000 0010010 +#define B1152000 0010011 +#define B1500000 0010012 +#define B2000000 0010013 +#define B2500000 0010014 +#define B3000000 0010015 +#define B3500000 0010016 +#define B4000000 0010017 +#define CIBAUD 002003600000 /* input baud rate */ +#define CMSPAR 010000000000 /* mark or space (stick) parity */ +#define CRTSCTS 020000000000 /* flow control */ + +#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */ + +/* c_lflag bits */ + +#define ISIG 0000001 +#define ICANON 0000002 +#define XCASE 0000004 +#define ECHO 0000010 +#define ECHOE 0000020 +#define ECHOK 0000040 +#define ECHONL 0000100 +#define NOFLSH 0000200 +#define TOSTOP 0000400 +#define ECHOCTL 0001000 +#define ECHOPRT 0002000 +#define ECHOKE 0004000 +#define FLUSHO 0010000 +#define PENDIN 0040000 +#define IEXTEN 0100000 +#define EXTPROC 0200000 + +/* tcflow() and TCXONC use these */ + +#define TCOOFF 0 +#define TCOON 1 +#define TCIOFF 2 +#define TCION 3 + +/* tcflush() and TCFLSH use these */ + +#define TCIFLUSH 0 +#define TCOFLUSH 1 +#define TCIOFLUSH 2 + +/* tcsetattr uses these */ + +#define TCSANOW 0 +#define TCSADRAIN 1 +#define TCSAFLUSH 2 + +#endif /* _XTENSA_TERMBITS_H */ diff --git a/arch/xtensa/include/asm/termios.h b/arch/xtensa/include/asm/termios.h new file mode 100644 index 00000000..4673f42f --- /dev/null +++ b/arch/xtensa/include/asm/termios.h @@ -0,0 +1,105 @@ +/* + * include/asm-xtensa/termios.h + * + * Copied from 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) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_TERMIOS_H +#define _XTENSA_TERMIOS_H + +#include <asm/termbits.h> +#include <asm/ioctls.h> + +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 */ + +#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 termios2)) +#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios2)) +#define user_termios_to_kernel_termios_1(k, u) copy_from_user(k, u, sizeof(struct termios)) +#define kernel_termios_to_user_termios_1(u, k) copy_to_user(u, k, sizeof(struct termios)) + +#endif /* __KERNEL__ */ + +#endif /* _XTENSA_TERMIOS_H */ diff --git a/arch/xtensa/include/asm/thread_info.h b/arch/xtensa/include/asm/thread_info.h new file mode 100644 index 00000000..6abbedd0 --- /dev/null +++ b/arch/xtensa/include/asm/thread_info.h @@ -0,0 +1,160 @@ +/* + * include/asm-xtensa/thread_info.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_THREAD_INFO_H +#define _XTENSA_THREAD_INFO_H + +#ifdef __KERNEL__ + +#ifndef __ASSEMBLY__ +# include <asm/processor.h> +#endif + +/* + * 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 + */ + +#ifndef __ASSEMBLY__ + +#if XTENSA_HAVE_COPROCESSORS + +typedef struct xtregs_coprocessor { + xtregs_cp0_t cp0; + xtregs_cp1_t cp1; + xtregs_cp2_t cp2; + xtregs_cp3_t cp3; + xtregs_cp4_t cp4; + xtregs_cp5_t cp5; + xtregs_cp6_t cp6; + xtregs_cp7_t cp7; +} xtregs_coprocessor_t; + +#endif + +struct thread_info { + struct task_struct *task; /* main task structure */ + struct exec_domain *exec_domain; /* execution domain */ + unsigned long flags; /* low level flags */ + unsigned long status; /* thread-synchronous flags */ + __u32 cpu; /* current CPU */ + __s32 preempt_count; /* 0 => preemptable,< 0 => BUG*/ + + mm_segment_t addr_limit; /* thread address space */ + struct restart_block restart_block; + + unsigned long cpenable; + + /* Allocate storage for extra user states and coprocessor states. */ +#if XTENSA_HAVE_COPROCESSORS + xtregs_coprocessor_t xtregs_cp; +#endif + xtregs_user_t xtregs_user; +}; + +#else /* !__ASSEMBLY__ */ + +/* offsets into the thread_info struct for assembly code access */ +#define TI_TASK 0x00000000 +#define TI_EXEC_DOMAIN 0x00000004 +#define TI_FLAGS 0x00000008 +#define TI_STATUS 0x0000000C +#define TI_CPU 0x00000010 +#define TI_PRE_COUNT 0x00000014 +#define TI_ADDR_LIMIT 0x00000018 +#define TI_RESTART_BLOCK 0x000001C + +#endif + +#define PREEMPT_ACTIVE 0x10000000 + +/* + * macros/functions for gaining access to the thread information structure + */ + +#ifndef __ASSEMBLY__ + +#define INIT_THREAD_INFO(tsk) \ +{ \ + .task = &tsk, \ + .exec_domain = &default_exec_domain, \ + .flags = 0, \ + .cpu = 0, \ + .preempt_count = INIT_PREEMPT_COUNT, \ + .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__("extui %0,a1,0,13\n\t" + "xor %0, a1, %0" : "=&r" (ti) : ); + return ti; +} + +#else /* !__ASSEMBLY__ */ + +/* how to get the thread information struct from ASM */ +#define GET_THREAD_INFO(reg,sp) \ + extui reg, sp, 0, 13; \ + xor reg, sp, reg +#endif + + +/* + * thread information flags + * - these are process state flags that various assembly files may need to access + * - pending work-to-be-done flags are in LSW + * - other flags in MSW + */ +#define TIF_SYSCALL_TRACE 0 /* syscall trace active */ +#define TIF_SIGPENDING 1 /* signal pending */ +#define TIF_NEED_RESCHED 2 /* rescheduling necessary */ +#define TIF_SINGLESTEP 3 /* restore singlestep on return to user mode */ +#define TIF_IRET 4 /* return with iret */ +#define TIF_MEMDIE 5 /* is terminating due to OOM killer */ +#define TIF_RESTORE_SIGMASK 6 /* restore signal mask in do_signal() */ +#define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */ + +#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) +#define _TIF_SIGPENDING (1<<TIF_SIGPENDING) +#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) +#define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP) +#define _TIF_IRET (1<<TIF_IRET) +#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) +#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK) + +#define _TIF_WORK_MASK 0x0000FFFE /* work to do on interrupt/exception return */ +#define _TIF_ALLWORK_MASK 0x0000FFFF /* work to do on any return to u-space */ + +/* + * Thread-synchronous status. + * + * This is different from the flags in that nobody else + * ever touches our thread-synchronous status, so we don't + * have to worry about atomic accesses. + */ +#define TS_USEDFPU 0x0001 /* FPU was used by this task this quantum (SMP) */ + +#define THREAD_SIZE 8192 //(2*PAGE_SIZE) +#define THREAD_SIZE_ORDER 1 + +#endif /* __KERNEL__ */ +#endif /* _XTENSA_THREAD_INFO */ diff --git a/arch/xtensa/include/asm/timex.h b/arch/xtensa/include/asm/timex.h new file mode 100644 index 00000000..053bc427 --- /dev/null +++ b/arch/xtensa/include/asm/timex.h @@ -0,0 +1,96 @@ +/* + * include/asm-xtensa/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. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_TIMEX_H +#define _XTENSA_TIMEX_H + +#ifdef __KERNEL__ + +#include <asm/processor.h> +#include <linux/stringify.h> + +#define _INTLEVEL(x) XCHAL_INT ## x ## _LEVEL +#define INTLEVEL(x) _INTLEVEL(x) + +#if INTLEVEL(XCHAL_TIMER0_INTERRUPT) == 1 +# define LINUX_TIMER 0 +# define LINUX_TIMER_INT XCHAL_TIMER0_INTERRUPT +#elif INTLEVEL(XCHAL_TIMER1_INTERRUPT) == 1 +# define LINUX_TIMER 1 +# define LINUX_TIMER_INT XCHAL_TIMER1_INTERRUPT +#elif INTLEVEL(XCHAL_TIMER2_INTERRUPT) == 1 +# define LINUX_TIMER 2 +# define LINUX_TIMER_INT XCHAL_TIMER2_INTERRUPT +#else +# error "Bad timer number for Linux configurations!" +#endif + +#define LINUX_TIMER_MASK (1L << LINUX_TIMER_INT) + +#define CLOCK_TICK_RATE 1193180 /* (everyone is using this value) */ +#define CLOCK_TICK_FACTOR 20 /* Factor of both 10^6 and CLOCK_TICK_RATE */ + +#ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT +extern unsigned long ccount_per_jiffy; +extern unsigned long nsec_per_ccount; +#define CCOUNT_PER_JIFFY ccount_per_jiffy +#define NSEC_PER_CCOUNT nsec_per_ccount +#else +#define CCOUNT_PER_JIFFY (CONFIG_XTENSA_CPU_CLOCK*(1000000UL/HZ)) +#define NSEC_PER_CCOUNT (1000UL / CONFIG_XTENSA_CPU_CLOCK) +#endif + + +typedef unsigned long long cycles_t; + +/* + * Only used for SMP. + */ + +extern cycles_t cacheflush_time; + +#define get_cycles() (0) + + +/* + * Register access. + */ + +#define WSR_CCOUNT(r) asm volatile ("wsr %0,"__stringify(CCOUNT) :: "a" (r)) +#define RSR_CCOUNT(r) asm volatile ("rsr %0,"__stringify(CCOUNT) : "=a" (r)) +#define WSR_CCOMPARE(x,r) asm volatile ("wsr %0,"__stringify(CCOMPARE)"+"__stringify(x) :: "a"(r)) +#define RSR_CCOMPARE(x,r) asm volatile ("rsr %0,"__stringify(CCOMPARE)"+"__stringify(x) : "=a"(r)) + +static inline unsigned long get_ccount (void) +{ + unsigned long ccount; + RSR_CCOUNT(ccount); + return ccount; +} + +static inline void set_ccount (unsigned long ccount) +{ + WSR_CCOUNT(ccount); +} + +static inline unsigned long get_linux_timer (void) +{ + unsigned ccompare; + RSR_CCOMPARE(LINUX_TIMER, ccompare); + return ccompare; +} + +static inline void set_linux_timer (unsigned long ccompare) +{ + WSR_CCOMPARE(LINUX_TIMER, ccompare); +} + +#endif /* __KERNEL__ */ +#endif /* _XTENSA_TIMEX_H */ diff --git a/arch/xtensa/include/asm/tlb.h b/arch/xtensa/include/asm/tlb.h new file mode 100644 index 00000000..0d766f9c --- /dev/null +++ b/arch/xtensa/include/asm/tlb.h @@ -0,0 +1,47 @@ +/* + * include/asm-xtensa/tlb.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_TLB_H +#define _XTENSA_TLB_H + +#include <asm/cache.h> +#include <asm/page.h> + +#if (DCACHE_WAY_SIZE <= PAGE_SIZE) + +/* Note, read http://lkml.org/lkml/2004/1/15/6 */ + +# define tlb_start_vma(tlb,vma) do { } while (0) +# define tlb_end_vma(tlb,vma) do { } while (0) + +#else + +# define tlb_start_vma(tlb, vma) \ + do { \ + if (!tlb->fullmm) \ + flush_cache_range(vma, vma->vm_start, vma->vm_end); \ + } while(0) + +# define tlb_end_vma(tlb, vma) \ + do { \ + if (!tlb->fullmm) \ + flush_tlb_range(vma, vma->vm_start, vma->vm_end); \ + } while(0) + +#endif + +#define __tlb_remove_tlb_entry(tlb,pte,addr) do { } while (0) +#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm) + +#include <asm-generic/tlb.h> + +#define __pte_free_tlb(tlb, pte, address) pte_free((tlb)->mm, pte) + +#endif /* _XTENSA_TLB_H */ diff --git a/arch/xtensa/include/asm/tlbflush.h b/arch/xtensa/include/asm/tlbflush.h new file mode 100644 index 00000000..46d24007 --- /dev/null +++ b/arch/xtensa/include/asm/tlbflush.h @@ -0,0 +1,191 @@ +/* + * include/asm-xtensa/tlbflush.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_TLBFLUSH_H +#define _XTENSA_TLBFLUSH_H + +#ifdef __KERNEL__ + +#include <linux/stringify.h> +#include <asm/processor.h> + +#define DTLB_WAY_PGD 7 + +#define ITLB_ARF_WAYS 4 +#define DTLB_ARF_WAYS 4 + +#define ITLB_HIT_BIT 3 +#define DTLB_HIT_BIT 4 + +#ifndef __ASSEMBLY__ + +/* TLB flushing: + * + * - flush_tlb_all() flushes all processes TLB entries + * - flush_tlb_mm(mm) flushes the specified mm context TLB entries + * - flush_tlb_page(mm, vmaddr) flushes a single page + * - flush_tlb_range(mm, start, end) flushes a range of pages + */ + +extern void flush_tlb_all(void); +extern void flush_tlb_mm(struct mm_struct*); +extern void flush_tlb_page(struct vm_area_struct*,unsigned long); +extern void flush_tlb_range(struct vm_area_struct*,unsigned long,unsigned long); + +#define flush_tlb_kernel_range(start,end) flush_tlb_all() + +/* TLB operations. */ + +static inline unsigned long itlb_probe(unsigned long addr) +{ + unsigned long tmp; + __asm__ __volatile__("pitlb %0, %1\n\t" : "=a" (tmp) : "a" (addr)); + return tmp; +} + +static inline unsigned long dtlb_probe(unsigned long addr) +{ + unsigned long tmp; + __asm__ __volatile__("pdtlb %0, %1\n\t" : "=a" (tmp) : "a" (addr)); + return tmp; +} + +static inline void invalidate_itlb_entry (unsigned long probe) +{ + __asm__ __volatile__("iitlb %0; isync\n\t" : : "a" (probe)); +} + +static inline void invalidate_dtlb_entry (unsigned long probe) +{ + __asm__ __volatile__("idtlb %0; dsync\n\t" : : "a" (probe)); +} + +/* Use the .._no_isync functions with caution. Generally, these are + * handy for bulk invalidates followed by a single 'isync'. The + * caller must follow up with an 'isync', which can be relatively + * expensive on some Xtensa implementations. + */ +static inline void invalidate_itlb_entry_no_isync (unsigned entry) +{ + /* Caller must follow up with 'isync'. */ + __asm__ __volatile__ ("iitlb %0\n" : : "a" (entry) ); +} + +static inline void invalidate_dtlb_entry_no_isync (unsigned entry) +{ + /* Caller must follow up with 'isync'. */ + __asm__ __volatile__ ("idtlb %0\n" : : "a" (entry) ); +} + +static inline void set_itlbcfg_register (unsigned long val) +{ + __asm__ __volatile__("wsr %0, "__stringify(ITLBCFG)"\n\t" "isync\n\t" + : : "a" (val)); +} + +static inline void set_dtlbcfg_register (unsigned long val) +{ + __asm__ __volatile__("wsr %0, "__stringify(DTLBCFG)"; dsync\n\t" + : : "a" (val)); +} + +static inline void set_ptevaddr_register (unsigned long val) +{ + __asm__ __volatile__(" wsr %0, "__stringify(PTEVADDR)"; isync\n" + : : "a" (val)); +} + +static inline unsigned long read_ptevaddr_register (void) +{ + unsigned long tmp; + __asm__ __volatile__("rsr %0, "__stringify(PTEVADDR)"\n\t" : "=a" (tmp)); + return tmp; +} + +static inline void write_dtlb_entry (pte_t entry, int way) +{ + __asm__ __volatile__("wdtlb %1, %0; dsync\n\t" + : : "r" (way), "r" (entry) ); +} + +static inline void write_itlb_entry (pte_t entry, int way) +{ + __asm__ __volatile__("witlb %1, %0; isync\n\t" + : : "r" (way), "r" (entry) ); +} + +static inline void invalidate_page_directory (void) +{ + invalidate_dtlb_entry (DTLB_WAY_PGD); + invalidate_dtlb_entry (DTLB_WAY_PGD+1); + invalidate_dtlb_entry (DTLB_WAY_PGD+2); +} + +static inline void invalidate_itlb_mapping (unsigned address) +{ + unsigned long tlb_entry; + if (((tlb_entry = itlb_probe(address)) & (1 << ITLB_HIT_BIT)) != 0) + invalidate_itlb_entry(tlb_entry); +} + +static inline void invalidate_dtlb_mapping (unsigned address) +{ + unsigned long tlb_entry; + if (((tlb_entry = dtlb_probe(address)) & (1 << DTLB_HIT_BIT)) != 0) + invalidate_dtlb_entry(tlb_entry); +} + +#define check_pgt_cache() do { } while (0) + + +/* + * DO NOT USE THESE FUNCTIONS. These instructions aren't part of the Xtensa + * ISA and exist only for test purposes.. + * You may find it helpful for MMU debugging, however. + * + * 'at' is the unmodified input register + * 'as' is the output register, as follows (specific to the Linux config): + * + * as[31..12] contain the virtual address + * as[11..08] are meaningless + * as[07..00] contain the asid + */ + +static inline unsigned long read_dtlb_virtual (int way) +{ + unsigned long tmp; + __asm__ __volatile__("rdtlb0 %0, %1\n\t" : "=a" (tmp), "+a" (way)); + return tmp; +} + +static inline unsigned long read_dtlb_translation (int way) +{ + unsigned long tmp; + __asm__ __volatile__("rdtlb1 %0, %1\n\t" : "=a" (tmp), "+a" (way)); + return tmp; +} + +static inline unsigned long read_itlb_virtual (int way) +{ + unsigned long tmp; + __asm__ __volatile__("ritlb0 %0, %1\n\t" : "=a" (tmp), "+a" (way)); + return tmp; +} + +static inline unsigned long read_itlb_translation (int way) +{ + unsigned long tmp; + __asm__ __volatile__("ritlb1 %0, %1\n\t" : "=a" (tmp), "+a" (way)); + return tmp; +} + +#endif /* __ASSEMBLY__ */ +#endif /* __KERNEL__ */ +#endif /* _XTENSA_TLBFLUSH_H */ diff --git a/arch/xtensa/include/asm/topology.h b/arch/xtensa/include/asm/topology.h new file mode 100644 index 00000000..7309e38a --- /dev/null +++ b/arch/xtensa/include/asm/topology.h @@ -0,0 +1,16 @@ +/* + * include/asm-xtensa/topology.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_TOPOLOGY_H +#define _XTENSA_TOPOLOGY_H + +#include <asm-generic/topology.h> + +#endif /* _XTENSA_TOPOLOGY_H */ diff --git a/arch/xtensa/include/asm/types.h b/arch/xtensa/include/asm/types.h new file mode 100644 index 00000000..6d4db7e8 --- /dev/null +++ b/arch/xtensa/include/asm/types.h @@ -0,0 +1,36 @@ +/* + * include/asm-xtensa/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. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_TYPES_H +#define _XTENSA_TYPES_H + +#include <asm-generic/int-ll64.h> + +#ifdef __ASSEMBLY__ +# define __XTENSA_UL(x) (x) +# define __XTENSA_UL_CONST(x) x +#else +# define __XTENSA_UL(x) ((unsigned long)(x)) +# define __XTENSA_UL_CONST(x) x##UL +#endif + +#ifndef __ASSEMBLY__ + +/* + * These aren't exported outside the kernel to avoid name space clashes + */ +#ifdef __KERNEL__ + +#define BITS_PER_LONG 32 + +#endif /* __KERNEL__ */ +#endif + +#endif /* _XTENSA_TYPES_H */ diff --git a/arch/xtensa/include/asm/uaccess.h b/arch/xtensa/include/asm/uaccess.h new file mode 100644 index 00000000..6e4bb3b7 --- /dev/null +++ b/arch/xtensa/include/asm/uaccess.h @@ -0,0 +1,502 @@ +/* + * include/asm-xtensa/uaccess.h + * + * User space memory access functions + * + * These routines provide basic accessing functions to the user memory + * space for the kernel. This header file provides functions such as: + * + * 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) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_UACCESS_H +#define _XTENSA_UACCESS_H + +#include <linux/errno.h> +#ifndef __ASSEMBLY__ +#include <linux/prefetch.h> +#endif +#include <asm/types.h> + +#define VERIFY_READ 0 +#define VERIFY_WRITE 1 + +#ifdef __ASSEMBLY__ + +#include <asm/current.h> +#include <asm/asm-offsets.h> +#include <asm/processor.h> + +/* + * These assembly macros mirror the C macros that follow below. They + * should always have identical functionality. See + * arch/xtensa/kernel/sys.S for usage. + */ + +#define KERNEL_DS 0 +#define USER_DS 1 + +#define get_ds (KERNEL_DS) + +/* + * get_fs reads current->thread.current_ds into a register. + * On Entry: + * <ad> anything + * <sp> stack + * On Exit: + * <ad> contains current->thread.current_ds + */ + .macro get_fs ad, sp + GET_CURRENT(\ad,\sp) + l32i \ad, \ad, THREAD_CURRENT_DS + .endm + +/* + * set_fs sets current->thread.current_ds to some value. + * On Entry: + * <at> anything (temp register) + * <av> value to write + * <sp> stack + * On Exit: + * <at> destroyed (actually, current) + * <av> preserved, value to write + */ + .macro set_fs at, av, sp + GET_CURRENT(\at,\sp) + s32i \av, \at, THREAD_CURRENT_DS + .endm + +/* + * kernel_ok determines whether we should bypass addr/size checking. + * See the equivalent C-macro version below for clarity. + * On success, kernel_ok branches to a label indicated by parameter + * <success>. This implies that the macro falls through to the next + * insruction on an error. + * + * Note that while this macro can be used independently, we designed + * in for optimal use in the access_ok macro below (i.e., we fall + * through on error). + * + * On Entry: + * <at> anything (temp register) + * <success> label to branch to on success; implies + * fall-through macro on error + * <sp> stack pointer + * On Exit: + * <at> destroyed (actually, current->thread.current_ds) + */ + +#if ((KERNEL_DS != 0) || (USER_DS == 0)) +# error Assembly macro kernel_ok fails +#endif + .macro kernel_ok at, sp, success + get_fs \at, \sp + beqz \at, \success + .endm + +/* + * user_ok determines whether the access to user-space memory is allowed. + * See the equivalent C-macro version below for clarity. + * + * On error, user_ok branches to a label indicated by parameter + * <error>. This implies that the macro falls through to the next + * instruction on success. + * + * Note that while this macro can be used independently, we designed + * in for optimal use in the access_ok macro below (i.e., we fall + * through on success). + * + * On Entry: + * <aa> register containing memory address + * <as> register containing memory size + * <at> temp register + * <error> label to branch to on error; implies fall-through + * macro on success + * On Exit: + * <aa> preserved + * <as> preserved + * <at> destroyed (actually, (TASK_SIZE + 1 - size)) + */ + .macro user_ok aa, as, at, error + movi \at, __XTENSA_UL_CONST(TASK_SIZE) + bgeu \as, \at, \error + sub \at, \at, \as + bgeu \aa, \at, \error + .endm + +/* + * access_ok determines whether a memory access is allowed. See the + * equivalent C-macro version below for clarity. + * + * On error, access_ok branches to a label indicated by parameter + * <error>. This implies that the macro falls through to the next + * instruction on success. + * + * Note that we assume success is the common case, and we optimize the + * branch fall-through case on success. + * + * On Entry: + * <aa> register containing memory address + * <as> register containing memory size + * <at> temp register + * <sp> + * <error> label to branch to on error; implies fall-through + * macro on success + * On Exit: + * <aa> preserved + * <as> preserved + * <at> destroyed + */ + .macro access_ok aa, as, at, sp, error + kernel_ok \at, \sp, .Laccess_ok_\@ + user_ok \aa, \as, \at, \error +.Laccess_ok_\@: + .endm + +#else /* __ASSEMBLY__ not defined */ + +#include <linux/sched.h> + +/* + * 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 + * grossly misnamed. + */ + +#define KERNEL_DS ((mm_segment_t) { 0 }) +#define USER_DS ((mm_segment_t) { 1 }) + +#define get_ds() (KERNEL_DS) +#define get_fs() (current->thread.current_ds) +#define set_fs(val) (current->thread.current_ds = (val)) + +#define segment_eq(a,b) ((a).seg == (b).seg) + +#define __kernel_ok (segment_eq(get_fs(), KERNEL_DS)) +#define __user_ok(addr,size) (((size) <= TASK_SIZE)&&((addr) <= TASK_SIZE-(size))) +#define __access_ok(addr,size) (__kernel_ok || __user_ok((addr),(size))) +#define access_ok(type,addr,size) __access_ok((unsigned long)(addr),(size)) + +/* + * These are the main single-value transfer routines. They + * automatically use the right size if we just have the right pointer + * type. + * + * This gets kind of ugly. We want to return _two_ values in + * "get_user()" and yet we don't want to do any pointers, because that + * is too much of a performance impact. Thus we have a few rather ugly + * macros here, and hide all the uglyness from the user. + * + * 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 of the user access functions are versions that + * do not verify the address space, that must have been done previously + * with a separate "access_ok()" call (this is used when we do multiple + * accesses to the same area of user memory). + */ +#define __put_user(x,ptr) __put_user_nocheck((x),(ptr),sizeof(*(ptr))) +#define __get_user(x,ptr) __get_user_nocheck((x),(ptr),sizeof(*(ptr))) + + +extern long __put_user_bad(void); + +#define __put_user_nocheck(x,ptr,size) \ +({ \ + long __pu_err; \ + __put_user_size((x),(ptr),(size),__pu_err); \ + __pu_err; \ +}) + +#define __put_user_check(x,ptr,size) \ +({ \ + long __pu_err = -EFAULT; \ + __typeof__(*(ptr)) *__pu_addr = (ptr); \ + if (access_ok(VERIFY_WRITE,__pu_addr,size)) \ + __put_user_size((x),__pu_addr,(size),__pu_err); \ + __pu_err; \ +}) + +#define __put_user_size(x,ptr,size,retval) \ +do { \ + int __cb; \ + retval = 0; \ + switch (size) { \ + case 1: __put_user_asm(x,ptr,retval,1,"s8i",__cb); break; \ + case 2: __put_user_asm(x,ptr,retval,2,"s16i",__cb); break; \ + case 4: __put_user_asm(x,ptr,retval,4,"s32i",__cb); break; \ + case 8: { \ + __typeof__(*ptr) __v64 = x; \ + retval = __copy_to_user(ptr,&__v64,8); \ + break; \ + } \ + default: __put_user_bad(); \ + } \ +} while (0) + + +/* + * Consider a case of a user single load/store would cause both an + * unaligned exception and an MMU-related exception (unaligned + * exceptions happen first): + * + * User code passes a bad variable ptr to a system call. + * Kernel tries to access the variable. + * Unaligned exception occurs. + * Unaligned exception handler tries to make aligned accesses. + * Double exception occurs for MMU-related cause (e.g., page not mapped). + * do_page_fault() thinks the fault address belongs to the kernel, not the + * user, and panics. + * + * The kernel currently prohibits user unaligned accesses. We use the + * __check_align_* macros to check for unaligned addresses before + * accessing user space so we don't crash the kernel. Both + * __put_user_asm and __get_user_asm use these alignment macros, so + * macro-specific labels such as 0f, 1f, %0, %2, and %3 must stay in + * sync. + */ + +#define __check_align_1 "" + +#define __check_align_2 \ + " _bbci.l %3, 0, 1f \n" \ + " movi %0, %4 \n" \ + " _j 2f \n" + +#define __check_align_4 \ + " _bbsi.l %3, 0, 0f \n" \ + " _bbci.l %3, 1, 1f \n" \ + "0: movi %0, %4 \n" \ + " _j 2f \n" + + +/* + * We don't tell gcc that we are accessing memory, but this is OK + * because we do not write to any memory gcc knows about, so there + * are no aliasing issues. + * + * WARNING: If you modify this macro at all, verify that the + * __check_align_* macros still work. + */ +#define __put_user_asm(x, addr, err, align, insn, cb) \ + __asm__ __volatile__( \ + __check_align_##align \ + "1: "insn" %2, %3, 0 \n" \ + "2: \n" \ + " .section .fixup,\"ax\" \n" \ + " .align 4 \n" \ + "4: \n" \ + " .long 2b \n" \ + "5: \n" \ + " l32r %1, 4b \n" \ + " movi %0, %4 \n" \ + " jx %1 \n" \ + " .previous \n" \ + " .section __ex_table,\"a\" \n" \ + " .long 1b, 5b \n" \ + " .previous" \ + :"=r" (err), "=r" (cb) \ + :"r" ((int)(x)), "r" (addr), "i" (-EFAULT), "0" (err)) + +#define __get_user_nocheck(x,ptr,size) \ +({ \ + long __gu_err, __gu_val; \ + __get_user_size(__gu_val,(ptr),(size),__gu_err); \ + (x) = (__typeof__(*(ptr)))__gu_val; \ + __gu_err; \ +}) + +#define __get_user_check(x,ptr,size) \ +({ \ + long __gu_err = -EFAULT, __gu_val = 0; \ + const __typeof__(*(ptr)) *__gu_addr = (ptr); \ + if (access_ok(VERIFY_READ,__gu_addr,size)) \ + __get_user_size(__gu_val,__gu_addr,(size),__gu_err); \ + (x) = (__typeof__(*(ptr)))__gu_val; \ + __gu_err; \ +}) + +extern long __get_user_bad(void); + +#define __get_user_size(x,ptr,size,retval) \ +do { \ + int __cb; \ + retval = 0; \ + switch (size) { \ + case 1: __get_user_asm(x,ptr,retval,1,"l8ui",__cb); break; \ + case 2: __get_user_asm(x,ptr,retval,2,"l16ui",__cb); break; \ + case 4: __get_user_asm(x,ptr,retval,4,"l32i",__cb); break; \ + case 8: retval = __copy_from_user(&x,ptr,8); break; \ + default: (x) = __get_user_bad(); \ + } \ +} while (0) + + +/* + * WARNING: If you modify this macro at all, verify that the + * __check_align_* macros still work. + */ +#define __get_user_asm(x, addr, err, align, insn, cb) \ + __asm__ __volatile__( \ + __check_align_##align \ + "1: "insn" %2, %3, 0 \n" \ + "2: \n" \ + " .section .fixup,\"ax\" \n" \ + " .align 4 \n" \ + "4: \n" \ + " .long 2b \n" \ + "5: \n" \ + " l32r %1, 4b \n" \ + " movi %2, 0 \n" \ + " movi %0, %4 \n" \ + " jx %1 \n" \ + " .previous \n" \ + " .section __ex_table,\"a\" \n" \ + " .long 1b, 5b \n" \ + " .previous" \ + :"=r" (err), "=r" (cb), "=r" (x) \ + :"r" (addr), "i" (-EFAULT), "0" (err)) + + +/* + * Copy to/from user space + */ + +/* + * We use a generic, arbitrary-sized copy subroutine. The Xtensa + * architecture would cause heavy code bloat if we tried to inline + * these functions and provide __constant_copy_* equivalents like the + * i386 versions. __xtensa_copy_user is quite efficient. See the + * .fixup section of __xtensa_copy_user for a discussion on the + * X_zeroing equivalents for Xtensa. + */ + +extern unsigned __xtensa_copy_user(void *to, const void *from, unsigned n); +#define __copy_user(to,from,size) __xtensa_copy_user(to,from,size) + + +static inline unsigned long +__generic_copy_from_user_nocheck(void *to, const void *from, unsigned long n) +{ + return __copy_user(to,from,n); +} + +static inline unsigned long +__generic_copy_to_user_nocheck(void *to, const void *from, unsigned long n) +{ + return __copy_user(to,from,n); +} + +static inline unsigned long +__generic_copy_to_user(void *to, const void *from, unsigned long n) +{ + prefetch(from); + if (access_ok(VERIFY_WRITE, to, n)) + return __copy_user(to,from,n); + return n; +} + +static inline unsigned long +__generic_copy_from_user(void *to, const void *from, unsigned long n) +{ + prefetchw(to); + if (access_ok(VERIFY_READ, from, n)) + return __copy_user(to,from,n); + else + memset(to, 0, n); + return n; +} + +#define copy_to_user(to,from,n) __generic_copy_to_user((to),(from),(n)) +#define copy_from_user(to,from,n) __generic_copy_from_user((to),(from),(n)) +#define __copy_to_user(to,from,n) __generic_copy_to_user_nocheck((to),(from),(n)) +#define __copy_from_user(to,from,n) __generic_copy_from_user_nocheck((to),(from),(n)) +#define __copy_to_user_inatomic __copy_to_user +#define __copy_from_user_inatomic __copy_from_user + + +/* + * We need to return the number of bytes not cleared. Our memset() + * returns zero if a problem occurs while accessing user-space memory. + * In that event, return no memory cleared. Otherwise, zero for + * success. + */ + +static inline unsigned long +__xtensa_clear_user(void *addr, unsigned long size) +{ + if ( ! memset(addr, 0, size) ) + return size; + return 0; +} + +static inline unsigned long +clear_user(void *addr, unsigned long size) +{ + if (access_ok(VERIFY_WRITE, addr, size)) + return __xtensa_clear_user(addr, size); + return size ? -EFAULT : 0; +} + +#define __clear_user __xtensa_clear_user + + +extern long __strncpy_user(char *, const char *, long); +#define __strncpy_from_user __strncpy_user + +static inline long +strncpy_from_user(char *dst, const char *src, long count) +{ + if (access_ok(VERIFY_READ, src, 1)) + return __strncpy_from_user(dst, src, count); + return -EFAULT; +} + + +#define strlen_user(str) strnlen_user((str), TASK_SIZE - 1) + +/* + * Return the size of a string (including the ending 0!) + */ +extern long __strnlen_user(const char *, long); + +static inline long strnlen_user(const char *str, long len) +{ + unsigned long top = __kernel_ok ? ~0UL : TASK_SIZE - 1; + + if ((unsigned long)str > top) + return 0; + return __strnlen_user(str, len); +} + + +struct exception_table_entry +{ + unsigned long insn, fixup; +}; + +/* Returns 0 if exception not found and fixup.unit otherwise. */ + +extern unsigned long search_exception_table(unsigned long addr); +extern void sort_exception_table(void); + +/* Returns the new pc */ +#define fixup_exception(map_reg, fixup_unit, pc) \ +({ \ + fixup_unit; \ +}) + +#endif /* __ASSEMBLY__ */ +#endif /* _XTENSA_UACCESS_H */ diff --git a/arch/xtensa/include/asm/ucontext.h b/arch/xtensa/include/asm/ucontext.h new file mode 100644 index 00000000..94c94ed3 --- /dev/null +++ b/arch/xtensa/include/asm/ucontext.h @@ -0,0 +1,22 @@ +/* + * include/asm-xtensa/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. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_UCONTEXT_H +#define _XTENSA_UCONTEXT_H + +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 /* _XTENSA_UCONTEXT_H */ diff --git a/arch/xtensa/include/asm/unaligned.h b/arch/xtensa/include/asm/unaligned.h new file mode 100644 index 00000000..8e7ed046 --- /dev/null +++ b/arch/xtensa/include/asm/unaligned.h @@ -0,0 +1,29 @@ +/* + * Xtensa doesn't handle unaligned accesses efficiently. + * + * 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) 2001 - 2005 Tensilica Inc. + */ +#ifndef _ASM_XTENSA_UNALIGNED_H +#define _ASM_XTENSA_UNALIGNED_H + +#include <asm/byteorder.h> + +#ifdef __LITTLE_ENDIAN +# include <linux/unaligned/le_struct.h> +# include <linux/unaligned/be_byteshift.h> +# include <linux/unaligned/generic.h> +# define get_unaligned __get_unaligned_le +# define put_unaligned __put_unaligned_le +#else +# include <linux/unaligned/be_struct.h> +# include <linux/unaligned/le_byteshift.h> +# include <linux/unaligned/generic.h> +# define get_unaligned __get_unaligned_be +# define put_unaligned __put_unaligned_be +#endif + +#endif /* _ASM_XTENSA_UNALIGNED_H */ diff --git a/arch/xtensa/include/asm/unistd.h b/arch/xtensa/include/asm/unistd.h new file mode 100644 index 00000000..798ee6d2 --- /dev/null +++ b/arch/xtensa/include/asm/unistd.h @@ -0,0 +1,739 @@ +/* + * include/asm-xtensa/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. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_UNISTD_H +#define _XTENSA_UNISTD_H + +#ifndef __SYSCALL +# define __SYSCALL(nr,func,nargs) +#endif + +#define __NR_spill 0 +__SYSCALL( 0, sys_ni_syscall, 0) +#define __NR_xtensa 1 +__SYSCALL( 1, sys_ni_syscall, 0) +#define __NR_available4 2 +__SYSCALL( 2, sys_ni_syscall, 0) +#define __NR_available5 3 +__SYSCALL( 3, sys_ni_syscall, 0) +#define __NR_available6 4 +__SYSCALL( 4, sys_ni_syscall, 0) +#define __NR_available7 5 +__SYSCALL( 5, sys_ni_syscall, 0) +#define __NR_available8 6 +__SYSCALL( 6, sys_ni_syscall, 0) +#define __NR_available9 7 +__SYSCALL( 7, sys_ni_syscall, 0) + +/* File Operations */ + +#define __NR_open 8 +__SYSCALL( 8, sys_open, 3) +#define __NR_close 9 +__SYSCALL( 9, sys_close, 1) +#define __NR_dup 10 +__SYSCALL( 10, sys_dup, 1) +#define __NR_dup2 11 +__SYSCALL( 11, sys_dup2, 2) +#define __NR_read 12 +__SYSCALL( 12, sys_read, 3) +#define __NR_write 13 +__SYSCALL( 13, sys_write, 3) +#define __NR_select 14 +__SYSCALL( 14, sys_select, 5) +#define __NR_lseek 15 +__SYSCALL( 15, sys_lseek, 3) +#define __NR_poll 16 +__SYSCALL( 16, sys_poll, 3) +#define __NR__llseek 17 +__SYSCALL( 17, sys_llseek, 5) +#define __NR_epoll_wait 18 +__SYSCALL( 18, sys_epoll_wait, 4) +#define __NR_epoll_ctl 19 +__SYSCALL( 19, sys_epoll_ctl, 4) +#define __NR_epoll_create 20 +__SYSCALL( 20, sys_epoll_create, 1) +#define __NR_creat 21 +__SYSCALL( 21, sys_creat, 2) +#define __NR_truncate 22 +__SYSCALL( 22, sys_truncate, 2) +#define __NR_ftruncate 23 +__SYSCALL( 23, sys_ftruncate, 2) +#define __NR_readv 24 +__SYSCALL( 24, sys_readv, 3) +#define __NR_writev 25 +__SYSCALL( 25, sys_writev, 3) +#define __NR_fsync 26 +__SYSCALL( 26, sys_fsync, 1) +#define __NR_fdatasync 27 +__SYSCALL( 27, sys_fdatasync, 1) +#define __NR_truncate64 28 +__SYSCALL( 28, sys_truncate64, 2) +#define __NR_ftruncate64 29 +__SYSCALL( 29, sys_ftruncate64, 2) +#define __NR_pread64 30 +__SYSCALL( 30, sys_pread64, 6) +#define __NR_pwrite64 31 +__SYSCALL( 31, sys_pwrite64, 6) + +#define __NR_link 32 +__SYSCALL( 32, sys_link, 2) +#define __NR_rename 33 +__SYSCALL( 33, sys_rename, 2) +#define __NR_symlink 34 +__SYSCALL( 34, sys_symlink, 2) +#define __NR_readlink 35 +__SYSCALL( 35, sys_readlink, 3) +#define __NR_mknod 36 +__SYSCALL( 36, sys_mknod, 3) +#define __NR_pipe 37 +__SYSCALL( 37, sys_pipe, 1) +#define __NR_unlink 38 +__SYSCALL( 38, sys_unlink, 1) +#define __NR_rmdir 39 +__SYSCALL( 39, sys_rmdir, 1) + +#define __NR_mkdir 40 +__SYSCALL( 40, sys_mkdir, 2) +#define __NR_chdir 41 +__SYSCALL( 41, sys_chdir, 1) +#define __NR_fchdir 42 +__SYSCALL( 42, sys_fchdir, 1) +#define __NR_getcwd 43 +__SYSCALL( 43, sys_getcwd, 2) + +#define __NR_chmod 44 +__SYSCALL( 44, sys_chmod, 2) +#define __NR_chown 45 +__SYSCALL( 45, sys_chown, 3) +#define __NR_stat 46 +__SYSCALL( 46, sys_newstat, 2) +#define __NR_stat64 47 +__SYSCALL( 47, sys_stat64, 2) + +#define __NR_lchown 48 +__SYSCALL( 48, sys_lchown, 3) +#define __NR_lstat 49 +__SYSCALL( 49, sys_newlstat, 2) +#define __NR_lstat64 50 +__SYSCALL( 50, sys_lstat64, 2) +#define __NR_available51 51 +__SYSCALL( 51, sys_ni_syscall, 0) + +#define __NR_fchmod 52 +__SYSCALL( 52, sys_fchmod, 2) +#define __NR_fchown 53 +__SYSCALL( 53, sys_fchown, 3) +#define __NR_fstat 54 +__SYSCALL( 54, sys_newfstat, 2) +#define __NR_fstat64 55 +__SYSCALL( 55, sys_fstat64, 2) + +#define __NR_flock 56 +__SYSCALL( 56, sys_flock, 2) +#define __NR_access 57 +__SYSCALL( 57, sys_access, 2) +#define __NR_umask 58 +__SYSCALL( 58, sys_umask, 1) +#define __NR_getdents 59 +__SYSCALL( 59, sys_getdents, 3) +#define __NR_getdents64 60 +__SYSCALL( 60, sys_getdents64, 3) +#define __NR_fcntl64 61 +__SYSCALL( 61, sys_fcntl64, 3) +#define __NR_available62 62 +__SYSCALL( 62, sys_ni_syscall, 0) +#define __NR_fadvise64_64 63 +__SYSCALL( 63, xtensa_fadvise64_64, 6) +#define __NR_utime 64 /* glibc 2.3.3 ?? */ +__SYSCALL( 64, sys_utime, 2) +#define __NR_utimes 65 +__SYSCALL( 65, sys_utimes, 2) +#define __NR_ioctl 66 +__SYSCALL( 66, sys_ioctl, 3) +#define __NR_fcntl 67 +__SYSCALL( 67, sys_fcntl, 3) + +#define __NR_setxattr 68 +__SYSCALL( 68, sys_setxattr, 5) +#define __NR_getxattr 69 +__SYSCALL( 69, sys_getxattr, 4) +#define __NR_listxattr 70 +__SYSCALL( 70, sys_listxattr, 3) +#define __NR_removexattr 71 +__SYSCALL( 71, sys_removexattr, 2) +#define __NR_lsetxattr 72 +__SYSCALL( 72, sys_lsetxattr, 5) +#define __NR_lgetxattr 73 +__SYSCALL( 73, sys_lgetxattr, 4) +#define __NR_llistxattr 74 +__SYSCALL( 74, sys_llistxattr, 3) +#define __NR_lremovexattr 75 +__SYSCALL( 75, sys_lremovexattr, 2) +#define __NR_fsetxattr 76 +__SYSCALL( 76, sys_fsetxattr, 5) +#define __NR_fgetxattr 77 +__SYSCALL( 77, sys_fgetxattr, 4) +#define __NR_flistxattr 78 +__SYSCALL( 78, sys_flistxattr, 3) +#define __NR_fremovexattr 79 +__SYSCALL( 79, sys_fremovexattr, 2) + +/* File Map / Shared Memory Operations */ + +#define __NR_mmap2 80 +__SYSCALL( 80, sys_mmap_pgoff, 6) +#define __NR_munmap 81 +__SYSCALL( 81, sys_munmap, 2) +#define __NR_mprotect 82 +__SYSCALL( 82, sys_mprotect, 3) +#define __NR_brk 83 +__SYSCALL( 83, sys_brk, 1) +#define __NR_mlock 84 +__SYSCALL( 84, sys_mlock, 2) +#define __NR_munlock 85 +__SYSCALL( 85, sys_munlock, 2) +#define __NR_mlockall 86 +__SYSCALL( 86, sys_mlockall, 1) +#define __NR_munlockall 87 +__SYSCALL( 87, sys_munlockall, 0) +#define __NR_mremap 88 +__SYSCALL( 88, sys_mremap, 4) +#define __NR_msync 89 +__SYSCALL( 89, sys_msync, 3) +#define __NR_mincore 90 +__SYSCALL( 90, sys_mincore, 3) +#define __NR_madvise 91 +__SYSCALL( 91, sys_madvise, 3) +#define __NR_shmget 92 +__SYSCALL( 92, sys_shmget, 4) +#define __NR_shmat 93 +__SYSCALL( 93, xtensa_shmat, 4) +#define __NR_shmctl 94 +__SYSCALL( 94, sys_shmctl, 4) +#define __NR_shmdt 95 +__SYSCALL( 95, sys_shmdt, 4) + +/* Socket Operations */ + +#define __NR_socket 96 +__SYSCALL( 96, sys_socket, 3) +#define __NR_setsockopt 97 +__SYSCALL( 97, sys_setsockopt, 5) +#define __NR_getsockopt 98 +__SYSCALL( 98, sys_getsockopt, 5) +#define __NR_shutdown 99 +__SYSCALL( 99, sys_shutdown, 2) + +#define __NR_bind 100 +__SYSCALL(100, sys_bind, 3) +#define __NR_connect 101 +__SYSCALL(101, sys_connect, 3) +#define __NR_listen 102 +__SYSCALL(102, sys_listen, 2) +#define __NR_accept 103 +__SYSCALL(103, sys_accept, 3) + +#define __NR_getsockname 104 +__SYSCALL(104, sys_getsockname, 3) +#define __NR_getpeername 105 +__SYSCALL(105, sys_getpeername, 3) +#define __NR_sendmsg 106 +__SYSCALL(106, sys_sendmsg, 3) +#define __NR_recvmsg 107 +__SYSCALL(107, sys_recvmsg, 3) +#define __NR_send 108 +__SYSCALL(108, sys_send, 4) +#define __NR_recv 109 +__SYSCALL(109, sys_recv, 4) +#define __NR_sendto 110 +__SYSCALL(110, sys_sendto, 6) +#define __NR_recvfrom 111 +__SYSCALL(111, sys_recvfrom, 6) + +#define __NR_socketpair 112 +__SYSCALL(112, sys_socketpair, 4) +#define __NR_sendfile 113 +__SYSCALL(113, sys_sendfile, 4) +#define __NR_sendfile64 114 +__SYSCALL(114, sys_sendfile64, 4) +#define __NR_available115 115 +__SYSCALL(115, sys_ni_syscall, 0) + +/* Process Operations */ + +#define __NR_clone 116 +__SYSCALL(116, xtensa_clone, 5) +#define __NR_execve 117 +__SYSCALL(117, xtensa_execve, 3) +#define __NR_exit 118 +__SYSCALL(118, sys_exit, 1) +#define __NR_exit_group 119 +__SYSCALL(119, sys_exit_group, 1) +#define __NR_getpid 120 +__SYSCALL(120, sys_getpid, 0) +#define __NR_wait4 121 +__SYSCALL(121, sys_wait4, 4) +#define __NR_waitid 122 +__SYSCALL(122, sys_waitid, 5) +#define __NR_kill 123 +__SYSCALL(123, sys_kill, 2) +#define __NR_tkill 124 +__SYSCALL(124, sys_tkill, 2) +#define __NR_tgkill 125 +__SYSCALL(125, sys_tgkill, 3) +#define __NR_set_tid_address 126 +__SYSCALL(126, sys_set_tid_address, 1) +#define __NR_gettid 127 +__SYSCALL(127, sys_gettid, 0) +#define __NR_setsid 128 +__SYSCALL(128, sys_setsid, 0) +#define __NR_getsid 129 +__SYSCALL(129, sys_getsid, 1) +#define __NR_prctl 130 +__SYSCALL(130, sys_prctl, 5) +#define __NR_personality 131 +__SYSCALL(131, sys_personality, 1) +#define __NR_getpriority 132 +__SYSCALL(132, sys_getpriority, 2) +#define __NR_setpriority 133 +__SYSCALL(133, sys_setpriority, 3) +#define __NR_setitimer 134 +__SYSCALL(134, sys_setitimer, 3) +#define __NR_getitimer 135 +__SYSCALL(135, sys_getitimer, 2) +#define __NR_setuid 136 +__SYSCALL(136, sys_setuid, 1) +#define __NR_getuid 137 +__SYSCALL(137, sys_getuid, 0) +#define __NR_setgid 138 +__SYSCALL(138, sys_setgid, 1) +#define __NR_getgid 139 +__SYSCALL(139, sys_getgid, 0) +#define __NR_geteuid 140 +__SYSCALL(140, sys_geteuid, 0) +#define __NR_getegid 141 +__SYSCALL(141, sys_getegid, 0) +#define __NR_setreuid 142 +__SYSCALL(142, sys_setreuid, 2) +#define __NR_setregid 143 +__SYSCALL(143, sys_setregid, 2) +#define __NR_setresuid 144 +__SYSCALL(144, sys_setresuid, 3) +#define __NR_getresuid 145 +__SYSCALL(145, sys_getresuid, 3) +#define __NR_setresgid 146 +__SYSCALL(146, sys_setresgid, 3) +#define __NR_getresgid 147 +__SYSCALL(147, sys_getresgid, 3) +#define __NR_setpgid 148 +__SYSCALL(148, sys_setpgid, 2) +#define __NR_getpgid 149 +__SYSCALL(149, sys_getpgid, 1) +#define __NR_getppid 150 +__SYSCALL(150, sys_getppid, 0) +#define __NR_getpgrp 151 +__SYSCALL(151, sys_getpgrp, 0) + +#define __NR_reserved152 152 /* set_thread_area */ +__SYSCALL(152, sys_ni_syscall, 0) +#define __NR_reserved153 153 /* get_thread_area */ +__SYSCALL(153, sys_ni_syscall, 0) +#define __NR_times 154 +__SYSCALL(154, sys_times, 1) +#define __NR_acct 155 +__SYSCALL(155, sys_acct, 1) +#define __NR_sched_setaffinity 156 +__SYSCALL(156, sys_sched_setaffinity, 3) +#define __NR_sched_getaffinity 157 +__SYSCALL(157, sys_sched_getaffinity, 3) +#define __NR_capget 158 +__SYSCALL(158, sys_capget, 2) +#define __NR_capset 159 +__SYSCALL(159, sys_capset, 2) +#define __NR_ptrace 160 +__SYSCALL(160, sys_ptrace, 4) +#define __NR_semtimedop 161 +__SYSCALL(161, sys_semtimedop, 5) +#define __NR_semget 162 +__SYSCALL(162, sys_semget, 4) +#define __NR_semop 163 +__SYSCALL(163, sys_semop, 4) +#define __NR_semctl 164 +__SYSCALL(164, sys_semctl, 4) +#define __NR_available165 165 +__SYSCALL(165, sys_ni_syscall, 0) +#define __NR_msgget 166 +__SYSCALL(166, sys_msgget, 4) +#define __NR_msgsnd 167 +__SYSCALL(167, sys_msgsnd, 4) +#define __NR_msgrcv 168 +__SYSCALL(168, sys_msgrcv, 4) +#define __NR_msgctl 169 +__SYSCALL(169, sys_msgctl, 4) +#define __NR_available170 170 +__SYSCALL(170, sys_ni_syscall, 0) +#define __NR_available171 171 +__SYSCALL(171, sys_ni_syscall, 0) + +/* File System */ + +#define __NR_mount 172 +__SYSCALL(172, sys_mount, 5) +#define __NR_swapon 173 +__SYSCALL(173, sys_swapon, 2) +#define __NR_chroot 174 +__SYSCALL(174, sys_chroot, 1) +#define __NR_pivot_root 175 +__SYSCALL(175, sys_pivot_root, 2) +#define __NR_umount 176 +__SYSCALL(176, sys_umount, 2) +#define __NR_swapoff 177 +__SYSCALL(177, sys_swapoff, 1) +#define __NR_sync 178 +__SYSCALL(178, sys_sync, 0) +#define __NR_available179 179 +__SYSCALL(179, sys_ni_syscall, 0) +#define __NR_setfsuid 180 +__SYSCALL(180, sys_setfsuid, 1) +#define __NR_setfsgid 181 +__SYSCALL(181, sys_setfsgid, 1) +#define __NR_sysfs 182 +__SYSCALL(182, sys_sysfs, 3) +#define __NR_ustat 183 +__SYSCALL(183, sys_ustat, 2) +#define __NR_statfs 184 +__SYSCALL(184, sys_statfs, 2) +#define __NR_fstatfs 185 +__SYSCALL(185, sys_fstatfs, 2) +#define __NR_statfs64 186 +__SYSCALL(186, sys_statfs64, 3) +#define __NR_fstatfs64 187 +__SYSCALL(187, sys_fstatfs64, 3) + +/* System */ + +#define __NR_setrlimit 188 +__SYSCALL(188, sys_setrlimit, 2) +#define __NR_getrlimit 189 +__SYSCALL(189, sys_getrlimit, 2) +#define __NR_getrusage 190 +__SYSCALL(190, sys_getrusage, 2) +#define __NR_futex 191 +__SYSCALL(191, sys_futex, 5) +#define __NR_gettimeofday 192 +__SYSCALL(192, sys_gettimeofday, 2) +#define __NR_settimeofday 193 +__SYSCALL(193, sys_settimeofday, 2) +#define __NR_adjtimex 194 +__SYSCALL(194, sys_adjtimex, 1) +#define __NR_nanosleep 195 +__SYSCALL(195, sys_nanosleep, 2) +#define __NR_getgroups 196 +__SYSCALL(196, sys_getgroups, 2) +#define __NR_setgroups 197 +__SYSCALL(197, sys_setgroups, 2) +#define __NR_sethostname 198 +__SYSCALL(198, sys_sethostname, 2) +#define __NR_setdomainname 199 +__SYSCALL(199, sys_setdomainname, 2) +#define __NR_syslog 200 +__SYSCALL(200, sys_syslog, 3) +#define __NR_vhangup 201 +__SYSCALL(201, sys_vhangup, 0) +#define __NR_uselib 202 +__SYSCALL(202, sys_uselib, 1) +#define __NR_reboot 203 +__SYSCALL(203, sys_reboot, 3) +#define __NR_quotactl 204 +__SYSCALL(204, sys_quotactl, 4) +#define __NR_nfsservctl 205 +__SYSCALL(205, sys_ni_syscall, 0) +#define __NR__sysctl 206 +__SYSCALL(206, sys_sysctl, 1) +#define __NR_bdflush 207 +__SYSCALL(207, sys_bdflush, 2) +#define __NR_uname 208 +__SYSCALL(208, sys_newuname, 1) +#define __NR_sysinfo 209 +__SYSCALL(209, sys_sysinfo, 1) +#define __NR_init_module 210 +__SYSCALL(210, sys_init_module, 2) +#define __NR_delete_module 211 +__SYSCALL(211, sys_delete_module, 1) + +#define __NR_sched_setparam 212 +__SYSCALL(212, sys_sched_setparam, 2) +#define __NR_sched_getparam 213 +__SYSCALL(213, sys_sched_getparam, 2) +#define __NR_sched_setscheduler 214 +__SYSCALL(214, sys_sched_setscheduler, 3) +#define __NR_sched_getscheduler 215 +__SYSCALL(215, sys_sched_getscheduler, 1) +#define __NR_sched_get_priority_max 216 +__SYSCALL(216, sys_sched_get_priority_max, 1) +#define __NR_sched_get_priority_min 217 +__SYSCALL(217, sys_sched_get_priority_min, 1) +#define __NR_sched_rr_get_interval 218 +__SYSCALL(218, sys_sched_rr_get_interval, 2) +#define __NR_sched_yield 219 +__SYSCALL(219, sys_sched_yield, 0) +#define __NR_available222 222 +__SYSCALL(222, sys_ni_syscall, 0) + +/* Signal Handling */ + +#define __NR_restart_syscall 223 +__SYSCALL(223, sys_restart_syscall, 0) +#define __NR_sigaltstack 224 +__SYSCALL(224, xtensa_sigaltstack, 2) +#define __NR_rt_sigreturn 225 +__SYSCALL(225, xtensa_rt_sigreturn, 1) +#define __NR_rt_sigaction 226 +__SYSCALL(226, sys_rt_sigaction, 4) +#define __NR_rt_sigprocmask 227 +__SYSCALL(227, sys_rt_sigprocmask, 4) +#define __NR_rt_sigpending 228 +__SYSCALL(228, sys_rt_sigpending, 2) +#define __NR_rt_sigtimedwait 229 +__SYSCALL(229, sys_rt_sigtimedwait, 4) +#define __NR_rt_sigqueueinfo 230 +__SYSCALL(230, sys_rt_sigqueueinfo, 3) +#define __NR_rt_sigsuspend 231 +__SYSCALL(231, xtensa_rt_sigsuspend, 2) + +/* Message */ + +#define __NR_mq_open 232 +__SYSCALL(232, sys_mq_open, 4) +#define __NR_mq_unlink 233 +__SYSCALL(233, sys_mq_unlink, 1) +#define __NR_mq_timedsend 234 +__SYSCALL(234, sys_mq_timedsend, 5) +#define __NR_mq_timedreceive 235 +__SYSCALL(235, sys_mq_timedreceive, 5) +#define __NR_mq_notify 236 +__SYSCALL(236, sys_mq_notify, 2) +#define __NR_mq_getsetattr 237 +__SYSCALL(237, sys_mq_getsetattr, 3) +#define __NR_available238 238 +__SYSCALL(238, sys_ni_syscall, 0) + +/* IO */ + +#define __NR_io_setup 239 +__SYSCALL(239, sys_io_setup, 2) +#define __NR_io_destroy 240 +__SYSCALL(240, sys_io_destroy, 1) +#define __NR_io_submit 241 +__SYSCALL(241, sys_io_submit, 3) +#define __NR_io_getevents 242 +__SYSCALL(242, sys_io_getevents, 5) +#define __NR_io_cancel 243 +__SYSCALL(243, sys_io_cancel, 3) +#define __NR_clock_settime 244 +__SYSCALL(244, sys_clock_settime, 2) +#define __NR_clock_gettime 245 +__SYSCALL(245, sys_clock_gettime, 2) +#define __NR_clock_getres 246 +__SYSCALL(246, sys_clock_getres, 2) +#define __NR_clock_nanosleep 247 +__SYSCALL(247, sys_clock_nanosleep, 4) + +/* Timer */ + +#define __NR_timer_create 248 +__SYSCALL(248, sys_timer_create, 3) +#define __NR_timer_delete 249 +__SYSCALL(249, sys_timer_delete, 1) +#define __NR_timer_settime 250 +__SYSCALL(250, sys_timer_settime, 4) +#define __NR_timer_gettime 251 +__SYSCALL(251, sys_timer_gettime, 2) +#define __NR_timer_getoverrun 252 +__SYSCALL(252, sys_timer_getoverrun, 1) + +/* System */ + +#define __NR_reserved244 253 +__SYSCALL(253, sys_ni_syscall, 0) +#define __NR_lookup_dcookie 254 +__SYSCALL(254, sys_lookup_dcookie, 4) +#define __NR_available255 255 +__SYSCALL(255, sys_ni_syscall, 0) +#define __NR_add_key 256 +__SYSCALL(256, sys_add_key, 5) +#define __NR_request_key 257 +__SYSCALL(257, sys_request_key, 5) +#define __NR_keyctl 258 +__SYSCALL(258, sys_keyctl, 5) +#define __NR_available259 259 +__SYSCALL(259, sys_ni_syscall, 0) + + +#define __NR_readahead 260 +__SYSCALL(260, sys_readahead, 5) +#define __NR_remap_file_pages 261 +__SYSCALL(261, sys_remap_file_pages, 5) +#define __NR_migrate_pages 262 +__SYSCALL(262, sys_migrate_pages, 0) +#define __NR_mbind 263 +__SYSCALL(263, sys_mbind, 6) +#define __NR_get_mempolicy 264 +__SYSCALL(264, sys_get_mempolicy, 5) +#define __NR_set_mempolicy 265 +__SYSCALL(265, sys_set_mempolicy, 3) +#define __NR_unshare 266 +__SYSCALL(266, sys_unshare, 1) +#define __NR_move_pages 267 +__SYSCALL(267, sys_move_pages, 0) +#define __NR_splice 268 +__SYSCALL(268, sys_splice, 0) +#define __NR_tee 269 +__SYSCALL(269, sys_tee, 0) +#define __NR_vmsplice 270 +__SYSCALL(270, sys_vmsplice, 0) +#define __NR_available271 271 +__SYSCALL(271, sys_ni_syscall, 0) + +#define __NR_pselect6 272 +__SYSCALL(272, sys_pselect6, 0) +#define __NR_ppoll 273 +__SYSCALL(273, sys_ppoll, 0) +#define __NR_epoll_pwait 274 +__SYSCALL(274, sys_epoll_pwait, 0) +#define __NR_available275 275 +__SYSCALL(275, sys_ni_syscall, 0) + +#define __NR_inotify_init 276 +__SYSCALL(276, sys_inotify_init, 0) +#define __NR_inotify_add_watch 277 +__SYSCALL(277, sys_inotify_add_watch, 3) +#define __NR_inotify_rm_watch 278 +__SYSCALL(278, sys_inotify_rm_watch, 2) +#define __NR_available279 279 +__SYSCALL(279, sys_ni_syscall, 0) + +#define __NR_getcpu 280 +__SYSCALL(280, sys_getcpu, 0) +#define __NR_kexec_load 281 +__SYSCALL(281, sys_ni_syscall, 0) + +#define __NR_ioprio_set 282 +__SYSCALL(282, sys_ioprio_set, 2) +#define __NR_ioprio_get 283 +__SYSCALL(283, sys_ioprio_get, 3) + +#define __NR_set_robust_list 284 +__SYSCALL(284, sys_set_robust_list, 3) +#define __NR_get_robust_list 285 +__SYSCALL(285, sys_get_robust_list, 3) +#define __NR_reserved286 286 /* sync_file_rangeX */ +__SYSCALL(286, sys_ni_syscall, 3) +#define __NR_available287 287 +__SYSCALL(287, sys_faccessat, 0) + +/* Relative File Operations */ + +#define __NR_openat 288 +__SYSCALL(288, sys_openat, 4) +#define __NR_mkdirat 289 +__SYSCALL(289, sys_mkdirat, 3) +#define __NR_mknodat 290 +__SYSCALL(290, sys_mknodat, 4) +#define __NR_unlinkat 291 +__SYSCALL(291, sys_unlinkat, 3) +#define __NR_renameat 292 +__SYSCALL(292, sys_renameat, 4) +#define __NR_linkat 293 +__SYSCALL(293, sys_linkat, 5) +#define __NR_symlinkat 294 +__SYSCALL(294, sys_symlinkat, 3) +#define __NR_readlinkat 295 +__SYSCALL(295, sys_readlinkat, 4) +#define __NR_utimensat 296 +__SYSCALL(296, sys_utimensat, 0) +#define __NR_fchownat 297 +__SYSCALL(297, sys_fchownat, 5) +#define __NR_futimesat 298 +__SYSCALL(298, sys_futimesat, 4) +#define __NR_fstatat64 299 +__SYSCALL(299, sys_fstatat64, 0) +#define __NR_fchmodat 300 +__SYSCALL(300, sys_fchmodat, 4) +#define __NR_faccessat 301 +__SYSCALL(301, sys_faccessat, 4) +#define __NR_available302 302 +__SYSCALL(302, sys_ni_syscall, 0) +#define __NR_available303 303 +__SYSCALL(303, sys_ni_syscall, 0) + +#define __NR_signalfd 304 +__SYSCALL(304, sys_signalfd, 3) +/* 305 was __NR_timerfd */ +__SYSCALL(305, sys_ni_syscall, 0) +#define __NR_eventfd 306 +__SYSCALL(306, sys_eventfd, 1) +#define __NR_recvmmsg 307 +__SYSCALL(307, sys_recvmmsg, 5) +#define __NR_setns 308 +__SYSCALL(308, sys_setns, 2) + +#define __NR_syscall_count 309 + +/* + * sysxtensa syscall handler + * + * int sysxtensa (SYS_XTENSA_ATOMIC_SET, ptr, val, unused); + * int sysxtensa (SYS_XTENSA_ATOMIC_ADD, ptr, val, unused); + * int sysxtensa (SYS_XTENSA_ATOMIC_EXG_ADD, ptr, val, unused); + * int sysxtensa (SYS_XTENSA_ATOMIC_CMP_SWP, ptr, oldval, newval); + * a2 a6 a3 a4 a5 + */ + +#define SYS_XTENSA_RESERVED 0 /* don't use this */ +#define SYS_XTENSA_ATOMIC_SET 1 /* set variable */ +#define SYS_XTENSA_ATOMIC_EXG_ADD 2 /* exchange memory and add */ +#define SYS_XTENSA_ATOMIC_ADD 3 /* add to memory */ +#define SYS_XTENSA_ATOMIC_CMP_SWP 4 /* compare and swap */ + +#define SYS_XTENSA_COUNT 5 /* count */ + +#ifdef __KERNEL__ + +/* + * "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 + */ +#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall"); + +#define __ARCH_WANT_STAT64 +#define __ARCH_WANT_SYS_UTIME +#define __ARCH_WANT_SYS_LLSEEK +#define __ARCH_WANT_SYS_RT_SIGACTION +#define __ARCH_WANT_SYS_RT_SIGSUSPEND +#define __ARCH_WANT_SYS_GETPGRP + +/* + * Ignore legacy system calls in the checksyscalls.sh script + */ + +#define __IGNORE_fork /* use clone */ +#define __IGNORE_time +#define __IGNORE_alarm /* use setitimer */ +#define __IGNORE_pause +#define __IGNORE_mmap /* use mmap2 */ +#define __IGNORE_vfork /* use clone */ +#define __IGNORE_fadvise64 /* use fadvise64_64 */ + +#endif /* __KERNEL__ */ +#endif /* _XTENSA_UNISTD_H */ diff --git a/arch/xtensa/include/asm/user.h b/arch/xtensa/include/asm/user.h new file mode 100644 index 00000000..2c3ed233 --- /dev/null +++ b/arch/xtensa/include/asm/user.h @@ -0,0 +1,20 @@ +/* + * include/asm-xtensa/user.h + * + * Xtensa Processor version. + * + * 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) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_USER_H +#define _XTENSA_USER_H + +/* This file usually defines a 'struct user' structure. However, it it only + * used for a.out file, which are not supported on Xtensa. + */ + +#endif /* _XTENSA_USER_H */ diff --git a/arch/xtensa/include/asm/vga.h b/arch/xtensa/include/asm/vga.h new file mode 100644 index 00000000..1fd8cab3 --- /dev/null +++ b/arch/xtensa/include/asm/vga.h @@ -0,0 +1,19 @@ +/* + * include/asm-xtensa/vga.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_VGA_H +#define _XTENSA_VGA_H + +#define VGA_MAP_MEM(x,s) (unsigned long)phys_to_virt(x) + +#define vga_readb(x) (*(x)) +#define vga_writeb(x,y) (*(y) = (x)) + +#endif diff --git a/arch/xtensa/include/asm/xor.h b/arch/xtensa/include/asm/xor.h new file mode 100644 index 00000000..e7b1f083 --- /dev/null +++ b/arch/xtensa/include/asm/xor.h @@ -0,0 +1,16 @@ +/* + * include/asm-xtensa/xor.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_XOR_H +#define _XTENSA_XOR_H + +#include <asm-generic/xor.h> + +#endif diff --git a/arch/xtensa/kernel/Makefile b/arch/xtensa/kernel/Makefile new file mode 100644 index 00000000..2d2728b3 --- /dev/null +++ b/arch/xtensa/kernel/Makefile @@ -0,0 +1,34 @@ +# +# Makefile for the Linux/Xtensa kernel. +# + +extra-y := head.o vmlinux.lds + +obj-y := align.o entry.o irq.o coprocessor.o process.o ptrace.o \ + setup.o signal.o syscall.o time.o traps.o vectors.o platform.o \ + pci-dma.o init_task.o io.o + +obj-$(CONFIG_KGDB) += xtensa-stub.o +obj-$(CONFIG_PCI) += pci.o +obj-$(CONFIG_MODULES) += xtensa_ksyms.o module.o + +# In the Xtensa architecture, assembly generates literals which must always +# precede the L32R instruction with a relative offset less than 256 kB. +# Therefore, the .text and .literal section must be combined in parenthesis +# in the linker script, such as: *(.literal .text). +# +# We need to post-process the generated vmlinux.lds scripts to convert +# *(xxx.text) to *(xxx.literal xxx.text) for the following text sections: +# .text .ref.text .*init.text .*exit.text .text.* +# +# Replicate rules in scripts/Makefile.build + +sed-y = -e 's/\*(\(\.[a-z]*it\|\.ref\|\)\.text)/*(\1.literal \1.text)/g' \ + -e 's/\*(\(\.text\.[a-z]*\))/*(\1.literal \1)/g' + +quiet_cmd__cpp_lds_S = LDS $@ + cmd__cpp_lds_S = $(CPP) $(cpp_flags) -P -C -Uxtensa -D__ASSEMBLY__ $< \ + | sed $(sed-y) >$@ + +$(obj)/vmlinux.lds: $(src)/vmlinux.lds.S FORCE + $(call if_changed_dep,_cpp_lds_S) diff --git a/arch/xtensa/kernel/align.S b/arch/xtensa/kernel/align.S new file mode 100644 index 00000000..33d6e9d2 --- /dev/null +++ b/arch/xtensa/kernel/align.S @@ -0,0 +1,455 @@ +/* + * arch/xtensa/kernel/align.S + * + * Handle unalignment exceptions in kernel space. + * + * 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) 2001 - 2005 Tensilica, Inc. + * + * Rewritten by Chris Zankel <chris@zankel.net> + * + * Based on work from Joe Taylor <joe@tensilica.com, joetylr@yahoo.com> + * and Marc Gauthier <marc@tensilica.com, marc@alimni.uwaterloo.ca> + */ + +#include <linux/linkage.h> +#include <asm/current.h> +#include <asm/asm-offsets.h> +#include <asm/processor.h> + +#if XCHAL_UNALIGNED_LOAD_EXCEPTION || XCHAL_UNALIGNED_STORE_EXCEPTION + +/* First-level exception handler for unaligned exceptions. + * + * Note: This handler works only for kernel exceptions. Unaligned user + * access should get a seg fault. + */ + +/* Big and little endian 16-bit values are located in + * different halves of a register. HWORD_START helps to + * abstract the notion of extracting a 16-bit value from a + * register. + * We also have to define new shifting instructions because + * lsb and msb are on 'opposite' ends in a register for + * different endian machines. + * + * Assume a memory region in ascending address: + * 0 1 2 3|4 5 6 7 + * + * When loading one word into a register, the content of that register is: + * LE 3 2 1 0, 7 6 5 4 + * BE 0 1 2 3, 4 5 6 7 + * + * Masking the bits of the higher/lower address means: + * LE X X 0 0, 0 0 X X + * BE 0 0 X X, X X 0 0 + * + * Shifting to higher/lower addresses, means: + * LE shift left / shift right + * BE shift right / shift left + * + * Extracting 16 bits from a 32 bit reg. value to higher/lower address means: + * LE mask 0 0 X X / shift left + * BE shift left / mask 0 0 X X + */ + +#define UNALIGNED_USER_EXCEPTION + +#if XCHAL_HAVE_BE + +#define HWORD_START 16 +#define INSN_OP0 28 +#define INSN_T 24 +#define INSN_OP1 16 + +.macro __src_b r, w0, w1; src \r, \w0, \w1; .endm +.macro __ssa8 r; ssa8b \r; .endm +.macro __ssa8r r; ssa8l \r; .endm +.macro __sh r, s; srl \r, \s; .endm +.macro __sl r, s; sll \r, \s; .endm +.macro __exth r, s; extui \r, \s, 0, 16; .endm +.macro __extl r, s; slli \r, \s, 16; .endm + +#else + +#define HWORD_START 0 +#define INSN_OP0 0 +#define INSN_T 4 +#define INSN_OP1 12 + +.macro __src_b r, w0, w1; src \r, \w1, \w0; .endm +.macro __ssa8 r; ssa8l \r; .endm +.macro __ssa8r r; ssa8b \r; .endm +.macro __sh r, s; sll \r, \s; .endm +.macro __sl r, s; srl \r, \s; .endm +.macro __exth r, s; slli \r, \s, 16; .endm +.macro __extl r, s; extui \r, \s, 0, 16; .endm + +#endif + +/* + * xxxx xxxx = imm8 field + * yyyy = imm4 field + * ssss = s field + * tttt = t field + * + * 16 0 + * ------------------- + * L32I.N yyyy ssss tttt 1000 + * S32I.N yyyy ssss tttt 1001 + * + * 23 0 + * ----------------------------- + * res 0000 0010 + * L16UI xxxx xxxx 0001 ssss tttt 0010 + * L32I xxxx xxxx 0010 ssss tttt 0010 + * XXX 0011 ssss tttt 0010 + * XXX 0100 ssss tttt 0010 + * S16I xxxx xxxx 0101 ssss tttt 0010 + * S32I xxxx xxxx 0110 ssss tttt 0010 + * XXX 0111 ssss tttt 0010 + * XXX 1000 ssss tttt 0010 + * L16SI xxxx xxxx 1001 ssss tttt 0010 + * XXX 1010 0010 + * **L32AI xxxx xxxx 1011 ssss tttt 0010 unsupported + * XXX 1100 0010 + * XXX 1101 0010 + * XXX 1110 0010 + * **S32RI xxxx xxxx 1111 ssss tttt 0010 unsupported + * ----------------------------- + * ^ ^ ^ + * sub-opcode (NIBBLE_R) -+ | | + * t field (NIBBLE_T) -----------+ | + * major opcode (NIBBLE_OP0) --------------+ + */ + +#define OP0_L32I_N 0x8 /* load immediate narrow */ +#define OP0_S32I_N 0x9 /* store immediate narrow */ +#define OP1_SI_MASK 0x4 /* OP1 bit set for stores */ +#define OP1_SI_BIT 2 /* OP1 bit number for stores */ + +#define OP1_L32I 0x2 +#define OP1_L16UI 0x1 +#define OP1_L16SI 0x9 +#define OP1_L32AI 0xb + +#define OP1_S32I 0x6 +#define OP1_S16I 0x5 +#define OP1_S32RI 0xf + +/* + * Entry condition: + * + * a0: trashed, original value saved on stack (PT_AREG0) + * a1: a1 + * a2: new stack pointer, original in DEPC + * a3: dispatch table + * depc: a2, original value saved on stack (PT_DEPC) + * excsave_1: a3 + * + * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC + * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception + */ + + +ENTRY(fast_unaligned) + + /* Note: We don't expect the address to be aligned on a word + * boundary. After all, the processor generated that exception + * and it would be a hardware fault. + */ + + /* Save some working register */ + + s32i a4, a2, PT_AREG4 + s32i a5, a2, PT_AREG5 + s32i a6, a2, PT_AREG6 + s32i a7, a2, PT_AREG7 + s32i a8, a2, PT_AREG8 + + rsr a0, DEPC + xsr a3, EXCSAVE_1 + s32i a0, a2, PT_AREG2 + s32i a3, a2, PT_AREG3 + + /* Keep value of SAR in a0 */ + + rsr a0, SAR + rsr a8, EXCVADDR # load unaligned memory address + + /* Now, identify one of the following load/store instructions. + * + * The only possible danger of a double exception on the + * following l32i instructions is kernel code in vmalloc + * memory. The processor was just executing at the EPC_1 + * address, and indeed, already fetched the instruction. That + * guarantees a TLB mapping, which hasn't been replaced by + * this unaligned exception handler that uses only static TLB + * mappings. However, high-level interrupt handlers might + * modify TLB entries, so for the generic case, we register a + * TABLE_FIXUP handler here, too. + */ + + /* a3...a6 saved on stack, a2 = SP */ + + /* Extract the instruction that caused the unaligned access. */ + + rsr a7, EPC_1 # load exception address + movi a3, ~3 + and a3, a3, a7 # mask lower bits + + l32i a4, a3, 0 # load 2 words + l32i a5, a3, 4 + + __ssa8 a7 + __src_b a4, a4, a5 # a4 has the instruction + + /* Analyze the instruction (load or store?). */ + + extui a5, a4, INSN_OP0, 4 # get insn.op0 nibble + +#if XCHAL_HAVE_DENSITY + _beqi a5, OP0_L32I_N, .Lload # L32I.N, jump + addi a6, a5, -OP0_S32I_N + _beqz a6, .Lstore # S32I.N, do a store +#endif + /* 'store indicator bit' not set, jump */ + _bbci.l a4, OP1_SI_BIT + INSN_OP1, .Lload + + /* Store: Jump to table entry to get the value in the source register.*/ + +.Lstore:movi a5, .Lstore_table # table + extui a6, a4, INSN_T, 4 # get source register + addx8 a5, a6, a5 + jx a5 # jump into table + + /* Invalid instruction, CRITICAL! */ +.Linvalid_instruction_load: + j .Linvalid_instruction + + /* Load: Load memory address. */ + +.Lload: movi a3, ~3 + and a3, a3, a8 # align memory address + + __ssa8 a8 +#ifdef UNALIGNED_USER_EXCEPTION + addi a3, a3, 8 + l32e a5, a3, -8 + l32e a6, a3, -4 +#else + l32i a5, a3, 0 + l32i a6, a3, 4 +#endif + __src_b a3, a5, a6 # a3 has the data word + +#if XCHAL_HAVE_DENSITY + addi a7, a7, 2 # increment PC (assume 16-bit insn) + + extui a5, a4, INSN_OP0, 4 + _beqi a5, OP0_L32I_N, 1f # l32i.n: jump + + addi a7, a7, 1 +#else + addi a7, a7, 3 +#endif + + extui a5, a4, INSN_OP1, 4 + _beqi a5, OP1_L32I, 1f # l32i: jump + + extui a3, a3, 0, 16 # extract lower 16 bits + _beqi a5, OP1_L16UI, 1f + addi a5, a5, -OP1_L16SI + _bnez a5, .Linvalid_instruction_load + + /* sign extend value */ + + slli a3, a3, 16 + srai a3, a3, 16 + + /* Set target register. */ + +1: + +#if XCHAL_HAVE_LOOPS + rsr a5, LEND # check if we reached LEND + bne a7, a5, 1f + rsr a5, LCOUNT # and LCOUNT != 0 + beqz a5, 1f + addi a5, a5, -1 # decrement LCOUNT and set + rsr a7, LBEG # set PC to LBEGIN + wsr a5, LCOUNT +#endif + +1: wsr a7, EPC_1 # skip load instruction + extui a4, a4, INSN_T, 4 # extract target register + movi a5, .Lload_table + addx8 a4, a4, a5 + jx a4 # jump to entry for target register + + .align 8 +.Lload_table: + s32i a3, a2, PT_AREG0; _j .Lexit; .align 8 + mov a1, a3; _j .Lexit; .align 8 # fishy?? + s32i a3, a2, PT_AREG2; _j .Lexit; .align 8 + s32i a3, a2, PT_AREG3; _j .Lexit; .align 8 + s32i a3, a2, PT_AREG4; _j .Lexit; .align 8 + s32i a3, a2, PT_AREG5; _j .Lexit; .align 8 + s32i a3, a2, PT_AREG6; _j .Lexit; .align 8 + s32i a3, a2, PT_AREG7; _j .Lexit; .align 8 + s32i a3, a2, PT_AREG8; _j .Lexit; .align 8 + mov a9, a3 ; _j .Lexit; .align 8 + mov a10, a3 ; _j .Lexit; .align 8 + mov a11, a3 ; _j .Lexit; .align 8 + mov a12, a3 ; _j .Lexit; .align 8 + mov a13, a3 ; _j .Lexit; .align 8 + mov a14, a3 ; _j .Lexit; .align 8 + mov a15, a3 ; _j .Lexit; .align 8 + +.Lstore_table: + l32i a3, a2, PT_AREG0; _j 1f; .align 8 + mov a3, a1; _j 1f; .align 8 # fishy?? + l32i a3, a2, PT_AREG2; _j 1f; .align 8 + l32i a3, a2, PT_AREG3; _j 1f; .align 8 + l32i a3, a2, PT_AREG4; _j 1f; .align 8 + l32i a3, a2, PT_AREG5; _j 1f; .align 8 + l32i a3, a2, PT_AREG6; _j 1f; .align 8 + l32i a3, a2, PT_AREG7; _j 1f; .align 8 + l32i a3, a2, PT_AREG8; _j 1f; .align 8 + mov a3, a9 ; _j 1f; .align 8 + mov a3, a10 ; _j 1f; .align 8 + mov a3, a11 ; _j 1f; .align 8 + mov a3, a12 ; _j 1f; .align 8 + mov a3, a13 ; _j 1f; .align 8 + mov a3, a14 ; _j 1f; .align 8 + mov a3, a15 ; _j 1f; .align 8 + +1: # a7: instruction pointer, a4: instruction, a3: value + + movi a6, 0 # mask: ffffffff:00000000 + +#if XCHAL_HAVE_DENSITY + addi a7, a7, 2 # incr. PC,assume 16-bit instruction + + extui a5, a4, INSN_OP0, 4 # extract OP0 + addi a5, a5, -OP0_S32I_N + _beqz a5, 1f # s32i.n: jump + + addi a7, a7, 1 # increment PC, 32-bit instruction +#else + addi a7, a7, 3 # increment PC, 32-bit instruction +#endif + + extui a5, a4, INSN_OP1, 4 # extract OP1 + _beqi a5, OP1_S32I, 1f # jump if 32 bit store + _bnei a5, OP1_S16I, .Linvalid_instruction_store + + movi a5, -1 + __extl a3, a3 # get 16-bit value + __exth a6, a5 # get 16-bit mask ffffffff:ffff0000 + + /* Get memory address */ + +1: +#if XCHAL_HAVE_LOOPS + rsr a4, LEND # check if we reached LEND + bne a7, a4, 1f + rsr a4, LCOUNT # and LCOUNT != 0 + beqz a4, 1f + addi a4, a4, -1 # decrement LCOUNT and set + rsr a7, LBEG # set PC to LBEGIN + wsr a4, LCOUNT +#endif + +1: wsr a7, EPC_1 # skip store instruction + movi a4, ~3 + and a4, a4, a8 # align memory address + + /* Insert value into memory */ + + movi a5, -1 # mask: ffffffff:XXXX0000 +#ifdef UNALIGNED_USER_EXCEPTION + addi a4, a4, 8 +#endif + + __ssa8r a8 + __src_b a7, a5, a6 # lo-mask F..F0..0 (BE) 0..0F..F (LE) + __src_b a6, a6, a5 # hi-mask 0..0F..F (BE) F..F0..0 (LE) +#ifdef UNALIGNED_USER_EXCEPTION + l32e a5, a4, -8 +#else + l32i a5, a4, 0 # load lower address word +#endif + and a5, a5, a7 # mask + __sh a7, a3 # shift value + or a5, a5, a7 # or with original value +#ifdef UNALIGNED_USER_EXCEPTION + s32e a5, a4, -8 + l32e a7, a4, -4 +#else + s32i a5, a4, 0 # store + l32i a7, a4, 4 # same for upper address word +#endif + __sl a5, a3 + and a6, a7, a6 + or a6, a6, a5 +#ifdef UNALIGNED_USER_EXCEPTION + s32e a6, a4, -4 +#else + s32i a6, a4, 4 +#endif + + /* Done. restore stack and return */ + +.Lexit: + movi a4, 0 + rsr a3, EXCSAVE_1 + s32i a4, a3, EXC_TABLE_FIXUP + + /* Restore working register */ + + l32i a8, a2, PT_AREG8 + l32i a7, a2, PT_AREG7 + l32i a6, a2, PT_AREG6 + l32i a5, a2, PT_AREG5 + l32i a4, a2, PT_AREG4 + l32i a3, a2, PT_AREG3 + + /* restore SAR and return */ + + wsr a0, SAR + l32i a0, a2, PT_AREG0 + l32i a2, a2, PT_AREG2 + rfe + + /* We cannot handle this exception. */ + + .extern _kernel_exception +.Linvalid_instruction_store: +.Linvalid_instruction: + + /* Restore a4...a8 and SAR, set SP, and jump to default exception. */ + + l32i a8, a2, PT_AREG8 + l32i a7, a2, PT_AREG7 + l32i a6, a2, PT_AREG6 + l32i a5, a2, PT_AREG5 + l32i a4, a2, PT_AREG4 + wsr a0, SAR + mov a1, a2 + + rsr a0, PS + bbsi.l a2, PS_UM_BIT, 1f # jump if user mode + + movi a0, _kernel_exception + jx a0 + +1: movi a0, _user_exception + jx a0 + + +#endif /* XCHAL_UNALIGNED_LOAD_EXCEPTION || XCHAL_UNALIGNED_STORE_EXCEPTION */ + diff --git a/arch/xtensa/kernel/asm-offsets.c b/arch/xtensa/kernel/asm-offsets.c new file mode 100644 index 00000000..7dc3f915 --- /dev/null +++ b/arch/xtensa/kernel/asm-offsets.c @@ -0,0 +1,111 @@ +/* + * arch/xtensa/kernel/asm-offsets.c + * + * Generates definitions from c-type structures used by assembly sources. + * + * 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) 2005 Tensilica Inc. + * + * Chris Zankel <chris@zankel.net> + */ + +#include <asm/processor.h> +#include <asm/coprocessor.h> + +#include <linux/types.h> +#include <linux/stddef.h> +#include <linux/thread_info.h> +#include <linux/ptrace.h> +#include <linux/mm.h> +#include <linux/kbuild.h> + +#include <asm/ptrace.h> +#include <asm/uaccess.h> + +int main(void) +{ + /* struct pt_regs */ + DEFINE(PT_PC, offsetof (struct pt_regs, pc)); + DEFINE(PT_PS, offsetof (struct pt_regs, ps)); + DEFINE(PT_DEPC, offsetof (struct pt_regs, depc)); + DEFINE(PT_EXCCAUSE, offsetof (struct pt_regs, exccause)); + DEFINE(PT_EXCVADDR, offsetof (struct pt_regs, excvaddr)); + DEFINE(PT_DEBUGCAUSE, offsetof (struct pt_regs, debugcause)); + DEFINE(PT_WMASK, offsetof (struct pt_regs, wmask)); + DEFINE(PT_LBEG, offsetof (struct pt_regs, lbeg)); + DEFINE(PT_LEND, offsetof (struct pt_regs, lend)); + DEFINE(PT_LCOUNT, offsetof (struct pt_regs, lcount)); + DEFINE(PT_SAR, offsetof (struct pt_regs, sar)); + DEFINE(PT_ICOUNTLEVEL, offsetof (struct pt_regs, icountlevel)); + DEFINE(PT_SYSCALL, offsetof (struct pt_regs, syscall)); + DEFINE(PT_AREG, offsetof (struct pt_regs, areg[0])); + DEFINE(PT_AREG0, offsetof (struct pt_regs, areg[0])); + DEFINE(PT_AREG1, offsetof (struct pt_regs, areg[1])); + DEFINE(PT_AREG2, offsetof (struct pt_regs, areg[2])); + DEFINE(PT_AREG3, offsetof (struct pt_regs, areg[3])); + DEFINE(PT_AREG4, offsetof (struct pt_regs, areg[4])); + DEFINE(PT_AREG5, offsetof (struct pt_regs, areg[5])); + DEFINE(PT_AREG6, offsetof (struct pt_regs, areg[6])); + DEFINE(PT_AREG7, offsetof (struct pt_regs, areg[7])); + DEFINE(PT_AREG8, offsetof (struct pt_regs, areg[8])); + DEFINE(PT_AREG9, offsetof (struct pt_regs, areg[9])); + DEFINE(PT_AREG10, offsetof (struct pt_regs, areg[10])); + DEFINE(PT_AREG11, offsetof (struct pt_regs, areg[11])); + DEFINE(PT_AREG12, offsetof (struct pt_regs, areg[12])); + DEFINE(PT_AREG13, offsetof (struct pt_regs, areg[13])); + DEFINE(PT_AREG14, offsetof (struct pt_regs, areg[14])); + DEFINE(PT_AREG15, offsetof (struct pt_regs, areg[15])); + DEFINE(PT_WINDOWBASE, offsetof (struct pt_regs, windowbase)); + DEFINE(PT_WINDOWSTART, offsetof(struct pt_regs, windowstart)); + DEFINE(PT_SIZE, sizeof(struct pt_regs)); + DEFINE(PT_AREG_END, offsetof (struct pt_regs, areg[XCHAL_NUM_AREGS])); + DEFINE(PT_USER_SIZE, offsetof(struct pt_regs, areg[XCHAL_NUM_AREGS])); + DEFINE(PT_XTREGS_OPT, offsetof(struct pt_regs, xtregs_opt)); + DEFINE(XTREGS_OPT_SIZE, sizeof(xtregs_opt_t)); + + /* struct task_struct */ + DEFINE(TASK_PTRACE, offsetof (struct task_struct, ptrace)); + DEFINE(TASK_MM, offsetof (struct task_struct, mm)); + DEFINE(TASK_ACTIVE_MM, offsetof (struct task_struct, active_mm)); + DEFINE(TASK_PID, offsetof (struct task_struct, pid)); + DEFINE(TASK_THREAD, offsetof (struct task_struct, thread)); + DEFINE(TASK_THREAD_INFO, offsetof (struct task_struct, stack)); + DEFINE(TASK_STRUCT_SIZE, sizeof (struct task_struct)); + + /* struct thread_info (offset from start_struct) */ + DEFINE(THREAD_RA, offsetof (struct task_struct, thread.ra)); + DEFINE(THREAD_SP, offsetof (struct task_struct, thread.sp)); + DEFINE(THREAD_CPENABLE, offsetof (struct thread_info, cpenable)); +#if XTENSA_HAVE_COPROCESSORS + DEFINE(THREAD_XTREGS_CP0, offsetof (struct thread_info, xtregs_cp)); + DEFINE(THREAD_XTREGS_CP1, offsetof (struct thread_info, xtregs_cp)); + DEFINE(THREAD_XTREGS_CP2, offsetof (struct thread_info, xtregs_cp)); + DEFINE(THREAD_XTREGS_CP3, offsetof (struct thread_info, xtregs_cp)); + DEFINE(THREAD_XTREGS_CP4, offsetof (struct thread_info, xtregs_cp)); + DEFINE(THREAD_XTREGS_CP5, offsetof (struct thread_info, xtregs_cp)); + DEFINE(THREAD_XTREGS_CP6, offsetof (struct thread_info, xtregs_cp)); + DEFINE(THREAD_XTREGS_CP7, offsetof (struct thread_info, xtregs_cp)); +#endif + DEFINE(THREAD_XTREGS_USER, offsetof (struct thread_info, xtregs_user)); + DEFINE(XTREGS_USER_SIZE, sizeof(xtregs_user_t)); + DEFINE(THREAD_CURRENT_DS, offsetof (struct task_struct, thread.current_ds)); + + /* struct mm_struct */ + DEFINE(MM_USERS, offsetof(struct mm_struct, mm_users)); + DEFINE(MM_PGD, offsetof (struct mm_struct, pgd)); + DEFINE(MM_CONTEXT, offsetof (struct mm_struct, context)); + + /* struct page */ + DEFINE(PAGE_FLAGS, offsetof(struct page, flags)); + + /* constants */ + DEFINE(_CLONE_VM, CLONE_VM); + DEFINE(_CLONE_UNTRACED, CLONE_UNTRACED); + DEFINE(PG_ARCH_1, PG_arch_1); + + return 0; +} + diff --git a/arch/xtensa/kernel/coprocessor.S b/arch/xtensa/kernel/coprocessor.S new file mode 100644 index 00000000..2bc1e145 --- /dev/null +++ b/arch/xtensa/kernel/coprocessor.S @@ -0,0 +1,335 @@ +/* + * arch/xtensa/kernel/coprocessor.S + * + * Xtensa processor configuration-specific table of coprocessor and + * other custom register layout information. + * + * 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) 2003 - 2007 Tensilica Inc. + */ + + +#include <linux/linkage.h> +#include <asm/asm-offsets.h> +#include <asm/processor.h> +#include <asm/coprocessor.h> +#include <asm/thread_info.h> +#include <asm/uaccess.h> +#include <asm/unistd.h> +#include <asm/ptrace.h> +#include <asm/current.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/signal.h> +#include <asm/tlbflush.h> + +/* + * Entry condition: + * + * a0: trashed, original value saved on stack (PT_AREG0) + * a1: a1 + * a2: new stack pointer, original in DEPC + * a3: dispatch table + * depc: a2, original value saved on stack (PT_DEPC) + * excsave_1: a3 + * + * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC + * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception + */ + +/* IO protection is currently unsupported. */ + +ENTRY(fast_io_protect) + wsr a0, EXCSAVE_1 + movi a0, unrecoverable_exception + callx0 a0 + +#if XTENSA_HAVE_COPROCESSORS + +/* + * Macros for lazy context switch. + */ + +#define SAVE_CP_REGS(x) \ + .align 4; \ + .Lsave_cp_regs_cp##x: \ + .if XTENSA_HAVE_COPROCESSOR(x); \ + xchal_cp##x##_store a2 a4 a5 a6 a7; \ + .endif; \ + jx a0 + +#define SAVE_CP_REGS_TAB(x) \ + .if XTENSA_HAVE_COPROCESSOR(x); \ + .long .Lsave_cp_regs_cp##x - .Lsave_cp_regs_jump_table; \ + .else; \ + .long 0; \ + .endif; \ + .long THREAD_XTREGS_CP##x + + +#define LOAD_CP_REGS(x) \ + .align 4; \ + .Lload_cp_regs_cp##x: \ + .if XTENSA_HAVE_COPROCESSOR(x); \ + xchal_cp##x##_load a2 a4 a5 a6 a7; \ + .endif; \ + jx a0 + +#define LOAD_CP_REGS_TAB(x) \ + .if XTENSA_HAVE_COPROCESSOR(x); \ + .long .Lload_cp_regs_cp##x - .Lload_cp_regs_jump_table; \ + .else; \ + .long 0; \ + .endif; \ + .long THREAD_XTREGS_CP##x + + SAVE_CP_REGS(0) + SAVE_CP_REGS(1) + SAVE_CP_REGS(2) + SAVE_CP_REGS(3) + SAVE_CP_REGS(4) + SAVE_CP_REGS(5) + SAVE_CP_REGS(6) + SAVE_CP_REGS(7) + + LOAD_CP_REGS(0) + LOAD_CP_REGS(1) + LOAD_CP_REGS(2) + LOAD_CP_REGS(3) + LOAD_CP_REGS(4) + LOAD_CP_REGS(5) + LOAD_CP_REGS(6) + LOAD_CP_REGS(7) + + .align 4 +.Lsave_cp_regs_jump_table: + SAVE_CP_REGS_TAB(0) + SAVE_CP_REGS_TAB(1) + SAVE_CP_REGS_TAB(2) + SAVE_CP_REGS_TAB(3) + SAVE_CP_REGS_TAB(4) + SAVE_CP_REGS_TAB(5) + SAVE_CP_REGS_TAB(6) + SAVE_CP_REGS_TAB(7) + +.Lload_cp_regs_jump_table: + LOAD_CP_REGS_TAB(0) + LOAD_CP_REGS_TAB(1) + LOAD_CP_REGS_TAB(2) + LOAD_CP_REGS_TAB(3) + LOAD_CP_REGS_TAB(4) + LOAD_CP_REGS_TAB(5) + LOAD_CP_REGS_TAB(6) + LOAD_CP_REGS_TAB(7) + +/* + * coprocessor_save(buffer, index) + * a2 a3 + * coprocessor_load(buffer, index) + * a2 a3 + * + * Save or load coprocessor registers for coprocessor 'index'. + * The register values are saved to or loaded from them 'buffer' address. + * + * Note that these functions don't update the coprocessor_owner information! + * + */ + +ENTRY(coprocessor_save) + entry a1, 32 + s32i a0, a1, 0 + movi a0, .Lsave_cp_regs_jump_table + addx8 a3, a3, a0 + l32i a3, a3, 0 + beqz a3, 1f + add a0, a0, a3 + callx0 a0 +1: l32i a0, a1, 0 + retw + +ENTRY(coprocessor_load) + entry a1, 32 + s32i a0, a1, 0 + movi a0, .Lload_cp_regs_jump_table + addx4 a3, a3, a0 + l32i a3, a3, 0 + beqz a3, 1f + add a0, a0, a3 + callx0 a0 +1: l32i a0, a1, 0 + retw + +/* + * coprocessor_flush(struct task_info*, index) + * a2 a3 + * coprocessor_restore(struct task_info*, index) + * a2 a3 + * + * Save or load coprocessor registers for coprocessor 'index'. + * The register values are saved to or loaded from the coprocessor area + * inside the task_info structure. + * + * Note that these functions don't update the coprocessor_owner information! + * + */ + + +ENTRY(coprocessor_flush) + entry a1, 32 + s32i a0, a1, 0 + movi a0, .Lsave_cp_regs_jump_table + addx8 a3, a3, a0 + l32i a4, a3, 4 + l32i a3, a3, 0 + add a2, a2, a4 + beqz a3, 1f + add a0, a0, a3 + callx0 a0 +1: l32i a0, a1, 0 + retw + +ENTRY(coprocessor_restore) + entry a1, 32 + s32i a0, a1, 0 + movi a0, .Lload_cp_regs_jump_table + addx4 a3, a3, a0 + l32i a4, a3, 4 + l32i a3, a3, 0 + add a2, a2, a4 + beqz a3, 1f + add a0, a0, a3 + callx0 a0 +1: l32i a0, a1, 0 + retw + +/* + * Entry condition: + * + * a0: trashed, original value saved on stack (PT_AREG0) + * a1: a1 + * a2: new stack pointer, original in DEPC + * a3: dispatch table + * depc: a2, original value saved on stack (PT_DEPC) + * excsave_1: a3 + * + * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC + * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception + */ + +ENTRY(fast_coprocessor_double) + wsr a0, EXCSAVE_1 + movi a0, unrecoverable_exception + callx0 a0 + + +ENTRY(fast_coprocessor) + + /* Save remaining registers a1-a3 and SAR */ + + xsr a3, EXCSAVE_1 + s32i a3, a2, PT_AREG3 + rsr a3, SAR + s32i a1, a2, PT_AREG1 + s32i a3, a2, PT_SAR + mov a1, a2 + rsr a2, DEPC + s32i a2, a1, PT_AREG2 + + /* + * The hal macros require up to 4 temporary registers. We use a3..a6. + */ + + s32i a4, a1, PT_AREG4 + s32i a5, a1, PT_AREG5 + s32i a6, a1, PT_AREG6 + + /* Find coprocessor number. Subtract first CP EXCCAUSE from EXCCAUSE */ + + rsr a3, EXCCAUSE + addi a3, a3, -EXCCAUSE_COPROCESSOR0_DISABLED + + /* Set corresponding CPENABLE bit -> (sar:cp-index, a3: 1<<cp-index)*/ + + ssl a3 # SAR: 32 - coprocessor_number + movi a2, 1 + rsr a0, CPENABLE + sll a2, a2 + or a0, a0, a2 + wsr a0, CPENABLE + rsync + + /* Retrieve previous owner. (a3 still holds CP number) */ + + movi a0, coprocessor_owner # list of owners + addx4 a0, a3, a0 # entry for CP + l32i a4, a0, 0 + + beqz a4, 1f # skip 'save' if no previous owner + + /* Disable coprocessor for previous owner. (a2 = 1 << CP number) */ + + l32i a5, a4, THREAD_CPENABLE + xor a5, a5, a2 # (1 << cp-id) still in a2 + s32i a5, a4, THREAD_CPENABLE + + /* + * Get context save area and 'call' save routine. + * (a4 still holds previous owner (thread_info), a3 CP number) + */ + + movi a5, .Lsave_cp_regs_jump_table + movi a0, 2f # a0: 'return' address + addx8 a3, a3, a5 # a3: coprocessor number + l32i a2, a3, 4 # a2: xtregs offset + l32i a3, a3, 0 # a3: jump offset + add a2, a2, a4 + add a4, a3, a5 # a4: address of save routine + jx a4 + + /* Note that only a0 and a1 were preserved. */ + +2: rsr a3, EXCCAUSE + addi a3, a3, -EXCCAUSE_COPROCESSOR0_DISABLED + movi a0, coprocessor_owner + addx4 a0, a3, a0 + + /* Set new 'owner' (a0 points to the CP owner, a3 contains the CP nr) */ + +1: GET_THREAD_INFO (a4, a1) + s32i a4, a0, 0 + + /* Get context save area and 'call' load routine. */ + + movi a5, .Lload_cp_regs_jump_table + movi a0, 1f + addx8 a3, a3, a5 + l32i a2, a3, 4 # a2: xtregs offset + l32i a3, a3, 0 # a3: jump offset + add a2, a2, a4 + add a4, a3, a5 + jx a4 + + /* Restore all registers and return from exception handler. */ + +1: l32i a6, a1, PT_AREG6 + l32i a5, a1, PT_AREG5 + l32i a4, a1, PT_AREG4 + + l32i a0, a1, PT_SAR + l32i a3, a1, PT_AREG3 + l32i a2, a1, PT_AREG2 + wsr a0, SAR + l32i a0, a1, PT_AREG0 + l32i a1, a1, PT_AREG1 + + rfe + + .data +ENTRY(coprocessor_owner) + .fill XCHAL_CP_MAX, 4, 0 + +#endif /* XTENSA_HAVE_COPROCESSORS */ + diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S new file mode 100644 index 00000000..6223f334 --- /dev/null +++ b/arch/xtensa/kernel/entry.S @@ -0,0 +1,1960 @@ +/* + * arch/xtensa/kernel/entry.S + * + * Low-level exception handling + * + * 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) 2004-2007 by Tensilica Inc. + * + * Chris Zankel <chris@zankel.net> + * + */ + +#include <linux/linkage.h> +#include <asm/asm-offsets.h> +#include <asm/processor.h> +#include <asm/coprocessor.h> +#include <asm/thread_info.h> +#include <asm/uaccess.h> +#include <asm/unistd.h> +#include <asm/ptrace.h> +#include <asm/current.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/signal.h> +#include <asm/tlbflush.h> +#include <variant/tie-asm.h> + +/* Unimplemented features. */ + +#undef KERNEL_STACK_OVERFLOW_CHECK +#undef PREEMPTIBLE_KERNEL +#undef ALLOCA_EXCEPTION_IN_IRAM + +/* Not well tested. + * + * - fast_coprocessor + */ + +/* + * Macro to find first bit set in WINDOWBASE from the left + 1 + * + * 100....0 -> 1 + * 010....0 -> 2 + * 000....1 -> WSBITS + */ + + .macro ffs_ws bit mask + +#if XCHAL_HAVE_NSA + nsau \bit, \mask # 32-WSBITS ... 31 (32 iff 0) + addi \bit, \bit, WSBITS - 32 + 1 # uppest bit set -> return 1 +#else + movi \bit, WSBITS +#if WSBITS > 16 + _bltui \mask, 0x10000, 99f + addi \bit, \bit, -16 + extui \mask, \mask, 16, 16 +#endif +#if WSBITS > 8 +99: _bltui \mask, 0x100, 99f + addi \bit, \bit, -8 + srli \mask, \mask, 8 +#endif +99: _bltui \mask, 0x10, 99f + addi \bit, \bit, -4 + srli \mask, \mask, 4 +99: _bltui \mask, 0x4, 99f + addi \bit, \bit, -2 + srli \mask, \mask, 2 +99: _bltui \mask, 0x2, 99f + addi \bit, \bit, -1 +99: + +#endif + .endm + +/* ----------------- DEFAULT FIRST LEVEL EXCEPTION HANDLERS ----------------- */ + +/* + * First-level exception handler for user exceptions. + * Save some special registers, extra states and all registers in the AR + * register file that were in use in the user task, and jump to the common + * exception code. + * We save SAR (used to calculate WMASK), and WB and WS (we don't have to + * save them for kernel exceptions). + * + * Entry condition for user_exception: + * + * a0: trashed, original value saved on stack (PT_AREG0) + * a1: a1 + * a2: new stack pointer, original value in depc + * a3: dispatch table + * depc: a2, original value saved on stack (PT_DEPC) + * excsave1: a3 + * + * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC + * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception + * + * Entry condition for _user_exception: + * + * a0-a3 and depc have been saved to PT_AREG0...PT_AREG3 and PT_DEPC + * excsave has been restored, and + * stack pointer (a1) has been set. + * + * Note: _user_exception might be at an odd address. Don't use call0..call12 + */ + +ENTRY(user_exception) + + /* Save a2, a3, and depc, restore excsave_1 and set SP. */ + + xsr a3, EXCSAVE_1 + rsr a0, DEPC + s32i a1, a2, PT_AREG1 + s32i a0, a2, PT_AREG2 + s32i a3, a2, PT_AREG3 + mov a1, a2 + + .globl _user_exception +_user_exception: + + /* Save SAR and turn off single stepping */ + + movi a2, 0 + rsr a3, SAR + xsr a2, ICOUNTLEVEL + s32i a3, a1, PT_SAR + s32i a2, a1, PT_ICOUNTLEVEL + + /* Rotate ws so that the current windowbase is at bit0. */ + /* Assume ws = xxwww1yyyy. Rotate ws right, so that a2 = yyyyxxwww1 */ + + rsr a2, WINDOWBASE + rsr a3, WINDOWSTART + ssr a2 + s32i a2, a1, PT_WINDOWBASE + s32i a3, a1, PT_WINDOWSTART + slli a2, a3, 32-WSBITS + src a2, a3, a2 + srli a2, a2, 32-WSBITS + s32i a2, a1, PT_WMASK # needed for restoring registers + + /* Save only live registers. */ + + _bbsi.l a2, 1, 1f + s32i a4, a1, PT_AREG4 + s32i a5, a1, PT_AREG5 + s32i a6, a1, PT_AREG6 + s32i a7, a1, PT_AREG7 + _bbsi.l a2, 2, 1f + s32i a8, a1, PT_AREG8 + s32i a9, a1, PT_AREG9 + s32i a10, a1, PT_AREG10 + s32i a11, a1, PT_AREG11 + _bbsi.l a2, 3, 1f + s32i a12, a1, PT_AREG12 + s32i a13, a1, PT_AREG13 + s32i a14, a1, PT_AREG14 + s32i a15, a1, PT_AREG15 + _bnei a2, 1, 1f # only one valid frame? + + /* Only one valid frame, skip saving regs. */ + + j 2f + + /* Save the remaining registers. + * We have to save all registers up to the first '1' from + * the right, except the current frame (bit 0). + * Assume a2 is: 001001000110001 + * All register frames starting from the top field to the marked '1' + * must be saved. + */ + +1: addi a3, a2, -1 # eliminate '1' in bit 0: yyyyxxww0 + neg a3, a3 # yyyyxxww0 -> YYYYXXWW1+1 + and a3, a3, a2 # max. only one bit is set + + /* Find number of frames to save */ + + ffs_ws a0, a3 # number of frames to the '1' from left + + /* Store information into WMASK: + * bits 0..3: xxx1 masked lower 4 bits of the rotated windowstart, + * bits 4...: number of valid 4-register frames + */ + + slli a3, a0, 4 # number of frames to save in bits 8..4 + extui a2, a2, 0, 4 # mask for the first 16 registers + or a2, a3, a2 + s32i a2, a1, PT_WMASK # needed when we restore the reg-file + + /* Save 4 registers at a time */ + +1: rotw -1 + s32i a0, a5, PT_AREG_END - 16 + s32i a1, a5, PT_AREG_END - 12 + s32i a2, a5, PT_AREG_END - 8 + s32i a3, a5, PT_AREG_END - 4 + addi a0, a4, -1 + addi a1, a5, -16 + _bnez a0, 1b + + /* WINDOWBASE still in SAR! */ + + rsr a2, SAR # original WINDOWBASE + movi a3, 1 + ssl a2 + sll a3, a3 + wsr a3, WINDOWSTART # set corresponding WINDOWSTART bit + wsr a2, WINDOWBASE # and WINDOWSTART + rsync + + /* We are back to the original stack pointer (a1) */ + +2: /* Now, jump to the common exception handler. */ + + j common_exception + + +/* + * First-level exit handler for kernel exceptions + * Save special registers and the live window frame. + * Note: Even though we changes the stack pointer, we don't have to do a + * MOVSP here, as we do that when we return from the exception. + * (See comment in the kernel exception exit code) + * + * Entry condition for kernel_exception: + * + * a0: trashed, original value saved on stack (PT_AREG0) + * a1: a1 + * a2: new stack pointer, original in DEPC + * a3: dispatch table + * depc: a2, original value saved on stack (PT_DEPC) + * excsave_1: a3 + * + * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC + * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception + * + * Entry condition for _kernel_exception: + * + * a0-a3 and depc have been saved to PT_AREG0...PT_AREG3 and PT_DEPC + * excsave has been restored, and + * stack pointer (a1) has been set. + * + * Note: _kernel_exception might be at an odd address. Don't use call0..call12 + */ + +ENTRY(kernel_exception) + + /* Save a0, a2, a3, DEPC and set SP. */ + + xsr a3, EXCSAVE_1 # restore a3, excsave_1 + rsr a0, DEPC # get a2 + s32i a1, a2, PT_AREG1 + s32i a0, a2, PT_AREG2 + s32i a3, a2, PT_AREG3 + mov a1, a2 + + .globl _kernel_exception +_kernel_exception: + + /* Save SAR and turn off single stepping */ + + movi a2, 0 + rsr a3, SAR + xsr a2, ICOUNTLEVEL + s32i a3, a1, PT_SAR + s32i a2, a1, PT_ICOUNTLEVEL + + /* Rotate ws so that the current windowbase is at bit0. */ + /* Assume ws = xxwww1yyyy. Rotate ws right, so that a2 = yyyyxxwww1 */ + + rsr a2, WINDOWBASE # don't need to save these, we only + rsr a3, WINDOWSTART # need shifted windowstart: windowmask + ssr a2 + slli a2, a3, 32-WSBITS + src a2, a3, a2 + srli a2, a2, 32-WSBITS + s32i a2, a1, PT_WMASK # needed for kernel_exception_exit + + /* Save only the live window-frame */ + + _bbsi.l a2, 1, 1f + s32i a4, a1, PT_AREG4 + s32i a5, a1, PT_AREG5 + s32i a6, a1, PT_AREG6 + s32i a7, a1, PT_AREG7 + _bbsi.l a2, 2, 1f + s32i a8, a1, PT_AREG8 + s32i a9, a1, PT_AREG9 + s32i a10, a1, PT_AREG10 + s32i a11, a1, PT_AREG11 + _bbsi.l a2, 3, 1f + s32i a12, a1, PT_AREG12 + s32i a13, a1, PT_AREG13 + s32i a14, a1, PT_AREG14 + s32i a15, a1, PT_AREG15 + +1: + +#ifdef KERNEL_STACK_OVERFLOW_CHECK + + /* Stack overflow check, for debugging */ + extui a2, a1, TASK_SIZE_BITS,XX + movi a3, SIZE?? + _bge a2, a3, out_of_stack_panic + +#endif + +/* + * This is the common exception handler. + * We get here from the user exception handler or simply by falling through + * from the kernel exception handler. + * Save the remaining special registers, switch to kernel mode, and jump + * to the second-level exception handler. + * + */ + +common_exception: + + /* Save some registers, disable loops and clear the syscall flag. */ + + rsr a2, DEBUGCAUSE + rsr a3, EPC_1 + s32i a2, a1, PT_DEBUGCAUSE + s32i a3, a1, PT_PC + + movi a2, -1 + rsr a3, EXCVADDR + s32i a2, a1, PT_SYSCALL + movi a2, 0 + s32i a3, a1, PT_EXCVADDR + xsr a2, LCOUNT + s32i a2, a1, PT_LCOUNT + + /* It is now save to restore the EXC_TABLE_FIXUP variable. */ + + rsr a0, EXCCAUSE + movi a3, 0 + rsr a2, EXCSAVE_1 + s32i a0, a1, PT_EXCCAUSE + s32i a3, a2, EXC_TABLE_FIXUP + + /* All unrecoverable states are saved on stack, now, and a1 is valid, + * so we can allow exceptions and interrupts (*) again. + * Set PS(EXCM = 0, UM = 0, RING = 0, OWB = 0, WOE = 1, INTLEVEL = X) + * + * (*) We only allow interrupts if PS.INTLEVEL was not set to 1 before + * (interrupts disabled) and if this exception is not an interrupt. + */ + + rsr a3, PS + addi a0, a0, -4 + movi a2, 1 + extui a3, a3, 0, 1 # a3 = PS.INTLEVEL[0] + moveqz a3, a2, a0 # a3 = 1 iff interrupt exception + movi a2, 1 << PS_WOE_BIT + or a3, a3, a2 + rsr a0, EXCCAUSE + xsr a3, PS + + s32i a3, a1, PT_PS # save ps + + /* Save LBEG, LEND */ + + rsr a2, LBEG + rsr a3, LEND + s32i a2, a1, PT_LBEG + s32i a3, a1, PT_LEND + + /* Save optional registers. */ + + save_xtregs_opt a1 a2 a4 a5 a6 a7 PT_XTREGS_OPT + + /* Go to second-level dispatcher. Set up parameters to pass to the + * exception handler and call the exception handler. + */ + + movi a4, exc_table + mov a6, a1 # pass stack frame + mov a7, a0 # pass EXCCAUSE + addx4 a4, a0, a4 + l32i a4, a4, EXC_TABLE_DEFAULT # load handler + + /* Call the second-level handler */ + + callx4 a4 + + /* Jump here for exception exit */ + +common_exception_return: + + /* Jump if we are returning from kernel exceptions. */ + +1: l32i a3, a1, PT_PS + _bbci.l a3, PS_UM_BIT, 4f + + /* Specific to a user exception exit: + * We need to check some flags for signal handling and rescheduling, + * and have to restore WB and WS, extra states, and all registers + * in the register file that were in use in the user task. + * Note that we don't disable interrupts here. + */ + + GET_THREAD_INFO(a2,a1) + l32i a4, a2, TI_FLAGS + + _bbsi.l a4, TIF_NEED_RESCHED, 3f + _bbci.l a4, TIF_SIGPENDING, 4f + + l32i a4, a1, PT_DEPC + bgeui a4, VALID_DOUBLE_EXCEPTION_ADDRESS, 4f + + /* Call do_signal() */ + + movi a4, do_signal # int do_signal(struct pt_regs*, sigset_t*) + mov a6, a1 + movi a7, 0 + callx4 a4 + j 1b + +3: /* Reschedule */ + + movi a4, schedule # void schedule (void) + callx4 a4 + j 1b + +4: /* Restore optional registers. */ + + load_xtregs_opt a1 a2 a4 a5 a6 a7 PT_XTREGS_OPT + + wsr a3, PS /* disable interrupts */ + + _bbci.l a3, PS_UM_BIT, kernel_exception_exit + +user_exception_exit: + + /* Restore the state of the task and return from the exception. */ + + /* Switch to the user thread WINDOWBASE. Save SP temporarily in DEPC */ + + l32i a2, a1, PT_WINDOWBASE + l32i a3, a1, PT_WINDOWSTART + wsr a1, DEPC # use DEPC as temp storage + wsr a3, WINDOWSTART # restore WINDOWSTART + ssr a2 # preserve user's WB in the SAR + wsr a2, WINDOWBASE # switch to user's saved WB + rsync + rsr a1, DEPC # restore stack pointer + l32i a2, a1, PT_WMASK # register frames saved (in bits 4...9) + rotw -1 # we restore a4..a7 + _bltui a6, 16, 1f # only have to restore current window? + + /* The working registers are a0 and a3. We are restoring to + * a4..a7. Be careful not to destroy what we have just restored. + * Note: wmask has the format YYYYM: + * Y: number of registers saved in groups of 4 + * M: 4 bit mask of first 16 registers + */ + + mov a2, a6 + mov a3, a5 + +2: rotw -1 # a0..a3 become a4..a7 + addi a3, a7, -4*4 # next iteration + addi a2, a6, -16 # decrementing Y in WMASK + l32i a4, a3, PT_AREG_END + 0 + l32i a5, a3, PT_AREG_END + 4 + l32i a6, a3, PT_AREG_END + 8 + l32i a7, a3, PT_AREG_END + 12 + _bgeui a2, 16, 2b + + /* Clear unrestored registers (don't leak anything to user-land */ + +1: rsr a0, WINDOWBASE + rsr a3, SAR + sub a3, a0, a3 + beqz a3, 2f + extui a3, a3, 0, WBBITS + +1: rotw -1 + addi a3, a7, -1 + movi a4, 0 + movi a5, 0 + movi a6, 0 + movi a7, 0 + bgei a3, 1, 1b + + /* We are back were we were when we started. + * Note: a2 still contains WMASK (if we've returned to the original + * frame where we had loaded a2), or at least the lower 4 bits + * (if we have restored WSBITS-1 frames). + */ + +2: j common_exception_exit + + /* This is the kernel exception exit. + * We avoided to do a MOVSP when we entered the exception, but we + * have to do it here. + */ + +kernel_exception_exit: + +#ifdef PREEMPTIBLE_KERNEL + +#ifdef CONFIG_PREEMPT + + /* + * Note: We've just returned from a call4, so we have + * at least 4 addt'l regs. + */ + + /* Check current_thread_info->preempt_count */ + + GET_THREAD_INFO(a2) + l32i a3, a2, TI_PREEMPT + bnez a3, 1f + + l32i a2, a2, TI_FLAGS + +1: + +#endif + +#endif + + /* Check if we have to do a movsp. + * + * We only have to do a movsp if the previous window-frame has + * been spilled to the *temporary* exception stack instead of the + * task's stack. This is the case if the corresponding bit in + * WINDOWSTART for the previous window-frame was set before + * (not spilled) but is zero now (spilled). + * If this bit is zero, all other bits except the one for the + * current window frame are also zero. So, we can use a simple test: + * 'and' WINDOWSTART and WINDOWSTART-1: + * + * (XXXXXX1[0]* - 1) AND XXXXXX1[0]* = XXXXXX0[0]* + * + * The result is zero only if one bit was set. + * + * (Note: We might have gone through several task switches before + * we come back to the current task, so WINDOWBASE might be + * different from the time the exception occurred.) + */ + + /* Test WINDOWSTART before and after the exception. + * We actually have WMASK, so we only have to test if it is 1 or not. + */ + + l32i a2, a1, PT_WMASK + _beqi a2, 1, common_exception_exit # Spilled before exception,jump + + /* Test WINDOWSTART now. If spilled, do the movsp */ + + rsr a3, WINDOWSTART + addi a0, a3, -1 + and a3, a3, a0 + _bnez a3, common_exception_exit + + /* Do a movsp (we returned from a call4, so we have at least a0..a7) */ + + addi a0, a1, -16 + l32i a3, a0, 0 + l32i a4, a0, 4 + s32i a3, a1, PT_SIZE+0 + s32i a4, a1, PT_SIZE+4 + l32i a3, a0, 8 + l32i a4, a0, 12 + s32i a3, a1, PT_SIZE+8 + s32i a4, a1, PT_SIZE+12 + + /* Common exception exit. + * We restore the special register and the current window frame, and + * return from the exception. + * + * Note: We expect a2 to hold PT_WMASK + */ + +common_exception_exit: + + /* Restore address registers. */ + + _bbsi.l a2, 1, 1f + l32i a4, a1, PT_AREG4 + l32i a5, a1, PT_AREG5 + l32i a6, a1, PT_AREG6 + l32i a7, a1, PT_AREG7 + _bbsi.l a2, 2, 1f + l32i a8, a1, PT_AREG8 + l32i a9, a1, PT_AREG9 + l32i a10, a1, PT_AREG10 + l32i a11, a1, PT_AREG11 + _bbsi.l a2, 3, 1f + l32i a12, a1, PT_AREG12 + l32i a13, a1, PT_AREG13 + l32i a14, a1, PT_AREG14 + l32i a15, a1, PT_AREG15 + + /* Restore PC, SAR */ + +1: l32i a2, a1, PT_PC + l32i a3, a1, PT_SAR + wsr a2, EPC_1 + wsr a3, SAR + + /* Restore LBEG, LEND, LCOUNT */ + + l32i a2, a1, PT_LBEG + l32i a3, a1, PT_LEND + wsr a2, LBEG + l32i a2, a1, PT_LCOUNT + wsr a3, LEND + wsr a2, LCOUNT + + /* We control single stepping through the ICOUNTLEVEL register. */ + + l32i a2, a1, PT_ICOUNTLEVEL + movi a3, -2 + wsr a2, ICOUNTLEVEL + wsr a3, ICOUNT + + /* Check if it was double exception. */ + + l32i a0, a1, PT_DEPC + l32i a3, a1, PT_AREG3 + l32i a2, a1, PT_AREG2 + _bgeui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f + + /* Restore a0...a3 and return */ + + l32i a0, a1, PT_AREG0 + l32i a1, a1, PT_AREG1 + rfe + +1: wsr a0, DEPC + l32i a0, a1, PT_AREG0 + l32i a1, a1, PT_AREG1 + rfde + +/* + * Debug exception handler. + * + * Currently, we don't support KGDB, so only user application can be debugged. + * + * When we get here, a0 is trashed and saved to excsave[debuglevel] + */ + +ENTRY(debug_exception) + + rsr a0, EPS + XCHAL_DEBUGLEVEL + bbsi.l a0, PS_EXCM_BIT, 1f # exception mode + + /* Set EPC_1 and EXCCAUSE */ + + wsr a2, DEPC # save a2 temporarily + rsr a2, EPC + XCHAL_DEBUGLEVEL + wsr a2, EPC_1 + + movi a2, EXCCAUSE_MAPPED_DEBUG + wsr a2, EXCCAUSE + + /* Restore PS to the value before the debug exc but with PS.EXCM set.*/ + + movi a2, 1 << PS_EXCM_BIT + or a2, a0, a2 + movi a0, debug_exception # restore a3, debug jump vector + wsr a2, PS + xsr a0, EXCSAVE + XCHAL_DEBUGLEVEL + + /* Switch to kernel/user stack, restore jump vector, and save a0 */ + + bbsi.l a2, PS_UM_BIT, 2f # jump if user mode + + addi a2, a1, -16-PT_SIZE # assume kernel stack + s32i a0, a2, PT_AREG0 + movi a0, 0 + s32i a1, a2, PT_AREG1 + s32i a0, a2, PT_DEPC # mark it as a regular exception + xsr a0, DEPC + s32i a3, a2, PT_AREG3 + s32i a0, a2, PT_AREG2 + mov a1, a2 + j _kernel_exception + +2: rsr a2, EXCSAVE_1 + l32i a2, a2, EXC_TABLE_KSTK # load kernel stack pointer + s32i a0, a2, PT_AREG0 + movi a0, 0 + s32i a1, a2, PT_AREG1 + s32i a0, a2, PT_DEPC + xsr a0, DEPC + s32i a3, a2, PT_AREG3 + s32i a0, a2, PT_AREG2 + mov a1, a2 + j _user_exception + + /* Debug exception while in exception mode. */ +1: j 1b // FIXME!! + + +/* + * We get here in case of an unrecoverable exception. + * The only thing we can do is to be nice and print a panic message. + * We only produce a single stack frame for panic, so ??? + * + * + * Entry conditions: + * + * - a0 contains the caller address; original value saved in excsave1. + * - the original a0 contains a valid return address (backtrace) or 0. + * - a2 contains a valid stackpointer + * + * Notes: + * + * - If the stack pointer could be invalid, the caller has to setup a + * dummy stack pointer (e.g. the stack of the init_task) + * + * - If the return address could be invalid, the caller has to set it + * to 0, so the backtrace would stop. + * + */ + .align 4 +unrecoverable_text: + .ascii "Unrecoverable error in exception handler\0" + +ENTRY(unrecoverable_exception) + + movi a0, 1 + movi a1, 0 + + wsr a0, WINDOWSTART + wsr a1, WINDOWBASE + rsync + + movi a1, (1 << PS_WOE_BIT) | 1 + wsr a1, PS + rsync + + movi a1, init_task + movi a0, 0 + addi a1, a1, PT_REGS_OFFSET + + movi a4, panic + movi a6, unrecoverable_text + + callx4 a4 + +1: j 1b + + +/* -------------------------- FAST EXCEPTION HANDLERS ----------------------- */ + +/* + * Fast-handler for alloca exceptions + * + * The ALLOCA handler is entered when user code executes the MOVSP + * instruction and the caller's frame is not in the register file. + * In this case, the caller frame's a0..a3 are on the stack just + * below sp (a1), and this handler moves them. + * + * For "MOVSP <ar>,<as>" without destination register a1, this routine + * simply moves the value from <as> to <ar> without moving the save area. + * + * Entry condition: + * + * a0: trashed, original value saved on stack (PT_AREG0) + * a1: a1 + * a2: new stack pointer, original in DEPC + * a3: dispatch table + * depc: a2, original value saved on stack (PT_DEPC) + * excsave_1: a3 + * + * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC + * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception + */ + +#if XCHAL_HAVE_BE +#define _EXTUI_MOVSP_SRC(ar) extui ar, ar, 4, 4 +#define _EXTUI_MOVSP_DST(ar) extui ar, ar, 0, 4 +#else +#define _EXTUI_MOVSP_SRC(ar) extui ar, ar, 0, 4 +#define _EXTUI_MOVSP_DST(ar) extui ar, ar, 4, 4 +#endif + +ENTRY(fast_alloca) + + /* We shouldn't be in a double exception. */ + + l32i a0, a2, PT_DEPC + _bgeui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, .Lunhandled_double + + rsr a0, DEPC # get a2 + s32i a4, a2, PT_AREG4 # save a4 and + s32i a0, a2, PT_AREG2 # a2 to stack + + /* Exit critical section. */ + + movi a0, 0 + s32i a0, a3, EXC_TABLE_FIXUP + + /* Restore a3, excsave_1 */ + + xsr a3, EXCSAVE_1 # make sure excsave_1 is valid for dbl. + rsr a4, EPC_1 # get exception address + s32i a3, a2, PT_AREG3 # save a3 to stack + +#ifdef ALLOCA_EXCEPTION_IN_IRAM +#error iram not supported +#else + /* Note: l8ui not allowed in IRAM/IROM!! */ + l8ui a0, a4, 1 # read as(src) from MOVSP instruction +#endif + movi a3, .Lmovsp_src + _EXTUI_MOVSP_SRC(a0) # extract source register number + addx8 a3, a0, a3 + jx a3 + +.Lunhandled_double: + wsr a0, EXCSAVE_1 + movi a0, unrecoverable_exception + callx0 a0 + + .align 8 +.Lmovsp_src: + l32i a3, a2, PT_AREG0; _j 1f; .align 8 + mov a3, a1; _j 1f; .align 8 + l32i a3, a2, PT_AREG2; _j 1f; .align 8 + l32i a3, a2, PT_AREG3; _j 1f; .align 8 + l32i a3, a2, PT_AREG4; _j 1f; .align 8 + mov a3, a5; _j 1f; .align 8 + mov a3, a6; _j 1f; .align 8 + mov a3, a7; _j 1f; .align 8 + mov a3, a8; _j 1f; .align 8 + mov a3, a9; _j 1f; .align 8 + mov a3, a10; _j 1f; .align 8 + mov a3, a11; _j 1f; .align 8 + mov a3, a12; _j 1f; .align 8 + mov a3, a13; _j 1f; .align 8 + mov a3, a14; _j 1f; .align 8 + mov a3, a15; _j 1f; .align 8 + +1: + +#ifdef ALLOCA_EXCEPTION_IN_IRAM +#error iram not supported +#else + l8ui a0, a4, 0 # read ar(dst) from MOVSP instruction +#endif + addi a4, a4, 3 # step over movsp + _EXTUI_MOVSP_DST(a0) # extract destination register + wsr a4, EPC_1 # save new epc_1 + + _bnei a0, 1, 1f # no 'movsp a1, ax': jump + + /* Move the save area. This implies the use of the L32E + * and S32E instructions, because this move must be done with + * the user's PS.RING privilege levels, not with ring 0 + * (kernel's) privileges currently active with PS.EXCM + * set. Note that we have stil registered a fixup routine with the + * double exception vector in case a double exception occurs. + */ + + /* a0,a4:avail a1:old user stack a2:exc. stack a3:new user stack. */ + + l32e a0, a1, -16 + l32e a4, a1, -12 + s32e a0, a3, -16 + s32e a4, a3, -12 + l32e a0, a1, -8 + l32e a4, a1, -4 + s32e a0, a3, -8 + s32e a4, a3, -4 + + /* Restore stack-pointer and all the other saved registers. */ + + mov a1, a3 + + l32i a4, a2, PT_AREG4 + l32i a3, a2, PT_AREG3 + l32i a0, a2, PT_AREG0 + l32i a2, a2, PT_AREG2 + rfe + + /* MOVSP <at>,<as> was invoked with <at> != a1. + * Because the stack pointer is not being modified, + * we should be able to just modify the pointer + * without moving any save area. + * The processor only traps these occurrences if the + * caller window isn't live, so unfortunately we can't + * use this as an alternate trap mechanism. + * So we just do the move. This requires that we + * resolve the destination register, not just the source, + * so there's some extra work. + * (PERHAPS NOT REALLY NEEDED, BUT CLEANER...) + */ + + /* a0 dst-reg, a1 user-stack, a2 stack, a3 value of src reg. */ + +1: movi a4, .Lmovsp_dst + addx8 a4, a0, a4 + jx a4 + + .align 8 +.Lmovsp_dst: + s32i a3, a2, PT_AREG0; _j 1f; .align 8 + mov a1, a3; _j 1f; .align 8 + s32i a3, a2, PT_AREG2; _j 1f; .align 8 + s32i a3, a2, PT_AREG3; _j 1f; .align 8 + s32i a3, a2, PT_AREG4; _j 1f; .align 8 + mov a5, a3; _j 1f; .align 8 + mov a6, a3; _j 1f; .align 8 + mov a7, a3; _j 1f; .align 8 + mov a8, a3; _j 1f; .align 8 + mov a9, a3; _j 1f; .align 8 + mov a10, a3; _j 1f; .align 8 + mov a11, a3; _j 1f; .align 8 + mov a12, a3; _j 1f; .align 8 + mov a13, a3; _j 1f; .align 8 + mov a14, a3; _j 1f; .align 8 + mov a15, a3; _j 1f; .align 8 + +1: l32i a4, a2, PT_AREG4 + l32i a3, a2, PT_AREG3 + l32i a0, a2, PT_AREG0 + l32i a2, a2, PT_AREG2 + rfe + + +/* + * fast system calls. + * + * WARNING: The kernel doesn't save the entire user context before + * handling a fast system call. These functions are small and short, + * usually offering some functionality not available to user tasks. + * + * BE CAREFUL TO PRESERVE THE USER'S CONTEXT. + * + * Entry condition: + * + * a0: trashed, original value saved on stack (PT_AREG0) + * a1: a1 + * a2: new stack pointer, original in DEPC + * a3: dispatch table + * depc: a2, original value saved on stack (PT_DEPC) + * excsave_1: a3 + */ + +ENTRY(fast_syscall_kernel) + + /* Skip syscall. */ + + rsr a0, EPC_1 + addi a0, a0, 3 + wsr a0, EPC_1 + + l32i a0, a2, PT_DEPC + bgeui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, fast_syscall_unrecoverable + + rsr a0, DEPC # get syscall-nr + _beqz a0, fast_syscall_spill_registers + _beqi a0, __NR_xtensa, fast_syscall_xtensa + + j kernel_exception + +ENTRY(fast_syscall_user) + + /* Skip syscall. */ + + rsr a0, EPC_1 + addi a0, a0, 3 + wsr a0, EPC_1 + + l32i a0, a2, PT_DEPC + bgeui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, fast_syscall_unrecoverable + + rsr a0, DEPC # get syscall-nr + _beqz a0, fast_syscall_spill_registers + _beqi a0, __NR_xtensa, fast_syscall_xtensa + + j user_exception + +ENTRY(fast_syscall_unrecoverable) + + /* Restore all states. */ + + l32i a0, a2, PT_AREG0 # restore a0 + xsr a2, DEPC # restore a2, depc + rsr a3, EXCSAVE_1 + + wsr a0, EXCSAVE_1 + movi a0, unrecoverable_exception + callx0 a0 + + + +/* + * sysxtensa syscall handler + * + * int sysxtensa (SYS_XTENSA_ATOMIC_SET, ptr, val, unused); + * int sysxtensa (SYS_XTENSA_ATOMIC_ADD, ptr, val, unused); + * int sysxtensa (SYS_XTENSA_ATOMIC_EXG_ADD, ptr, val, unused); + * int sysxtensa (SYS_XTENSA_ATOMIC_CMP_SWP, ptr, oldval, newval); + * a2 a6 a3 a4 a5 + * + * Entry condition: + * + * a0: a2 (syscall-nr), original value saved on stack (PT_AREG0) + * a1: a1 + * a2: new stack pointer, original in a0 and DEPC + * a3: dispatch table, original in excsave_1 + * a4..a15: unchanged + * depc: a2, original value saved on stack (PT_DEPC) + * excsave_1: a3 + * + * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC + * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception + * + * Note: we don't have to save a2; a2 holds the return value + * + * We use the two macros TRY and CATCH: + * + * TRY adds an entry to the __ex_table fixup table for the immediately + * following instruction. + * + * CATCH catches any exception that occurred at one of the preceding TRY + * statements and continues from there + * + * Usage TRY l32i a0, a1, 0 + * <other code> + * done: rfe + * CATCH <set return code> + * j done + */ + +#define TRY \ + .section __ex_table, "a"; \ + .word 66f, 67f; \ + .text; \ +66: + +#define CATCH \ +67: + +ENTRY(fast_syscall_xtensa) + + xsr a3, EXCSAVE_1 # restore a3, excsave1 + + s32i a7, a2, PT_AREG7 # we need an additional register + movi a7, 4 # sizeof(unsigned int) + access_ok a3, a7, a0, a2, .Leac # a0: scratch reg, a2: sp + + addi a6, a6, -1 # assuming SYS_XTENSA_ATOMIC_SET = 1 + _bgeui a6, SYS_XTENSA_COUNT - 1, .Lill + _bnei a6, SYS_XTENSA_ATOMIC_CMP_SWP - 1, .Lnswp + + /* Fall through for ATOMIC_CMP_SWP. */ + +.Lswp: /* Atomic compare and swap */ + +TRY l32i a0, a3, 0 # read old value + bne a0, a4, 1f # same as old value? jump +TRY s32i a5, a3, 0 # different, modify value + l32i a7, a2, PT_AREG7 # restore a7 + l32i a0, a2, PT_AREG0 # restore a0 + movi a2, 1 # and return 1 + addi a6, a6, 1 # restore a6 (really necessary?) + rfe + +1: l32i a7, a2, PT_AREG7 # restore a7 + l32i a0, a2, PT_AREG0 # restore a0 + movi a2, 0 # return 0 (note that we cannot set + addi a6, a6, 1 # restore a6 (really necessary?) + rfe + +.Lnswp: /* Atomic set, add, and exg_add. */ + +TRY l32i a7, a3, 0 # orig + add a0, a4, a7 # + arg + moveqz a0, a4, a6 # set +TRY s32i a0, a3, 0 # write new value + + mov a0, a2 + mov a2, a7 + l32i a7, a0, PT_AREG7 # restore a7 + l32i a0, a0, PT_AREG0 # restore a0 + addi a6, a6, 1 # restore a6 (really necessary?) + rfe + +CATCH +.Leac: l32i a7, a2, PT_AREG7 # restore a7 + l32i a0, a2, PT_AREG0 # restore a0 + movi a2, -EFAULT + rfe + +.Lill: l32i a7, a2, PT_AREG0 # restore a7 + l32i a0, a2, PT_AREG0 # restore a0 + movi a2, -EINVAL + rfe + + + + +/* fast_syscall_spill_registers. + * + * Entry condition: + * + * a0: trashed, original value saved on stack (PT_AREG0) + * a1: a1 + * a2: new stack pointer, original in DEPC + * a3: dispatch table + * depc: a2, original value saved on stack (PT_DEPC) + * excsave_1: a3 + * + * Note: We assume the stack pointer is EXC_TABLE_KSTK in the fixup handler. + */ + +ENTRY(fast_syscall_spill_registers) + + /* Register a FIXUP handler (pass current wb as a parameter) */ + + movi a0, fast_syscall_spill_registers_fixup + s32i a0, a3, EXC_TABLE_FIXUP + rsr a0, WINDOWBASE + s32i a0, a3, EXC_TABLE_PARAM + + /* Save a3 and SAR on stack. */ + + rsr a0, SAR + xsr a3, EXCSAVE_1 # restore a3 and excsave_1 + s32i a3, a2, PT_AREG3 + s32i a4, a2, PT_AREG4 + s32i a0, a2, PT_AREG5 # store SAR to PT_AREG5 + + /* The spill routine might clobber a7, a11, and a15. */ + + s32i a7, a2, PT_AREG7 + s32i a11, a2, PT_AREG11 + s32i a15, a2, PT_AREG15 + + call0 _spill_registers # destroys a3, a4, and SAR + + /* Advance PC, restore registers and SAR, and return from exception. */ + + l32i a3, a2, PT_AREG5 + l32i a4, a2, PT_AREG4 + l32i a0, a2, PT_AREG0 + wsr a3, SAR + l32i a3, a2, PT_AREG3 + + /* Restore clobbered registers. */ + + l32i a7, a2, PT_AREG7 + l32i a11, a2, PT_AREG11 + l32i a15, a2, PT_AREG15 + + movi a2, 0 + rfe + +/* Fixup handler. + * + * We get here if the spill routine causes an exception, e.g. tlb miss. + * We basically restore WINDOWBASE and WINDOWSTART to the condition when + * we entered the spill routine and jump to the user exception handler. + * + * a0: value of depc, original value in depc + * a2: trashed, original value in EXC_TABLE_DOUBLE_SAVE + * a3: exctable, original value in excsave1 + */ + +fast_syscall_spill_registers_fixup: + + rsr a2, WINDOWBASE # get current windowbase (a2 is saved) + xsr a0, DEPC # restore depc and a0 + ssl a2 # set shift (32 - WB) + + /* We need to make sure the current registers (a0-a3) are preserved. + * To do this, we simply set the bit for the current window frame + * in WS, so that the exception handlers save them to the task stack. + */ + + rsr a3, EXCSAVE_1 # get spill-mask + slli a2, a3, 1 # shift left by one + + slli a3, a2, 32-WSBITS + src a2, a2, a3 # a1 = xxwww1yyxxxwww1yy...... + wsr a2, WINDOWSTART # set corrected windowstart + + movi a3, exc_table + l32i a2, a3, EXC_TABLE_DOUBLE_SAVE # restore a2 + l32i a3, a3, EXC_TABLE_PARAM # original WB (in user task) + + /* Return to the original (user task) WINDOWBASE. + * We leave the following frame behind: + * a0, a1, a2 same + * a3: trashed (saved in excsave_1) + * depc: depc (we have to return to that address) + * excsave_1: a3 + */ + + wsr a3, WINDOWBASE + rsync + + /* We are now in the original frame when we entered _spill_registers: + * a0: return address + * a1: used, stack pointer + * a2: kernel stack pointer + * a3: available, saved in EXCSAVE_1 + * depc: exception address + * excsave: a3 + * Note: This frame might be the same as above. + */ + + /* Setup stack pointer. */ + + addi a2, a2, -PT_USER_SIZE + s32i a0, a2, PT_AREG0 + + /* Make sure we return to this fixup handler. */ + + movi a3, fast_syscall_spill_registers_fixup_return + s32i a3, a2, PT_DEPC # setup depc + + /* Jump to the exception handler. */ + + movi a3, exc_table + rsr a0, EXCCAUSE + addx4 a0, a0, a3 # find entry in table + l32i a0, a0, EXC_TABLE_FAST_USER # load handler + jx a0 + +fast_syscall_spill_registers_fixup_return: + + /* When we return here, all registers have been restored (a2: DEPC) */ + + wsr a2, DEPC # exception address + + /* Restore fixup handler. */ + + xsr a3, EXCSAVE_1 + movi a2, fast_syscall_spill_registers_fixup + s32i a2, a3, EXC_TABLE_FIXUP + rsr a2, WINDOWBASE + s32i a2, a3, EXC_TABLE_PARAM + l32i a2, a3, EXC_TABLE_KSTK + + /* Load WB at the time the exception occurred. */ + + rsr a3, SAR # WB is still in SAR + neg a3, a3 + wsr a3, WINDOWBASE + rsync + + /* Restore a3 and return. */ + + movi a3, exc_table + xsr a3, EXCSAVE_1 + + rfde + + +/* + * spill all registers. + * + * This is not a real function. The following conditions must be met: + * + * - must be called with call0. + * - uses a3, a4 and SAR. + * - the last 'valid' register of each frame are clobbered. + * - the caller must have registered a fixup handler + * (or be inside a critical section) + * - PS_EXCM must be set (PS_WOE cleared?) + */ + +ENTRY(_spill_registers) + + /* + * Rotate ws so that the current windowbase is at bit 0. + * Assume ws = xxxwww1yy (www1 current window frame). + * Rotate ws right so that a4 = yyxxxwww1. + */ + + rsr a4, WINDOWBASE + rsr a3, WINDOWSTART # a3 = xxxwww1yy + ssr a4 # holds WB + slli a4, a3, WSBITS + or a3, a3, a4 # a3 = xxxwww1yyxxxwww1yy + srl a3, a3 # a3 = 00xxxwww1yyxxxwww1 + + /* We are done if there are no more than the current register frame. */ + + extui a3, a3, 1, WSBITS-1 # a3 = 0yyxxxwww + movi a4, (1 << (WSBITS-1)) + _beqz a3, .Lnospill # only one active frame? jump + + /* We want 1 at the top, so that we return to the current windowbase */ + + or a3, a3, a4 # 1yyxxxwww + + /* Skip empty frames - get 'oldest' WINDOWSTART-bit. */ + + wsr a3, WINDOWSTART # save shifted windowstart + neg a4, a3 + and a3, a4, a3 # first bit set from right: 000010000 + + ffs_ws a4, a3 # a4: shifts to skip empty frames + movi a3, WSBITS + sub a4, a3, a4 # WSBITS-a4:number of 0-bits from right + ssr a4 # save in SAR for later. + + rsr a3, WINDOWBASE + add a3, a3, a4 + wsr a3, WINDOWBASE + rsync + + rsr a3, WINDOWSTART + srl a3, a3 # shift windowstart + + /* WB is now just one frame below the oldest frame in the register + window. WS is shifted so the oldest frame is in bit 0, thus, WB + and WS differ by one 4-register frame. */ + + /* Save frames. Depending what call was used (call4, call8, call12), + * we have to save 4,8. or 12 registers. + */ + + _bbsi.l a3, 1, .Lc4 + _bbsi.l a3, 2, .Lc8 + + /* Special case: we have a call12-frame starting at a4. */ + + _bbci.l a3, 3, .Lc12 # bit 3 shouldn't be zero! (Jump to Lc12 first) + + s32e a4, a1, -16 # a1 is valid with an empty spill area + l32e a4, a5, -12 + s32e a8, a4, -48 + mov a8, a4 + l32e a4, a1, -16 + j .Lc12c + +.Lnospill: + ret + +.Lloop: _bbsi.l a3, 1, .Lc4 + _bbci.l a3, 2, .Lc12 + +.Lc8: s32e a4, a13, -16 + l32e a4, a5, -12 + s32e a8, a4, -32 + s32e a5, a13, -12 + s32e a6, a13, -8 + s32e a7, a13, -4 + s32e a9, a4, -28 + s32e a10, a4, -24 + s32e a11, a4, -20 + + srli a11, a3, 2 # shift windowbase by 2 + rotw 2 + _bnei a3, 1, .Lloop + +.Lexit: /* Done. Do the final rotation, set WS, and return. */ + + rotw 1 + rsr a3, WINDOWBASE + ssl a3 + movi a3, 1 + sll a3, a3 + wsr a3, WINDOWSTART + ret + +.Lc4: s32e a4, a9, -16 + s32e a5, a9, -12 + s32e a6, a9, -8 + s32e a7, a9, -4 + + srli a7, a3, 1 + rotw 1 + _bnei a3, 1, .Lloop + j .Lexit + +.Lc12: _bbci.l a3, 3, .Linvalid_mask # bit 2 shouldn't be zero! + + /* 12-register frame (call12) */ + + l32e a2, a5, -12 + s32e a8, a2, -48 + mov a8, a2 + +.Lc12c: s32e a9, a8, -44 + s32e a10, a8, -40 + s32e a11, a8, -36 + s32e a12, a8, -32 + s32e a13, a8, -28 + s32e a14, a8, -24 + s32e a15, a8, -20 + srli a15, a3, 3 + + /* The stack pointer for a4..a7 is out of reach, so we rotate the + * window, grab the stackpointer, and rotate back. + * Alternatively, we could also use the following approach, but that + * makes the fixup routine much more complicated: + * rotw 1 + * s32e a0, a13, -16 + * ... + * rotw 2 + */ + + rotw 1 + mov a5, a13 + rotw -1 + + s32e a4, a9, -16 + s32e a5, a9, -12 + s32e a6, a9, -8 + s32e a7, a9, -4 + + rotw 3 + + _beqi a3, 1, .Lexit + j .Lloop + +.Linvalid_mask: + + /* We get here because of an unrecoverable error in the window + * registers. If we are in user space, we kill the application, + * however, this condition is unrecoverable in kernel space. + */ + + rsr a0, PS + _bbci.l a0, PS_UM_BIT, 1f + + /* User space: Setup a dummy frame and kill application. + * Note: We assume EXC_TABLE_KSTK contains a valid stack pointer. + */ + + movi a0, 1 + movi a1, 0 + + wsr a0, WINDOWSTART + wsr a1, WINDOWBASE + rsync + + movi a0, 0 + + movi a3, exc_table + l32i a1, a3, EXC_TABLE_KSTK + wsr a3, EXCSAVE_1 + + movi a4, (1 << PS_WOE_BIT) | 1 + wsr a4, PS + rsync + + movi a6, SIGSEGV + movi a4, do_exit + callx4 a4 + +1: /* Kernel space: PANIC! */ + + wsr a0, EXCSAVE_1 + movi a0, unrecoverable_exception + callx0 a0 # should not return +1: j 1b + +#ifdef CONFIG_MMU +/* + * We should never get here. Bail out! + */ + +ENTRY(fast_second_level_miss_double_kernel) + +1: movi a0, unrecoverable_exception + callx0 a0 # should not return +1: j 1b + +/* First-level entry handler for user, kernel, and double 2nd-level + * TLB miss exceptions. Note that for now, user and kernel miss + * exceptions share the same entry point and are handled identically. + * + * An old, less-efficient C version of this function used to exist. + * We include it below, interleaved as comments, for reference. + * + * Entry condition: + * + * a0: trashed, original value saved on stack (PT_AREG0) + * a1: a1 + * a2: new stack pointer, original in DEPC + * a3: dispatch table + * depc: a2, original value saved on stack (PT_DEPC) + * excsave_1: a3 + * + * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC + * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception + */ + +ENTRY(fast_second_level_miss) + + /* Save a1. Note: we don't expect a double exception. */ + + s32i a1, a2, PT_AREG1 + + /* We need to map the page of PTEs for the user task. Find + * the pointer to that page. Also, it's possible for tsk->mm + * to be NULL while tsk->active_mm is nonzero if we faulted on + * a vmalloc address. In that rare case, we must use + * active_mm instead to avoid a fault in this handler. See + * + * http://mail.nl.linux.org/linux-mm/2002-08/msg00258.html + * (or search Internet on "mm vs. active_mm") + * + * if (!mm) + * mm = tsk->active_mm; + * pgd = pgd_offset (mm, regs->excvaddr); + * pmd = pmd_offset (pgd, regs->excvaddr); + * pmdval = *pmd; + */ + + GET_CURRENT(a1,a2) + l32i a0, a1, TASK_MM # tsk->mm + beqz a0, 9f + + + /* We deliberately destroy a3 that holds the exception table. */ + +8: rsr a3, EXCVADDR # fault address + _PGD_OFFSET(a0, a3, a1) + l32i a0, a0, 0 # read pmdval + beqz a0, 2f + + /* Read ptevaddr and convert to top of page-table page. + * + * vpnval = read_ptevaddr_register() & PAGE_MASK; + * vpnval += DTLB_WAY_PGTABLE; + * pteval = mk_pte (virt_to_page(pmd_val(pmdval)), PAGE_KERNEL); + * write_dtlb_entry (pteval, vpnval); + * + * The messy computation for 'pteval' above really simplifies + * into the following: + * + * pteval = ((pmdval - PAGE_OFFSET) & PAGE_MASK) | PAGE_DIRECTORY + */ + + movi a1, -PAGE_OFFSET + add a0, a0, a1 # pmdval - PAGE_OFFSET + extui a1, a0, 0, PAGE_SHIFT # ... & PAGE_MASK + xor a0, a0, a1 + + movi a1, _PAGE_DIRECTORY + or a0, a0, a1 # ... | PAGE_DIRECTORY + + /* + * We utilize all three wired-ways (7-9) to hold pmd translations. + * Memory regions are mapped to the DTLBs according to bits 28 and 29. + * This allows to map the three most common regions to three different + * DTLBs: + * 0,1 -> way 7 program (0040.0000) and virtual (c000.0000) + * 2 -> way 8 shared libaries (2000.0000) + * 3 -> way 0 stack (3000.0000) + */ + + extui a3, a3, 28, 2 # addr. bit 28 and 29 0,1,2,3 + rsr a1, PTEVADDR + addx2 a3, a3, a3 # -> 0,3,6,9 + srli a1, a1, PAGE_SHIFT + extui a3, a3, 2, 2 # -> 0,0,1,2 + slli a1, a1, PAGE_SHIFT # ptevaddr & PAGE_MASK + addi a3, a3, DTLB_WAY_PGD + add a1, a1, a3 # ... + way_number + +3: wdtlb a0, a1 + dsync + + /* Exit critical section. */ + +4: movi a3, exc_table # restore a3 + movi a0, 0 + s32i a0, a3, EXC_TABLE_FIXUP + + /* Restore the working registers, and return. */ + + l32i a0, a2, PT_AREG0 + l32i a1, a2, PT_AREG1 + l32i a2, a2, PT_DEPC + xsr a3, EXCSAVE_1 + + bgeui a2, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f + + /* Restore excsave1 and return. */ + + rsr a2, DEPC + rfe + + /* Return from double exception. */ + +1: xsr a2, DEPC + esync + rfde + +9: l32i a0, a1, TASK_ACTIVE_MM # unlikely case mm == 0 + j 8b + +#if (DCACHE_WAY_SIZE > PAGE_SIZE) + +2: /* Special case for cache aliasing. + * We (should) only get here if a clear_user_page, copy_user_page + * or the aliased cache flush functions got preemptively interrupted + * by another task. Re-establish temporary mapping to the + * TLBTEMP_BASE areas. + */ + + /* We shouldn't be in a double exception */ + + l32i a0, a2, PT_DEPC + bgeui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, 2f + + /* Make sure the exception originated in the special functions */ + + movi a0, __tlbtemp_mapping_start + rsr a3, EPC_1 + bltu a3, a0, 2f + movi a0, __tlbtemp_mapping_end + bgeu a3, a0, 2f + + /* Check if excvaddr was in one of the TLBTEMP_BASE areas. */ + + movi a3, TLBTEMP_BASE_1 + rsr a0, EXCVADDR + bltu a0, a3, 2f + + addi a1, a0, -(2 << (DCACHE_ALIAS_ORDER + PAGE_SHIFT)) + bgeu a1, a3, 2f + + /* Check if we have to restore an ITLB mapping. */ + + movi a1, __tlbtemp_mapping_itlb + rsr a3, EPC_1 + sub a3, a3, a1 + + /* Calculate VPN */ + + movi a1, PAGE_MASK + and a1, a1, a0 + + /* Jump for ITLB entry */ + + bgez a3, 1f + + /* We can use up to two TLBTEMP areas, one for src and one for dst. */ + + extui a3, a0, PAGE_SHIFT + DCACHE_ALIAS_ORDER, 1 + add a1, a3, a1 + + /* PPN is in a6 for the first TLBTEMP area and in a7 for the second. */ + + mov a0, a6 + movnez a0, a7, a3 + j 3b + + /* ITLB entry. We only use dst in a6. */ + +1: witlb a6, a1 + isync + j 4b + + +#endif // DCACHE_WAY_SIZE > PAGE_SIZE + + +2: /* Invalid PGD, default exception handling */ + + movi a3, exc_table + rsr a1, DEPC + xsr a3, EXCSAVE_1 + s32i a1, a2, PT_AREG2 + s32i a3, a2, PT_AREG3 + mov a1, a2 + + rsr a2, PS + bbsi.l a2, PS_UM_BIT, 1f + j _kernel_exception +1: j _user_exception + + +/* + * StoreProhibitedException + * + * Update the pte and invalidate the itlb mapping for this pte. + * + * Entry condition: + * + * a0: trashed, original value saved on stack (PT_AREG0) + * a1: a1 + * a2: new stack pointer, original in DEPC + * a3: dispatch table + * depc: a2, original value saved on stack (PT_DEPC) + * excsave_1: a3 + * + * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC + * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception + */ + +ENTRY(fast_store_prohibited) + + /* Save a1 and a4. */ + + s32i a1, a2, PT_AREG1 + s32i a4, a2, PT_AREG4 + + GET_CURRENT(a1,a2) + l32i a0, a1, TASK_MM # tsk->mm + beqz a0, 9f + +8: rsr a1, EXCVADDR # fault address + _PGD_OFFSET(a0, a1, a4) + l32i a0, a0, 0 + beqz a0, 2f + + /* Note that we assume _PAGE_WRITABLE_BIT is only set if pte is valid.*/ + + _PTE_OFFSET(a0, a1, a4) + l32i a4, a0, 0 # read pteval + bbci.l a4, _PAGE_WRITABLE_BIT, 2f + + movi a1, _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_HW_WRITE + or a4, a4, a1 + rsr a1, EXCVADDR + s32i a4, a0, 0 + + /* We need to flush the cache if we have page coloring. */ +#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK + dhwb a0, 0 +#endif + pdtlb a0, a1 + wdtlb a4, a0 + + /* Exit critical section. */ + + movi a0, 0 + s32i a0, a3, EXC_TABLE_FIXUP + + /* Restore the working registers, and return. */ + + l32i a4, a2, PT_AREG4 + l32i a1, a2, PT_AREG1 + l32i a0, a2, PT_AREG0 + l32i a2, a2, PT_DEPC + + /* Restore excsave1 and a3. */ + + xsr a3, EXCSAVE_1 + bgeui a2, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f + + rsr a2, DEPC + rfe + + /* Double exception. Restore FIXUP handler and return. */ + +1: xsr a2, DEPC + esync + rfde + +9: l32i a0, a1, TASK_ACTIVE_MM # unlikely case mm == 0 + j 8b + +2: /* If there was a problem, handle fault in C */ + + rsr a4, DEPC # still holds a2 + xsr a3, EXCSAVE_1 + s32i a4, a2, PT_AREG2 + s32i a3, a2, PT_AREG3 + l32i a4, a2, PT_AREG4 + mov a1, a2 + + rsr a2, PS + bbsi.l a2, PS_UM_BIT, 1f + j _kernel_exception +1: j _user_exception +#endif /* CONFIG_MMU */ + +/* + * System Calls. + * + * void system_call (struct pt_regs* regs, int exccause) + * a2 a3 + */ + +ENTRY(system_call) + entry a1, 32 + + /* regs->syscall = regs->areg[2] */ + + l32i a3, a2, PT_AREG2 + mov a6, a2 + movi a4, do_syscall_trace_enter + s32i a3, a2, PT_SYSCALL + callx4 a4 + + /* syscall = sys_call_table[syscall_nr] */ + + movi a4, sys_call_table; + movi a5, __NR_syscall_count + movi a6, -ENOSYS + bgeu a3, a5, 1f + + addx4 a4, a3, a4 + l32i a4, a4, 0 + movi a5, sys_ni_syscall; + beq a4, a5, 1f + + /* Load args: arg0 - arg5 are passed via regs. */ + + l32i a6, a2, PT_AREG6 + l32i a7, a2, PT_AREG3 + l32i a8, a2, PT_AREG4 + l32i a9, a2, PT_AREG5 + l32i a10, a2, PT_AREG8 + l32i a11, a2, PT_AREG9 + + /* Pass one additional argument to the syscall: pt_regs (on stack) */ + s32i a2, a1, 0 + + callx4 a4 + +1: /* regs->areg[2] = return_value */ + + s32i a6, a2, PT_AREG2 + movi a4, do_syscall_trace_leave + mov a6, a2 + callx4 a4 + retw + + +/* + * Create a kernel thread + * + * int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) + * a2 a2 a3 a4 + */ + +ENTRY(kernel_thread) + entry a1, 16 + + mov a5, a2 # preserve fn over syscall + mov a7, a3 # preserve args over syscall + + movi a3, _CLONE_VM | _CLONE_UNTRACED + movi a2, __NR_clone + or a6, a4, a3 # arg0: flags + mov a3, a1 # arg1: sp + syscall + + beq a3, a1, 1f # branch if parent + mov a6, a7 # args + callx4 a5 # fn(args) + + movi a2, __NR_exit + syscall # return value of fn(args) still in a6 + +1: retw + +/* + * Do a system call from kernel instead of calling sys_execve, so we end up + * with proper pt_regs. + * + * int kernel_execve(const char *fname, char *const argv[], charg *const envp[]) + * a2 a2 a3 a4 + */ + +ENTRY(kernel_execve) + entry a1, 16 + mov a6, a2 # arg0 is in a6 + movi a2, __NR_execve + syscall + + retw + +/* + * Task switch. + * + * struct task* _switch_to (struct task* prev, struct task* next) + * a2 a2 a3 + */ + +ENTRY(_switch_to) + + entry a1, 16 + + mov a12, a2 # preserve 'prev' (a2) + mov a13, a3 # and 'next' (a3) + + l32i a4, a2, TASK_THREAD_INFO + l32i a5, a3, TASK_THREAD_INFO + + save_xtregs_user a4 a6 a8 a9 a10 a11 THREAD_XTREGS_USER + + s32i a0, a12, THREAD_RA # save return address + s32i a1, a12, THREAD_SP # save stack pointer + + /* Disable ints while we manipulate the stack pointer. */ + + movi a14, (1 << PS_EXCM_BIT) | LOCKLEVEL + xsr a14, PS + rsr a3, EXCSAVE_1 + rsync + s32i a3, a3, EXC_TABLE_FIXUP /* enter critical section */ + + /* Switch CPENABLE */ + +#if (XTENSA_HAVE_COPROCESSORS || XTENSA_HAVE_IO_PORTS) + l32i a3, a5, THREAD_CPENABLE + xsr a3, CPENABLE + s32i a3, a4, THREAD_CPENABLE +#endif + + /* Flush register file. */ + + call0 _spill_registers # destroys a3, a4, and SAR + + /* Set kernel stack (and leave critical section) + * Note: It's save to set it here. The stack will not be overwritten + * because the kernel stack will only be loaded again after + * we return from kernel space. + */ + + rsr a3, EXCSAVE_1 # exc_table + movi a6, 0 + addi a7, a5, PT_REGS_OFFSET + s32i a6, a3, EXC_TABLE_FIXUP + s32i a7, a3, EXC_TABLE_KSTK + + /* restore context of the task that 'next' addresses */ + + l32i a0, a13, THREAD_RA # restore return address + l32i a1, a13, THREAD_SP # restore stack pointer + + load_xtregs_user a5 a6 a8 a9 a10 a11 THREAD_XTREGS_USER + + wsr a14, PS + mov a2, a12 # return 'prev' + rsync + + retw + + +ENTRY(ret_from_fork) + + /* void schedule_tail (struct task_struct *prev) + * Note: prev is still in a6 (return value from fake call4 frame) + */ + movi a4, schedule_tail + callx4 a4 + + movi a4, do_syscall_trace_leave + mov a6, a1 + callx4 a4 + + j common_exception_return + diff --git a/arch/xtensa/kernel/head.S b/arch/xtensa/kernel/head.S new file mode 100644 index 00000000..3ef91a73 --- /dev/null +++ b/arch/xtensa/kernel/head.S @@ -0,0 +1,244 @@ +/* + * arch/xtensa/kernel/head.S + * + * Xtensa Processor startup code. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + * + * Chris Zankel <chris@zankel.net> + * Marc Gauthier <marc@tensilica.com, marc@alumni.uwaterloo.ca> + * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com> + * Kevin Chea + */ + +#include <asm/processor.h> +#include <asm/page.h> +#include <asm/cacheasm.h> + +#include <linux/init.h> +#include <linux/linkage.h> + +/* + * This module contains the entry code for kernel images. It performs the + * minimal setup needed to call the generic C routines. + * + * Prerequisites: + * + * - The kernel image has been loaded to the actual address where it was + * compiled to. + * - a2 contains either 0 or a pointer to a list of boot parameters. + * (see setup.c for more details) + * + */ + +/* + * _start + * + * The bootloader passes a pointer to a list of boot parameters in a2. + */ + + /* The first bytes of the kernel image must be an instruction, so we + * manually allocate and define the literal constant we need for a jx + * instruction. + */ + + __HEAD + .globl _start +_start: _j 2f + .align 4 +1: .word _startup +2: l32r a0, 1b + jx a0 + + .section .init.text, "ax" + .align 4 +_startup: + + /* Disable interrupts and exceptions. */ + + movi a0, LOCKLEVEL + wsr a0, PS + + /* Preserve the pointer to the boot parameter list in EXCSAVE_1 */ + + wsr a2, EXCSAVE_1 + + /* Start with a fresh windowbase and windowstart. */ + + movi a1, 1 + movi a0, 0 + wsr a1, WINDOWSTART + wsr a0, WINDOWBASE + rsync + + /* Set a0 to 0 for the remaining initialization. */ + + movi a0, 0 + + /* Clear debugging registers. */ + +#if XCHAL_HAVE_DEBUG + wsr a0, IBREAKENABLE + wsr a0, ICOUNT + movi a1, 15 + wsr a0, ICOUNTLEVEL + + .set _index, 0 + .rept XCHAL_NUM_DBREAK - 1 + wsr a0, DBREAKC + _index + .set _index, _index + 1 + .endr +#endif + + /* Clear CCOUNT (not really necessary, but nice) */ + + wsr a0, CCOUNT # not really necessary, but nice + + /* Disable zero-loops. */ + +#if XCHAL_HAVE_LOOPS + wsr a0, LCOUNT +#endif + + /* Disable all timers. */ + + .set _index, 0 + .rept XCHAL_NUM_TIMERS - 1 + wsr a0, CCOMPARE + _index + .set _index, _index + 1 + .endr + + /* Interrupt initialization. */ + + movi a2, XCHAL_INTTYPE_MASK_SOFTWARE | XCHAL_INTTYPE_MASK_EXTERN_EDGE + wsr a0, INTENABLE + wsr a2, INTCLEAR + + /* Disable coprocessors. */ + +#if XCHAL_CP_NUM > 0 + wsr a0, CPENABLE +#endif + + /* Set PS.INTLEVEL=1, PS.WOE=0, kernel stack, PS.EXCM=0 + * + * Note: PS.EXCM must be cleared before using any loop + * instructions; otherwise, they are silently disabled, and + * at most one iteration of the loop is executed. + */ + + movi a1, 1 + wsr a1, PS + rsync + + /* Initialize the caches. + * a2, a3 are just working registers (clobbered). + */ + +#if XCHAL_DCACHE_LINE_LOCKABLE + ___unlock_dcache_all a2 a3 +#endif + +#if XCHAL_ICACHE_LINE_LOCKABLE + ___unlock_icache_all a2 a3 +#endif + + ___invalidate_dcache_all a2 a3 + ___invalidate_icache_all a2 a3 + + isync + + /* Unpack data sections + * + * The linker script used to build the Linux kernel image + * creates a table located at __boot_reloc_table_start + * that contans the information what data needs to be unpacked. + * + * Uses a2-a7. + */ + + movi a2, __boot_reloc_table_start + movi a3, __boot_reloc_table_end + +1: beq a2, a3, 3f # no more entries? + l32i a4, a2, 0 # start destination (in RAM) + l32i a5, a2, 4 # end desination (in RAM) + l32i a6, a2, 8 # start source (in ROM) + addi a2, a2, 12 # next entry + beq a4, a5, 1b # skip, empty entry + beq a4, a6, 1b # skip, source and dest. are the same + +2: l32i a7, a6, 0 # load word + addi a6, a6, 4 + s32i a7, a4, 0 # store word + addi a4, a4, 4 + bltu a4, a5, 2b + j 1b + +3: + /* All code and initialized data segments have been copied. + * Now clear the BSS segment. + */ + + movi a2, __bss_start # start of BSS + movi a3, __bss_stop # end of BSS + + __loopt a2, a3, a4, 2 + s32i a0, a2, 0 + __endla a2, a4, 4 + +#if XCHAL_DCACHE_IS_WRITEBACK + + /* After unpacking, flush the writeback cache to memory so the + * instructions/data are available. + */ + + ___flush_dcache_all a2 a3 +#endif + + /* Setup stack and enable window exceptions (keep irqs disabled) */ + + movi a1, init_thread_union + addi a1, a1, KERNEL_STACK_SIZE + + movi a2, 0x00040001 # WOE=1, INTLEVEL=1, UM=0 + wsr a2, PS # (enable reg-windows; progmode stack) + rsync + + /* Set up EXCSAVE[DEBUGLEVEL] to point to the Debug Exception Handler.*/ + + movi a2, debug_exception + wsr a2, EXCSAVE + XCHAL_DEBUGLEVEL + + /* Set up EXCSAVE[1] to point to the exc_table. */ + + movi a6, exc_table + xsr a6, EXCSAVE_1 + + /* init_arch kick-starts the linux kernel */ + + movi a4, init_arch + callx4 a4 + + movi a4, start_kernel + callx4 a4 + +should_never_return: + j should_never_return + + +/* + * BSS section + */ + +__PAGE_ALIGNED_BSS +#ifdef CONFIG_MMU +ENTRY(swapper_pg_dir) + .fill PAGE_SIZE, 1, 0 +#endif +ENTRY(empty_zero_page) + .fill PAGE_SIZE, 1, 0 diff --git a/arch/xtensa/kernel/init_task.c b/arch/xtensa/kernel/init_task.c new file mode 100644 index 00000000..cd122fb7 --- /dev/null +++ b/arch/xtensa/kernel/init_task.c @@ -0,0 +1,31 @@ +/* + * arch/xtensa/kernel/init_task.c + * + * Xtensa Processor version. + * + * 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) 2007 Tensilica Inc. + * + * Chris Zankel <chris@zankel.net> + */ + +#include <linux/mm.h> +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/init_task.h> +#include <linux/module.h> +#include <linux/mqueue.h> + +#include <asm/uaccess.h> + +static struct signal_struct init_signals = INIT_SIGNALS(init_signals); +static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); +union thread_union init_thread_union __init_task_data = + { INIT_THREAD_INFO(init_task) }; + +struct task_struct init_task = INIT_TASK(init_task); + +EXPORT_SYMBOL(init_task); diff --git a/arch/xtensa/kernel/io.c b/arch/xtensa/kernel/io.c new file mode 100644 index 00000000..5b65269b --- /dev/null +++ b/arch/xtensa/kernel/io.c @@ -0,0 +1,75 @@ +/* + * arch/xtensa/io.c + * + * IO primitives + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Copied from sparc. + * + * Chris Zankel <chris@zankel.net> + * + */ + +#include <asm/io.h> +#include <asm/byteorder.h> + +void outsb(unsigned long addr, const void *src, unsigned long count) { + while (count) { + count -= 1; + writeb(*(const char *)src, addr); + src += 1; + addr += 1; + } +} + +void outsw(unsigned long addr, const void *src, unsigned long count) { + while (count) { + count -= 2; + writew(*(const short *)src, addr); + src += 2; + addr += 2; + } +} + +void outsl(unsigned long addr, const void *src, unsigned long count) { + while (count) { + count -= 4; + writel(*(const long *)src, addr); + src += 4; + addr += 4; + } +} + +void insb(unsigned long addr, void *dst, unsigned long count) { + while (count) { + count -= 1; + *(unsigned char *)dst = readb(addr); + dst += 1; + addr += 1; + } +} + +void insw(unsigned long addr, void *dst, unsigned long count) { + while (count) { + count -= 2; + *(unsigned short *)dst = readw(addr); + dst += 2; + addr += 2; + } +} + +void insl(unsigned long addr, void *dst, unsigned long count) { + while (count) { + count -= 4; + /* + * XXX I am sure we are in for an unaligned trap here. + */ + *(unsigned long *)dst = readl(addr); + dst += 4; + addr += 4; + } +} diff --git a/arch/xtensa/kernel/irq.c b/arch/xtensa/kernel/irq.c new file mode 100644 index 00000000..4340ee07 --- /dev/null +++ b/arch/xtensa/kernel/irq.c @@ -0,0 +1,151 @@ +/* + * linux/arch/xtensa/kernel/irq.c + * + * Xtensa built-in interrupt controller and some generic functions copied + * from i386. + * + * Copyright (C) 2002 - 2006 Tensilica, Inc. + * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar + * + * + * Chris Zankel <chris@zankel.net> + * Kevin Chea + * + */ + +#include <linux/module.h> +#include <linux/seq_file.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/kernel_stat.h> + +#include <asm/uaccess.h> +#include <asm/platform.h> + +static unsigned int cached_irq_mask; + +atomic_t irq_err_count; + +/* + * do_IRQ handles all normal device IRQ's (the special + * SMP cross-CPU interrupts have their own specific + * handlers). + */ + +asmlinkage void do_IRQ(int irq, struct pt_regs *regs) +{ + struct pt_regs *old_regs = set_irq_regs(regs); + + if (irq >= NR_IRQS) { + printk(KERN_EMERG "%s: cannot handle IRQ %d\n", + __func__, irq); + } + + irq_enter(); + +#ifdef CONFIG_DEBUG_STACKOVERFLOW + /* Debugging check for stack overflow: is there less than 1KB free? */ + { + unsigned long sp; + + __asm__ __volatile__ ("mov %0, a1\n" : "=a" (sp)); + sp &= THREAD_SIZE - 1; + + if (unlikely(sp < (sizeof(thread_info) + 1024))) + printk("Stack overflow in do_IRQ: %ld\n", + sp - sizeof(struct thread_info)); + } +#endif + generic_handle_irq(irq); + + irq_exit(); + set_irq_regs(old_regs); +} + +int arch_show_interrupts(struct seq_file *p, int prec) +{ + seq_printf(p, "%*s: ", prec, "ERR"); + seq_printf(p, "%10u\n", atomic_read(&irq_err_count)); + return 0; +} + +static void xtensa_irq_mask(struct irq_data *d) +{ + cached_irq_mask &= ~(1 << d->irq); + set_sr (cached_irq_mask, INTENABLE); +} + +static void xtensa_irq_unmask(struct irq_data *d) +{ + cached_irq_mask |= 1 << d->irq; + set_sr (cached_irq_mask, INTENABLE); +} + +static void xtensa_irq_enable(struct irq_data *d) +{ + variant_irq_enable(d->irq); + xtensa_irq_unmask(d->irq); +} + +static void xtensa_irq_disable(struct irq_data *d) +{ + xtensa_irq_mask(d->irq); + variant_irq_disable(d->irq); +} + +static void xtensa_irq_ack(struct irq_data *d) +{ + set_sr(1 << d->irq, INTCLEAR); +} + +static int xtensa_irq_retrigger(struct irq_data *d) +{ + set_sr (1 << d->irq, INTSET); + return 1; +} + + +static struct irq_chip xtensa_irq_chip = { + .name = "xtensa", + .irq_enable = xtensa_irq_enable, + .irq_disable = xtensa_irq_disable, + .irq_mask = xtensa_irq_mask, + .irq_unmask = xtensa_irq_unmask, + .irq_ack = xtensa_irq_ack, + .irq_retrigger = xtensa_irq_retrigger, +}; + +void __init init_IRQ(void) +{ + int index; + + for (index = 0; index < XTENSA_NR_IRQS; index++) { + int mask = 1 << index; + + if (mask & XCHAL_INTTYPE_MASK_SOFTWARE) + irq_set_chip_and_handler(index, &xtensa_irq_chip, + handle_simple_irq); + + else if (mask & XCHAL_INTTYPE_MASK_EXTERN_EDGE) + irq_set_chip_and_handler(index, &xtensa_irq_chip, + handle_edge_irq); + + else if (mask & XCHAL_INTTYPE_MASK_EXTERN_LEVEL) + irq_set_chip_and_handler(index, &xtensa_irq_chip, + handle_level_irq); + + else if (mask & XCHAL_INTTYPE_MASK_TIMER) + irq_set_chip_and_handler(index, &xtensa_irq_chip, + handle_edge_irq); + + else /* XCHAL_INTTYPE_MASK_WRITE_ERROR */ + /* XCHAL_INTTYPE_MASK_NMI */ + + irq_set_chip_and_handler(index, &xtensa_irq_chip, + handle_level_irq); + } + + cached_irq_mask = 0; + + variant_init_irq(); +} diff --git a/arch/xtensa/kernel/module.c b/arch/xtensa/kernel/module.c new file mode 100644 index 00000000..451dda92 --- /dev/null +++ b/arch/xtensa/kernel/module.c @@ -0,0 +1,192 @@ +/* + * arch/xtensa/kernel/module.c + * + * Module support. + * + * 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) 2001 - 2006 Tensilica Inc. + * + * Chris Zankel <chris@zankel.net> + * + */ + +#include <linux/module.h> +#include <linux/moduleloader.h> +#include <linux/elf.h> +#include <linux/vmalloc.h> +#include <linux/fs.h> +#include <linux/string.h> +#include <linux/kernel.h> +#include <linux/cache.h> + +#undef DEBUG_RELOCATE + +static int +decode_calln_opcode (unsigned char *location) +{ +#ifdef __XTENSA_EB__ + return (location[0] & 0xf0) == 0x50; +#endif +#ifdef __XTENSA_EL__ + return (location[0] & 0xf) == 0x5; +#endif +} + +static int +decode_l32r_opcode (unsigned char *location) +{ +#ifdef __XTENSA_EB__ + return (location[0] & 0xf0) == 0x10; +#endif +#ifdef __XTENSA_EL__ + return (location[0] & 0xf) == 0x1; +#endif +} + +int apply_relocate_add(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *mod) +{ + unsigned int i; + Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr; + Elf32_Sym *sym; + unsigned char *location; + uint32_t value; + +#ifdef DEBUG_RELOCATE + printk("Applying relocate section %u to %u\n", relsec, + sechdrs[relsec].sh_info); +#endif + for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) { + location = (char *)sechdrs[sechdrs[relsec].sh_info].sh_addr + + rela[i].r_offset; + sym = (Elf32_Sym *)sechdrs[symindex].sh_addr + + ELF32_R_SYM(rela[i].r_info); + value = sym->st_value + rela[i].r_addend; + + switch (ELF32_R_TYPE(rela[i].r_info)) { + case R_XTENSA_NONE: + case R_XTENSA_DIFF8: + case R_XTENSA_DIFF16: + case R_XTENSA_DIFF32: + case R_XTENSA_ASM_EXPAND: + break; + + case R_XTENSA_32: + case R_XTENSA_PLT: + *(uint32_t *)location += value; + break; + + case R_XTENSA_SLOT0_OP: + if (decode_calln_opcode(location)) { + value -= ((unsigned long)location & -4) + 4; + if ((value & 3) != 0 || + ((value + (1 << 19)) >> 20) != 0) { + printk("%s: relocation out of range, " + "section %d reloc %d " + "sym '%s'\n", + mod->name, relsec, i, + strtab + sym->st_name); + return -ENOEXEC; + } + value = (signed int)value >> 2; +#ifdef __XTENSA_EB__ + location[0] = ((location[0] & ~0x3) | + ((value >> 16) & 0x3)); + location[1] = (value >> 8) & 0xff; + location[2] = value & 0xff; +#endif +#ifdef __XTENSA_EL__ + location[0] = ((location[0] & ~0xc0) | + ((value << 6) & 0xc0)); + location[1] = (value >> 2) & 0xff; + location[2] = (value >> 10) & 0xff; +#endif + } else if (decode_l32r_opcode(location)) { + value -= (((unsigned long)location + 3) & -4); + if ((value & 3) != 0 || + (signed int)value >> 18 != -1) { + printk("%s: relocation out of range, " + "section %d reloc %d " + "sym '%s'\n", + mod->name, relsec, i, + strtab + sym->st_name); + return -ENOEXEC; + } + value = (signed int)value >> 2; + +#ifdef __XTENSA_EB__ + location[1] = (value >> 8) & 0xff; + location[2] = value & 0xff; +#endif +#ifdef __XTENSA_EL__ + location[1] = value & 0xff; + location[2] = (value >> 8) & 0xff; +#endif + } + /* FIXME: Ignore any other opcodes. The Xtensa + assembler currently assumes that the linker will + always do relaxation and so all PC-relative + operands need relocations. (The assembler also + writes out the tentative PC-relative values, + assuming no link-time relaxation, so it is usually + safe to ignore the relocations.) If the + assembler's "--no-link-relax" flag can be made to + work, and if all kernel modules can be assembled + with that flag, then unexpected relocations could + be detected here. */ + break; + + case R_XTENSA_SLOT1_OP: + case R_XTENSA_SLOT2_OP: + case R_XTENSA_SLOT3_OP: + case R_XTENSA_SLOT4_OP: + case R_XTENSA_SLOT5_OP: + case R_XTENSA_SLOT6_OP: + case R_XTENSA_SLOT7_OP: + case R_XTENSA_SLOT8_OP: + case R_XTENSA_SLOT9_OP: + case R_XTENSA_SLOT10_OP: + case R_XTENSA_SLOT11_OP: + case R_XTENSA_SLOT12_OP: + case R_XTENSA_SLOT13_OP: + case R_XTENSA_SLOT14_OP: + printk("%s: unexpected FLIX relocation: %u\n", + mod->name, + ELF32_R_TYPE(rela[i].r_info)); + return -ENOEXEC; + + case R_XTENSA_SLOT0_ALT: + case R_XTENSA_SLOT1_ALT: + case R_XTENSA_SLOT2_ALT: + case R_XTENSA_SLOT3_ALT: + case R_XTENSA_SLOT4_ALT: + case R_XTENSA_SLOT5_ALT: + case R_XTENSA_SLOT6_ALT: + case R_XTENSA_SLOT7_ALT: + case R_XTENSA_SLOT8_ALT: + case R_XTENSA_SLOT9_ALT: + case R_XTENSA_SLOT10_ALT: + case R_XTENSA_SLOT11_ALT: + case R_XTENSA_SLOT12_ALT: + case R_XTENSA_SLOT13_ALT: + case R_XTENSA_SLOT14_ALT: + printk("%s: unexpected ALT relocation: %u\n", + mod->name, + ELF32_R_TYPE(rela[i].r_info)); + return -ENOEXEC; + + default: + printk("%s: unexpected relocation: %u\n", + mod->name, + ELF32_R_TYPE(rela[i].r_info)); + return -ENOEXEC; + } + } + return 0; +} diff --git a/arch/xtensa/kernel/pci-dma.c b/arch/xtensa/kernel/pci-dma.c new file mode 100644 index 00000000..2783fda7 --- /dev/null +++ b/arch/xtensa/kernel/pci-dma.c @@ -0,0 +1,94 @@ +/* + * arch/xtensa/kernel/pci-dma.c + * + * DMA coherent memory allocation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Copyright (C) 2002 - 2005 Tensilica Inc. + * + * Based on version for i386. + * + * Chris Zankel <chris@zankel.net> + * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com> + */ + +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/string.h> +#include <linux/pci.h> +#include <linux/gfp.h> +#include <asm/io.h> +#include <asm/cacheflush.h> + +/* + * Note: We assume that the full memory space is always mapped to 'kseg' + * Otherwise we have to use page attributes (not implemented). + */ + +void * +dma_alloc_coherent(struct device *dev,size_t size,dma_addr_t *handle,gfp_t flag) +{ + unsigned long ret; + unsigned long uncached = 0; + + /* ignore region speicifiers */ + + flag &= ~(__GFP_DMA | __GFP_HIGHMEM); + + if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff)) + flag |= GFP_DMA; + ret = (unsigned long)__get_free_pages(flag, get_order(size)); + + if (ret == 0) + return NULL; + + /* We currently don't support coherent memory outside KSEG */ + + if (ret < XCHAL_KSEG_CACHED_VADDR + || ret >= XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_SIZE) + BUG(); + + + if (ret != 0) { + memset((void*) ret, 0, size); + uncached = ret+XCHAL_KSEG_BYPASS_VADDR-XCHAL_KSEG_CACHED_VADDR; + *handle = virt_to_bus((void*)ret); + __flush_invalidate_dcache_range(ret, size); + } + + return (void*)uncached; +} + +void dma_free_coherent(struct device *hwdev, size_t size, + void *vaddr, dma_addr_t dma_handle) +{ + long addr=(long)vaddr+XCHAL_KSEG_CACHED_VADDR-XCHAL_KSEG_BYPASS_VADDR; + + if (addr < 0 || addr >= XCHAL_KSEG_SIZE) + BUG(); + + free_pages(addr, get_order(size)); +} + + +void consistent_sync(void *vaddr, size_t size, int direction) +{ + switch (direction) { + case PCI_DMA_NONE: + BUG(); + case PCI_DMA_FROMDEVICE: /* invalidate only */ + __invalidate_dcache_range((unsigned long)vaddr, + (unsigned long)size); + break; + + case PCI_DMA_TODEVICE: /* writeback only */ + case PCI_DMA_BIDIRECTIONAL: /* writeback and invalidate */ + __flush_invalidate_dcache_range((unsigned long)vaddr, + (unsigned long)size); + break; + } +} diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c new file mode 100644 index 00000000..eb30e356 --- /dev/null +++ b/arch/xtensa/kernel/pci.c @@ -0,0 +1,384 @@ +/* + * arch/xtensa/kernel/pci.c + * + * PCI bios-type initialisation for PCI machines + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Copyright (C) 2001-2005 Tensilica Inc. + * + * Based largely on work from Cort (ppc/kernel/pci.c) + * IO functions copied from sparc. + * + * Chris Zankel <chris@zankel.net> + * + */ + +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/string.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/errno.h> +#include <linux/bootmem.h> + +#include <asm/pci-bridge.h> +#include <asm/platform.h> + +#undef DEBUG + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +/* PCI Controller */ + + +/* + * pcibios_alloc_controller + * pcibios_enable_device + * pcibios_fixups + * pcibios_align_resource + * pcibios_fixup_bus + * pcibios_setup + * pci_bus_add_device + * pci_mmap_page_range + */ + +struct pci_controller* pci_ctrl_head; +struct pci_controller** pci_ctrl_tail = &pci_ctrl_head; + +static int pci_bus_count; + +/* + * 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. + * + * Why? Because some silly external IO cards only decode + * the low 10 bits of the IO address. The 0x00-0xff region + * is reserved for motherboard devices that decode all 16 + * bits, so it's ok to allocate at, say, 0x2800-0x28ff, + * but we want to try to avoid allocating at 0x2900-0x2bff + * which might have be mirrored at 0x0100-0x03ff.. + */ +resource_size_t +pcibios_align_resource(void *data, const struct resource *res, + resource_size_t size, resource_size_t align) +{ + struct pci_dev *dev = data; + resource_size_t start = res->start; + + if (res->flags & IORESOURCE_IO) { + if (size > 0x100) { + printk(KERN_ERR "PCI: I/O Region %s/%d too large" + " (%ld bytes)\n", pci_name(dev), + dev->resource - res, size); + } + + if (start & 0x300) + start = (start + 0x3ff) & ~0x3ff; + } + + return start; +} + +int +pcibios_enable_resources(struct pci_dev *dev, int mask) +{ + u16 cmd, old_cmd; + int idx; + struct resource *r; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + old_cmd = cmd; + for(idx=0; idx<6; idx++) { + r = &dev->resource[idx]; + if (!r->start && r->end) { + printk (KERN_ERR "PCI: Device %s not available because " + "of resource collisions\n", pci_name(dev)); + 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("PCI: Enabling device %s (%04x -> %04x)\n", + pci_name(dev), old_cmd, cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + return 0; +} + +struct pci_controller * __init pcibios_alloc_controller(void) +{ + struct pci_controller *pci_ctrl; + + pci_ctrl = (struct pci_controller *)alloc_bootmem(sizeof(*pci_ctrl)); + memset(pci_ctrl, 0, sizeof(struct pci_controller)); + + *pci_ctrl_tail = pci_ctrl; + pci_ctrl_tail = &pci_ctrl->next; + + return pci_ctrl; +} + +static void __init pci_controller_apertures(struct pci_controller *pci_ctrl, + struct list_head *resources) +{ + struct resource *res; + unsigned long io_offset; + int i; + + io_offset = (unsigned long)pci_ctrl->io_space.base; + res = &pci_ctrl->io_resource; + if (!res->flags) { + if (io_offset) + printk (KERN_ERR "I/O resource not set for host" + " bridge %d\n", pci_ctrl->index); + res->start = 0; + res->end = IO_SPACE_LIMIT; + res->flags = IORESOURCE_IO; + } + res->start += io_offset; + res->end += io_offset; + pci_add_resource_offset(resources, res, io_offset); + + for (i = 0; i < 3; i++) { + res = &pci_ctrl->mem_resources[i]; + if (!res->flags) { + if (i > 0) + continue; + printk(KERN_ERR "Memory resource not set for " + "host bridge %d\n", pci_ctrl->index); + res->start = 0; + res->end = ~0U; + res->flags = IORESOURCE_MEM; + } + pci_add_resource(resources, res); + } +} + +static int __init pcibios_init(void) +{ + struct pci_controller *pci_ctrl; + struct list_head resources; + struct pci_bus *bus; + int next_busno = 0, i; + + printk("PCI: Probing PCI hardware\n"); + + /* Scan all of the recorded PCI controllers. */ + for (pci_ctrl = pci_ctrl_head; pci_ctrl; pci_ctrl = pci_ctrl->next) { + pci_ctrl->last_busno = 0xff; + INIT_LIST_HEAD(&resources); + pci_controller_apertures(pci_ctrl, &resources); + bus = pci_scan_root_bus(NULL, pci_ctrl->first_busno, + pci_ctrl->ops, pci_ctrl, &resources); + pci_ctrl->bus = bus; + pci_ctrl->last_busno = bus->subordinate; + if (next_busno <= pci_ctrl->last_busno) + next_busno = pci_ctrl->last_busno+1; + } + pci_bus_count = next_busno; + + return platform_pcibios_fixup(); +} + +subsys_initcall(pcibios_init); + +void __init pcibios_fixup_bus(struct pci_bus *bus) +{ + if (bus->parent) { + /* This is a subordinate bridge */ + pci_read_bridge_bases(bus); + } +} + +char __init *pcibios_setup(char *str) +{ + return str; +} + +void pcibios_set_master(struct pci_dev *dev) +{ + /* No special bus mastering setup handling */ +} + +/* the next one is stolen from the alpha port... */ + +void __init +pcibios_update_irq(struct pci_dev *dev, int irq) +{ + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); +} + +int pcibios_enable_device(struct pci_dev *dev, int mask) +{ + u16 cmd, old_cmd; + int idx; + struct resource *r; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + old_cmd = cmd; + for (idx=0; idx<6; idx++) { + r = &dev->resource[idx]; + if (!r->start && r->end) { + printk(KERN_ERR "PCI: Device %s not available because " + "of resource collisions\n", pci_name(dev)); + return -EINVAL; + } + if (r->flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + if (r->flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + } + if (cmd != old_cmd) { + printk("PCI: Enabling device %s (%04x -> %04x)\n", + pci_name(dev), old_cmd, cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + + return 0; +} + +#ifdef CONFIG_PROC_FS + +/* + * Return the index of the PCI controller for device pdev. + */ + +int +pci_controller_num(struct pci_dev *dev) +{ + struct pci_controller *pci_ctrl = (struct pci_controller*) dev->sysdata; + return pci_ctrl->index; +} + +#endif /* CONFIG_PROC_FS */ + +/* + * Platform support for /proc/bus/pci/X/Y mmap()s, + * modelled on the sparc64 implementation by Dave Miller. + * -- paulus. + */ + +/* + * Adjust vm_pgoff of VMA such that it is the physical page offset + * corresponding to the 32-bit pci bus offset for DEV requested by the user. + * + * Basically, the user finds the base address for his device which he wishes + * to mmap. They read the 32-bit value from the config space base register, + * add whatever PAGE_SIZE multiple offset they wish, and feed this into the + * offset parameter of mmap on /proc/bus/pci/XXX for that device. + * + * Returns negative error code on failure, zero on success. + */ +static __inline__ int +__pci_mmap_make_offset(struct pci_dev *dev, struct vm_area_struct *vma, + enum pci_mmap_state mmap_state) +{ + struct pci_controller *pci_ctrl = (struct pci_controller*) dev->sysdata; + unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; + unsigned long io_offset = 0; + int i, res_bit; + + if (pci_ctrl == 0) + return -EINVAL; /* should never happen */ + + /* If memory, add on the PCI bridge address offset */ + if (mmap_state == pci_mmap_mem) { + res_bit = IORESOURCE_MEM; + } else { + io_offset = (unsigned long)pci_ctrl->io_space.base; + offset += io_offset; + res_bit = IORESOURCE_IO; + } + + /* + * Check that the offset requested corresponds to one of the + * resources of the device. + */ + for (i = 0; i <= PCI_ROM_RESOURCE; i++) { + struct resource *rp = &dev->resource[i]; + int flags = rp->flags; + + /* treat ROM as memory (should be already) */ + if (i == PCI_ROM_RESOURCE) + flags |= IORESOURCE_MEM; + + /* Active and same type? */ + if ((flags & res_bit) == 0) + continue; + + /* In the range of this resource? */ + if (offset < (rp->start & PAGE_MASK) || offset > rp->end) + continue; + + /* found it! construct the final physical address */ + if (mmap_state == pci_mmap_io) + offset += pci_ctrl->io_space.start - io_offset; + vma->vm_pgoff = offset >> PAGE_SHIFT; + return 0; + } + + return -EINVAL; +} + +/* + * Set vm_page_prot of VMA, as appropriate for this architecture, for a pci + * device mapping. + */ +static __inline__ void +__pci_mmap_set_pgprot(struct pci_dev *dev, struct vm_area_struct *vma, + enum pci_mmap_state mmap_state, int write_combine) +{ + int prot = pgprot_val(vma->vm_page_prot); + + /* Set to write-through */ + prot &= ~_PAGE_NO_CACHE; +#if 0 + if (!write_combine) + prot |= _PAGE_WRITETHRU; +#endif + vma->vm_page_prot = __pgprot(prot); +} + +/* + * Perform the actual remap of the pages for a PCI device mapping, as + * appropriate for this architecture. The region in the process to map + * is described by vm_start and vm_end members of VMA, the base physical + * address is found in vm_pgoff. + * The pci device structure is provided so that architectures may make mapping + * decisions on a per-device or per-bus basis. + * + * Returns a negative error code on failure, zero on success. + */ +int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, + enum pci_mmap_state mmap_state, + int write_combine) +{ + int ret; + + ret = __pci_mmap_make_offset(dev, vma, mmap_state); + if (ret < 0) + return ret; + + __pci_mmap_set_pgprot(dev, vma, mmap_state, write_combine); + + ret = io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, + vma->vm_end - vma->vm_start,vma->vm_page_prot); + + return ret; +} diff --git a/arch/xtensa/kernel/platform.c b/arch/xtensa/kernel/platform.c new file mode 100644 index 00000000..1b91a97f --- /dev/null +++ b/arch/xtensa/kernel/platform.c @@ -0,0 +1,47 @@ +/* + * arch/xtensa/kernel/platform.c + * + * Default platform functions. + * + * 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) 2005 Tensilica Inc. + * + * Chris Zankel <chris@zankel.net> + */ + +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/time.h> +#include <asm/platform.h> +#include <asm/timex.h> +#include <asm/param.h> /* HZ */ + +#define _F(r,f,a,b) \ + r __platform_##f a b; \ + r platform_##f a __attribute__((weak, alias("__platform_"#f))) + +/* + * Default functions that are used if no platform specific function is defined. + * (Please, refer to include/asm-xtensa/platform.h for more information) + */ + +_F(void, setup, (char** cmd), { }); +_F(void, init_irq, (void), { }); +_F(void, restart, (void), { while(1); }); +_F(void, halt, (void), { while(1); }); +_F(void, power_off, (void), { while(1); }); +_F(void, idle, (void), { __asm__ __volatile__ ("waiti 0" ::: "memory"); }); +_F(void, heartbeat, (void), { }); +_F(int, pcibios_fixup, (void), { return 0; }); + +#ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT +_F(void, calibrate_ccount, (void), +{ + printk ("ERROR: Cannot calibrate cpu frequency! Assuming 100MHz.\n"); + ccount_per_jiffy = 100 * (1000000UL/HZ); +}); +#endif + diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c new file mode 100644 index 00000000..6a2d6edf --- /dev/null +++ b/arch/xtensa/kernel/process.c @@ -0,0 +1,336 @@ +/* + * arch/xtensa/kernel/process.c + * + * Xtensa Processor version. + * + * 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) 2001 - 2005 Tensilica Inc. + * + * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com> + * Chris Zankel <chris@zankel.net> + * Marc Gauthier <marc@tensilica.com, marc@alumni.uwaterloo.ca> + * Kevin Chea + */ + +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/smp.h> +#include <linux/stddef.h> +#include <linux/unistd.h> +#include <linux/ptrace.h> +#include <linux/elf.h> +#include <linux/init.h> +#include <linux/prctl.h> +#include <linux/init_task.h> +#include <linux/module.h> +#include <linux/mqueue.h> +#include <linux/fs.h> +#include <linux/slab.h> + +#include <asm/pgtable.h> +#include <asm/uaccess.h> +#include <asm/io.h> +#include <asm/processor.h> +#include <asm/platform.h> +#include <asm/mmu.h> +#include <asm/irq.h> +#include <linux/atomic.h> +#include <asm/asm-offsets.h> +#include <asm/regs.h> + +extern void ret_from_fork(void); + +struct task_struct *current_set[NR_CPUS] = {&init_task, }; + +void (*pm_power_off)(void) = NULL; +EXPORT_SYMBOL(pm_power_off); + + +#if XTENSA_HAVE_COPROCESSORS + +void coprocessor_release_all(struct thread_info *ti) +{ + unsigned long cpenable; + int i; + + /* Make sure we don't switch tasks during this operation. */ + + preempt_disable(); + + /* Walk through all cp owners and release it for the requested one. */ + + cpenable = ti->cpenable; + + for (i = 0; i < XCHAL_CP_MAX; i++) { + if (coprocessor_owner[i] == ti) { + coprocessor_owner[i] = 0; + cpenable &= ~(1 << i); + } + } + + ti->cpenable = cpenable; + coprocessor_clear_cpenable(); + + preempt_enable(); +} + +void coprocessor_flush_all(struct thread_info *ti) +{ + unsigned long cpenable; + int i; + + preempt_disable(); + + cpenable = ti->cpenable; + + for (i = 0; i < XCHAL_CP_MAX; i++) { + if ((cpenable & 1) != 0 && coprocessor_owner[i] == ti) + coprocessor_flush(ti, i); + cpenable >>= 1; + } + + preempt_enable(); +} + +#endif + + +/* + * Powermanagement idle function, if any is provided by the platform. + */ + +void cpu_idle(void) +{ + local_irq_enable(); + + /* endless idle loop with no priority at all */ + while (1) { + while (!need_resched()) + platform_idle(); + schedule_preempt_disabled(); + } +} + +/* + * This is called when the thread calls exit(). + */ +void exit_thread(void) +{ +#if XTENSA_HAVE_COPROCESSORS + coprocessor_release_all(current_thread_info()); +#endif +} + +/* + * Flush thread state. This is called when a thread does an execve() + * Note that we flush coprocessor registers for the case execve fails. + */ +void flush_thread(void) +{ +#if XTENSA_HAVE_COPROCESSORS + struct thread_info *ti = current_thread_info(); + coprocessor_flush_all(ti); + coprocessor_release_all(ti); +#endif +} + +/* + * This is called before the thread is copied. + */ +void prepare_to_copy(struct task_struct *tsk) +{ +#if XTENSA_HAVE_COPROCESSORS + coprocessor_flush_all(task_thread_info(tsk)); +#endif +} + +/* + * Copy thread. + * + * The stack layout for the new thread looks like this: + * + * +------------------------+ <- sp in childregs (= tos) + * | childregs | + * +------------------------+ <- thread.sp = sp in dummy-frame + * | dummy-frame | (saved in dummy-frame spill-area) + * +------------------------+ + * + * We create a dummy frame to return to ret_from_fork: + * a0 points to ret_from_fork (simulating a call4) + * sp points to itself (thread.sp) + * a2, a3 are unused. + * + * Note: This is a pristine frame, so we don't need any spill region on top of + * childregs. + */ + +int copy_thread(unsigned long clone_flags, unsigned long usp, + unsigned long unused, + struct task_struct * p, struct pt_regs * regs) +{ + struct pt_regs *childregs; + struct thread_info *ti; + unsigned long tos; + int user_mode = user_mode(regs); + + /* Set up new TSS. */ + tos = (unsigned long)task_stack_page(p) + THREAD_SIZE; + if (user_mode) + childregs = (struct pt_regs*)(tos - PT_USER_SIZE); + else + childregs = (struct pt_regs*)tos - 1; + + *childregs = *regs; + + /* Create a call4 dummy-frame: a0 = 0, a1 = childregs. */ + *((int*)childregs - 3) = (unsigned long)childregs; + *((int*)childregs - 4) = 0; + + childregs->areg[1] = tos; + childregs->areg[2] = 0; + p->set_child_tid = p->clear_child_tid = NULL; + p->thread.ra = MAKE_RA_FOR_CALL((unsigned long)ret_from_fork, 0x1); + p->thread.sp = (unsigned long)childregs; + + if (user_mode(regs)) { + + int len = childregs->wmask & ~0xf; + childregs->areg[1] = usp; + memcpy(&childregs->areg[XCHAL_NUM_AREGS - len/4], + ®s->areg[XCHAL_NUM_AREGS - len/4], len); +// FIXME: we need to set THREADPTR in thread_info... + if (clone_flags & CLONE_SETTLS) + childregs->areg[2] = childregs->areg[6]; + + } else { + /* In kernel space, we start a new thread with a new stack. */ + childregs->wmask = 1; + } + +#if (XTENSA_HAVE_COPROCESSORS || XTENSA_HAVE_IO_PORTS) + ti = task_thread_info(p); + ti->cpenable = 0; +#endif + + return 0; +} + + +/* + * These bracket the sleeping functions.. + */ + +unsigned long get_wchan(struct task_struct *p) +{ + unsigned long sp, pc; + unsigned long stack_page = (unsigned long) task_stack_page(p); + int count = 0; + + if (!p || p == current || p->state == TASK_RUNNING) + return 0; + + sp = p->thread.sp; + pc = MAKE_PC_FROM_RA(p->thread.ra, p->thread.sp); + + do { + if (sp < stack_page + sizeof(struct task_struct) || + sp >= (stack_page + THREAD_SIZE) || + pc == 0) + return 0; + if (!in_sched_functions(pc)) + return pc; + + /* Stack layout: sp-4: ra, sp-3: sp' */ + + pc = MAKE_PC_FROM_RA(*(unsigned long*)sp - 4, sp); + sp = *(unsigned long *)sp - 3; + } while (count++ < 16); + return 0; +} + +/* + * xtensa_gregset_t and 'struct pt_regs' are vastly different formats + * of processor registers. Besides different ordering, + * xtensa_gregset_t contains non-live register information that + * 'struct pt_regs' does not. Exception handling (primarily) uses + * 'struct pt_regs'. Core files and ptrace use xtensa_gregset_t. + * + */ + +void xtensa_elf_core_copy_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs) +{ + unsigned long wb, ws, wm; + int live, last; + + wb = regs->windowbase; + ws = regs->windowstart; + wm = regs->wmask; + ws = ((ws >> wb) | (ws << (WSBITS - wb))) & ((1 << WSBITS) - 1); + + /* Don't leak any random bits. */ + + memset(elfregs, 0, sizeof (elfregs)); + + /* Note: PS.EXCM is not set while user task is running; its + * being set in regs->ps is for exception handling convenience. + */ + + elfregs->pc = regs->pc; + elfregs->ps = (regs->ps & ~(1 << PS_EXCM_BIT)); + elfregs->lbeg = regs->lbeg; + elfregs->lend = regs->lend; + elfregs->lcount = regs->lcount; + elfregs->sar = regs->sar; + elfregs->windowstart = ws; + + live = (wm & 2) ? 4 : (wm & 4) ? 8 : (wm & 8) ? 12 : 16; + last = XCHAL_NUM_AREGS - (wm >> 4) * 4; + memcpy(elfregs->a, regs->areg, live * 4); + memcpy(elfregs->a + last, regs->areg + last, (wm >> 4) * 16); +} + +int dump_fpu(void) +{ + return 0; +} + +asmlinkage +long xtensa_clone(unsigned long clone_flags, unsigned long newsp, + void __user *parent_tid, void *child_tls, + void __user *child_tid, long a5, + struct pt_regs *regs) +{ + if (!newsp) + newsp = regs->areg[1]; + return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid); +} + +/* + * xtensa_execve() executes a new program. + */ + +asmlinkage +long xtensa_execve(const char __user *name, + const char __user *const __user *argv, + const char __user *const __user *envp, + long a3, long a4, long a5, + struct pt_regs *regs) +{ + long error; + char * filename; + + filename = getname(name); + error = PTR_ERR(filename); + if (IS_ERR(filename)) + goto out; + error = do_execve(filename, argv, envp, regs); + putname(filename); +out: + return error; +} + diff --git a/arch/xtensa/kernel/ptrace.c b/arch/xtensa/kernel/ptrace.c new file mode 100644 index 00000000..33eea4c1 --- /dev/null +++ b/arch/xtensa/kernel/ptrace.c @@ -0,0 +1,346 @@ +// TODO some minor issues +/* + * 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) 2001 - 2007 Tensilica Inc. + * + * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com> + * Chris Zankel <chris@zankel.net> + * Scott Foehner<sfoehner@yahoo.com>, + * Kevin Chea + * Marc Gauthier<marc@tensilica.com> <marc@alumni.uwaterloo.ca> + */ + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/errno.h> +#include <linux/ptrace.h> +#include <linux/smp.h> +#include <linux/security.h> +#include <linux/signal.h> + +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/uaccess.h> +#include <asm/ptrace.h> +#include <asm/elf.h> +#include <asm/coprocessor.h> + + +void user_enable_single_step(struct task_struct *child) +{ + child->ptrace |= PT_SINGLESTEP; +} + +void user_disable_single_step(struct task_struct *child) +{ + child->ptrace &= ~PT_SINGLESTEP; +} + +/* + * Called by kernel/ptrace.c when detaching to disable single stepping. + */ + +void ptrace_disable(struct task_struct *child) +{ + /* Nothing to do.. */ +} + +int ptrace_getregs(struct task_struct *child, void __user *uregs) +{ + struct pt_regs *regs = task_pt_regs(child); + xtensa_gregset_t __user *gregset = uregs; + unsigned long wm = regs->wmask; + unsigned long wb = regs->windowbase; + int live, i; + + if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t))) + return -EIO; + + __put_user(regs->pc, &gregset->pc); + __put_user(regs->ps & ~(1 << PS_EXCM_BIT), &gregset->ps); + __put_user(regs->lbeg, &gregset->lbeg); + __put_user(regs->lend, &gregset->lend); + __put_user(regs->lcount, &gregset->lcount); + __put_user(regs->windowstart, &gregset->windowstart); + __put_user(regs->windowbase, &gregset->windowbase); + + live = (wm & 2) ? 4 : (wm & 4) ? 8 : (wm & 8) ? 12 : 16; + + for (i = 0; i < live; i++) + __put_user(regs->areg[i],gregset->a+((wb*4+i)%XCHAL_NUM_AREGS)); + for (i = XCHAL_NUM_AREGS - (wm >> 4) * 4; i < XCHAL_NUM_AREGS; i++) + __put_user(regs->areg[i],gregset->a+((wb*4+i)%XCHAL_NUM_AREGS)); + + return 0; +} + +int ptrace_setregs(struct task_struct *child, void __user *uregs) +{ + struct pt_regs *regs = task_pt_regs(child); + xtensa_gregset_t *gregset = uregs; + const unsigned long ps_mask = PS_CALLINC_MASK | PS_OWB_MASK; + unsigned long ps; + unsigned long wb; + + if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t))) + return -EIO; + + __get_user(regs->pc, &gregset->pc); + __get_user(ps, &gregset->ps); + __get_user(regs->lbeg, &gregset->lbeg); + __get_user(regs->lend, &gregset->lend); + __get_user(regs->lcount, &gregset->lcount); + __get_user(regs->windowstart, &gregset->windowstart); + __get_user(wb, &gregset->windowbase); + + regs->ps = (regs->ps & ~ps_mask) | (ps & ps_mask) | (1 << PS_EXCM_BIT); + + if (wb >= XCHAL_NUM_AREGS / 4) + return -EFAULT; + + regs->windowbase = wb; + + if (wb != 0 && __copy_from_user(regs->areg + XCHAL_NUM_AREGS - wb * 4, + gregset->a, wb * 16)) + return -EFAULT; + + if (__copy_from_user(regs->areg, gregset->a + wb*4, (WSBITS-wb) * 16)) + return -EFAULT; + + return 0; +} + + +int ptrace_getxregs(struct task_struct *child, void __user *uregs) +{ + struct pt_regs *regs = task_pt_regs(child); + struct thread_info *ti = task_thread_info(child); + elf_xtregs_t __user *xtregs = uregs; + int ret = 0; + + if (!access_ok(VERIFY_WRITE, uregs, sizeof(elf_xtregs_t))) + return -EIO; + +#if XTENSA_HAVE_COPROCESSORS + /* Flush all coprocessor registers to memory. */ + coprocessor_flush_all(ti); + ret |= __copy_to_user(&xtregs->cp0, &ti->xtregs_cp, + sizeof(xtregs_coprocessor_t)); +#endif + ret |= __copy_to_user(&xtregs->opt, ®s->xtregs_opt, + sizeof(xtregs->opt)); + ret |= __copy_to_user(&xtregs->user,&ti->xtregs_user, + sizeof(xtregs->user)); + + return ret ? -EFAULT : 0; +} + +int ptrace_setxregs(struct task_struct *child, void __user *uregs) +{ + struct thread_info *ti = task_thread_info(child); + struct pt_regs *regs = task_pt_regs(child); + elf_xtregs_t *xtregs = uregs; + int ret = 0; + + if (!access_ok(VERIFY_READ, uregs, sizeof(elf_xtregs_t))) + return -EFAULT; + +#if XTENSA_HAVE_COPROCESSORS + /* Flush all coprocessors before we overwrite them. */ + coprocessor_flush_all(ti); + coprocessor_release_all(ti); + + ret |= __copy_from_user(&ti->xtregs_cp, &xtregs->cp0, + sizeof(xtregs_coprocessor_t)); +#endif + ret |= __copy_from_user(®s->xtregs_opt, &xtregs->opt, + sizeof(xtregs->opt)); + ret |= __copy_from_user(&ti->xtregs_user, &xtregs->user, + sizeof(xtregs->user)); + + return ret ? -EFAULT : 0; +} + +int ptrace_peekusr(struct task_struct *child, long regno, long __user *ret) +{ + struct pt_regs *regs; + unsigned long tmp; + + regs = task_pt_regs(child); + tmp = 0; /* Default return value. */ + + switch(regno) { + + case REG_AR_BASE ... REG_AR_BASE + XCHAL_NUM_AREGS - 1: + tmp = regs->areg[regno - REG_AR_BASE]; + break; + + case REG_A_BASE ... REG_A_BASE + 15: + tmp = regs->areg[regno - REG_A_BASE]; + break; + + case REG_PC: + tmp = regs->pc; + break; + + case REG_PS: + /* Note: PS.EXCM is not set while user task is running; + * its being set in regs is for exception handling + * convenience. */ + tmp = (regs->ps & ~(1 << PS_EXCM_BIT)); + break; + + case REG_WB: + break; /* tmp = 0 */ + + case REG_WS: + { + unsigned long wb = regs->windowbase; + unsigned long ws = regs->windowstart; + tmp = ((ws>>wb) | (ws<<(WSBITS-wb))) & ((1<<WSBITS)-1); + break; + } + case REG_LBEG: + tmp = regs->lbeg; + break; + + case REG_LEND: + tmp = regs->lend; + break; + + case REG_LCOUNT: + tmp = regs->lcount; + break; + + case REG_SAR: + tmp = regs->sar; + break; + + case SYSCALL_NR: + tmp = regs->syscall; + break; + + default: + return -EIO; + } + return put_user(tmp, ret); +} + +int ptrace_pokeusr(struct task_struct *child, long regno, long val) +{ + struct pt_regs *regs; + regs = task_pt_regs(child); + + switch (regno) { + case REG_AR_BASE ... REG_AR_BASE + XCHAL_NUM_AREGS - 1: + regs->areg[regno - REG_AR_BASE] = val; + break; + + case REG_A_BASE ... REG_A_BASE + 15: + regs->areg[regno - REG_A_BASE] = val; + break; + + case REG_PC: + regs->pc = val; + break; + + case SYSCALL_NR: + regs->syscall = val; + break; + + default: + return -EIO; + } + return 0; +} + +long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) +{ + int ret = -EPERM; + void __user *datap = (void __user *) data; + + switch (request) { + case PTRACE_PEEKTEXT: /* read word at location addr. */ + case PTRACE_PEEKDATA: + ret = generic_ptrace_peekdata(child, addr, data); + break; + + case PTRACE_PEEKUSR: /* read register specified by addr. */ + ret = ptrace_peekusr(child, addr, datap); + break; + + case PTRACE_POKETEXT: /* write the word at location addr. */ + case PTRACE_POKEDATA: + ret = generic_ptrace_pokedata(child, addr, data); + break; + + case PTRACE_POKEUSR: /* write register specified by addr. */ + ret = ptrace_pokeusr(child, addr, data); + break; + + case PTRACE_GETREGS: + ret = ptrace_getregs(child, datap); + break; + + case PTRACE_SETREGS: + ret = ptrace_setregs(child, datap); + break; + + case PTRACE_GETXTREGS: + ret = ptrace_getxregs(child, datap); + break; + + case PTRACE_SETXTREGS: + ret = ptrace_setxregs(child, datap); + break; + + default: + ret = ptrace_request(child, request, addr, data); + break; + } + + return ret; +} + +void do_syscall_trace(void) +{ + /* + * The 0x80 provides a way for the tracing parent to distinguish + * between a syscall stop and SIGTRAP delivery + */ + ptrace_notify(SIGTRAP|((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0)); + + /* + * 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 (current->exit_code) { + send_sig(current->exit_code, current, 1); + current->exit_code = 0; + } +} + +void do_syscall_trace_enter(struct pt_regs *regs) +{ + if (test_thread_flag(TIF_SYSCALL_TRACE) + && (current->ptrace & PT_PTRACED)) + do_syscall_trace(); + +#if 0 + audit_syscall_entry(current, AUDIT_ARCH_XTENSA..); +#endif +} + +void do_syscall_trace_leave(struct pt_regs *regs) +{ + if ((test_thread_flag(TIF_SYSCALL_TRACE)) + && (current->ptrace & PT_PTRACED)) + do_syscall_trace(); +} + diff --git a/arch/xtensa/kernel/setup.c b/arch/xtensa/kernel/setup.c new file mode 100644 index 00000000..17e746f7 --- /dev/null +++ b/arch/xtensa/kernel/setup.c @@ -0,0 +1,480 @@ +/* + * arch/xtensa/kernel/setup.c + * + * 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 Linus Torvalds + * Copyright (C) 2001 - 2005 Tensilica Inc. + * + * Chris Zankel <chris@zankel.net> + * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com> + * Kevin Chea + * Marc Gauthier<marc@tensilica.com> <marc@alumni.uwaterloo.ca> + */ + +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/proc_fs.h> +#include <linux/screen_info.h> +#include <linux/bootmem.h> +#include <linux/kernel.h> + +#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE) +# include <linux/console.h> +#endif + +#ifdef CONFIG_RTC +# include <linux/timex.h> +#endif + +#ifdef CONFIG_PROC_FS +# include <linux/seq_file.h> +#endif + +#include <asm/bootparam.h> +#include <asm/pgtable.h> +#include <asm/processor.h> +#include <asm/timex.h> +#include <asm/platform.h> +#include <asm/page.h> +#include <asm/setup.h> +#include <asm/param.h> + +#include <platform/hardware.h> + +#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE) +struct screen_info screen_info = { 0, 24, 0, 0, 0, 80, 0, 0, 0, 24, 1, 16}; +#endif + +#ifdef CONFIG_BLK_DEV_FD +extern struct fd_ops no_fd_ops; +struct fd_ops *fd_ops; +#endif + +extern struct rtc_ops no_rtc_ops; +struct rtc_ops *rtc_ops; + +#ifdef CONFIG_BLK_DEV_INITRD +extern void *initrd_start; +extern void *initrd_end; +extern void *__initrd_start; +extern void *__initrd_end; +int initrd_is_mapped = 0; +extern int initrd_below_start_ok; +#endif + +unsigned char aux_device_present; +extern unsigned long loops_per_jiffy; + +/* Command line specified as configuration option. */ + +static char __initdata command_line[COMMAND_LINE_SIZE]; + +#ifdef CONFIG_CMDLINE_BOOL +static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE; +#endif + +sysmem_info_t __initdata sysmem; + +#ifdef CONFIG_BLK_DEV_INITRD +int initrd_is_mapped; +#endif + +#ifdef CONFIG_MMU +extern void init_mmu(void); +#else +static inline void init_mmu(void) { } +#endif + +extern void zones_init(void); + +/* + * Boot parameter parsing. + * + * The Xtensa port uses a list of variable-sized tags to pass data to + * the kernel. The first tag must be a BP_TAG_FIRST tag for the list + * to be recognised. The list is terminated with a zero-sized + * BP_TAG_LAST tag. + */ + +typedef struct tagtable { + u32 tag; + int (*parse)(const bp_tag_t*); +} tagtable_t; + +#define __tagtable(tag, fn) static tagtable_t __tagtable_##fn \ + __attribute__((unused, __section__(".taglist"))) = { tag, fn } + +/* parse current tag */ + +static int __init parse_tag_mem(const bp_tag_t *tag) +{ + meminfo_t *mi = (meminfo_t*)(tag->data); + + if (mi->type != MEMORY_TYPE_CONVENTIONAL) + return -1; + + if (sysmem.nr_banks >= SYSMEM_BANKS_MAX) { + printk(KERN_WARNING + "Ignoring memory bank 0x%08lx size %ldKB\n", + (unsigned long)mi->start, + (unsigned long)mi->end - (unsigned long)mi->start); + return -EINVAL; + } + sysmem.bank[sysmem.nr_banks].type = mi->type; + sysmem.bank[sysmem.nr_banks].start = PAGE_ALIGN(mi->start); + sysmem.bank[sysmem.nr_banks].end = mi->end & PAGE_SIZE; + sysmem.nr_banks++; + + return 0; +} + +__tagtable(BP_TAG_MEMORY, parse_tag_mem); + +#ifdef CONFIG_BLK_DEV_INITRD + +static int __init parse_tag_initrd(const bp_tag_t* tag) +{ + meminfo_t* mi; + mi = (meminfo_t*)(tag->data); + initrd_start = (void*)(mi->start); + initrd_end = (void*)(mi->end); + + return 0; +} + +__tagtable(BP_TAG_INITRD, parse_tag_initrd); + +#endif /* CONFIG_BLK_DEV_INITRD */ + +static int __init parse_tag_cmdline(const bp_tag_t* tag) +{ + strncpy(command_line, (char*)(tag->data), COMMAND_LINE_SIZE); + command_line[COMMAND_LINE_SIZE - 1] = '\0'; + return 0; +} + +__tagtable(BP_TAG_COMMAND_LINE, parse_tag_cmdline); + +static int __init parse_bootparam(const bp_tag_t* tag) +{ + extern tagtable_t __tagtable_begin, __tagtable_end; + tagtable_t *t; + + /* Boot parameters must start with a BP_TAG_FIRST tag. */ + + if (tag->id != BP_TAG_FIRST) { + printk(KERN_WARNING "Invalid boot parameters!\n"); + return 0; + } + + tag = (bp_tag_t*)((unsigned long)tag + sizeof(bp_tag_t) + tag->size); + + /* Parse all tags. */ + + while (tag != NULL && tag->id != BP_TAG_LAST) { + for (t = &__tagtable_begin; t < &__tagtable_end; t++) { + if (tag->id == t->tag) { + t->parse(tag); + break; + } + } + if (t == &__tagtable_end) + printk(KERN_WARNING "Ignoring tag " + "0x%08x\n", tag->id); + tag = (bp_tag_t*)((unsigned long)(tag + 1) + tag->size); + } + + return 0; +} + +/* + * Initialize architecture. (Early stage) + */ + +void __init init_arch(bp_tag_t *bp_start) +{ + +#ifdef CONFIG_BLK_DEV_INITRD + initrd_start = &__initrd_start; + initrd_end = &__initrd_end; +#endif + + sysmem.nr_banks = 0; + +#ifdef CONFIG_CMDLINE_BOOL + strcpy(command_line, default_command_line); +#endif + + /* Parse boot parameters */ + + if (bp_start) + parse_bootparam(bp_start); + + if (sysmem.nr_banks == 0) { + sysmem.nr_banks = 1; + sysmem.bank[0].start = PLATFORM_DEFAULT_MEM_START; + sysmem.bank[0].end = PLATFORM_DEFAULT_MEM_START + + PLATFORM_DEFAULT_MEM_SIZE; + } + + /* Early hook for platforms */ + + platform_init(bp_start); + + /* Initialize MMU. */ + + init_mmu(); +} + +/* + * Initialize system. Setup memory and reserve regions. + */ + +extern char _end; +extern char _stext; +extern char _WindowVectors_text_start; +extern char _WindowVectors_text_end; +extern char _DebugInterruptVector_literal_start; +extern char _DebugInterruptVector_text_end; +extern char _KernelExceptionVector_literal_start; +extern char _KernelExceptionVector_text_end; +extern char _UserExceptionVector_literal_start; +extern char _UserExceptionVector_text_end; +extern char _DoubleExceptionVector_literal_start; +extern char _DoubleExceptionVector_text_end; + +void __init setup_arch(char **cmdline_p) +{ + extern int mem_reserve(unsigned long, unsigned long, int); + extern void bootmem_init(void); + + memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE); + boot_command_line[COMMAND_LINE_SIZE-1] = '\0'; + *cmdline_p = command_line; + + /* Reserve some memory regions */ + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start < initrd_end) { + initrd_is_mapped = mem_reserve(__pa(initrd_start), + __pa(initrd_end), 0); + initrd_below_start_ok = 1; + } else { + initrd_start = 0; + } +#endif + + mem_reserve(__pa(&_stext),__pa(&_end), 1); + + mem_reserve(__pa(&_WindowVectors_text_start), + __pa(&_WindowVectors_text_end), 0); + + mem_reserve(__pa(&_DebugInterruptVector_literal_start), + __pa(&_DebugInterruptVector_text_end), 0); + + mem_reserve(__pa(&_KernelExceptionVector_literal_start), + __pa(&_KernelExceptionVector_text_end), 0); + + mem_reserve(__pa(&_UserExceptionVector_literal_start), + __pa(&_UserExceptionVector_text_end), 0); + + mem_reserve(__pa(&_DoubleExceptionVector_literal_start), + __pa(&_DoubleExceptionVector_text_end), 0); + + bootmem_init(); + + platform_setup(cmdline_p); + + + paging_init(); + zones_init(); + +#ifdef CONFIG_VT +# if defined(CONFIG_VGA_CONSOLE) + conswitchp = &vga_con; +# elif defined(CONFIG_DUMMY_CONSOLE) + conswitchp = &dummy_con; +# endif +#endif + +#ifdef CONFIG_PCI + platform_pcibios_init(); +#endif +} + +void machine_restart(char * cmd) +{ + platform_restart(); +} + +void machine_halt(void) +{ + platform_halt(); + while (1); +} + +void machine_power_off(void) +{ + platform_power_off(); + while (1); +} +#ifdef CONFIG_PROC_FS + +/* + * Display some core information through /proc/cpuinfo. + */ + +static int +c_show(struct seq_file *f, void *slot) +{ + /* high-level stuff */ + seq_printf(f,"processor\t: 0\n" + "vendor_id\t: Tensilica\n" + "model\t\t: Xtensa " XCHAL_HW_VERSION_NAME "\n" + "core ID\t\t: " XCHAL_CORE_ID "\n" + "build ID\t: 0x%x\n" + "byte order\t: %s\n" + "cpu MHz\t\t: %lu.%02lu\n" + "bogomips\t: %lu.%02lu\n", + XCHAL_BUILD_UNIQUE_ID, + XCHAL_HAVE_BE ? "big" : "little", + CCOUNT_PER_JIFFY/(1000000/HZ), + (CCOUNT_PER_JIFFY/(10000/HZ)) % 100, + loops_per_jiffy/(500000/HZ), + (loops_per_jiffy/(5000/HZ)) % 100); + + seq_printf(f,"flags\t\t: " +#if XCHAL_HAVE_NMI + "nmi " +#endif +#if XCHAL_HAVE_DEBUG + "debug " +# if XCHAL_HAVE_OCD + "ocd " +# endif +#endif +#if XCHAL_HAVE_DENSITY + "density " +#endif +#if XCHAL_HAVE_BOOLEANS + "boolean " +#endif +#if XCHAL_HAVE_LOOPS + "loop " +#endif +#if XCHAL_HAVE_NSA + "nsa " +#endif +#if XCHAL_HAVE_MINMAX + "minmax " +#endif +#if XCHAL_HAVE_SEXT + "sext " +#endif +#if XCHAL_HAVE_CLAMPS + "clamps " +#endif +#if XCHAL_HAVE_MAC16 + "mac16 " +#endif +#if XCHAL_HAVE_MUL16 + "mul16 " +#endif +#if XCHAL_HAVE_MUL32 + "mul32 " +#endif +#if XCHAL_HAVE_MUL32_HIGH + "mul32h " +#endif +#if XCHAL_HAVE_FP + "fpu " +#endif + "\n"); + + /* Registers. */ + seq_printf(f,"physical aregs\t: %d\n" + "misc regs\t: %d\n" + "ibreak\t\t: %d\n" + "dbreak\t\t: %d\n", + XCHAL_NUM_AREGS, + XCHAL_NUM_MISC_REGS, + XCHAL_NUM_IBREAK, + XCHAL_NUM_DBREAK); + + + /* Interrupt. */ + seq_printf(f,"num ints\t: %d\n" + "ext ints\t: %d\n" + "int levels\t: %d\n" + "timers\t\t: %d\n" + "debug level\t: %d\n", + XCHAL_NUM_INTERRUPTS, + XCHAL_NUM_EXTINTERRUPTS, + XCHAL_NUM_INTLEVELS, + XCHAL_NUM_TIMERS, + XCHAL_DEBUGLEVEL); + + /* Cache */ + seq_printf(f,"icache line size: %d\n" + "icache ways\t: %d\n" + "icache size\t: %d\n" + "icache flags\t: " +#if XCHAL_ICACHE_LINE_LOCKABLE + "lock" +#endif + "\n" + "dcache line size: %d\n" + "dcache ways\t: %d\n" + "dcache size\t: %d\n" + "dcache flags\t: " +#if XCHAL_DCACHE_IS_WRITEBACK + "writeback" +#endif +#if XCHAL_DCACHE_LINE_LOCKABLE + "lock" +#endif + "\n", + XCHAL_ICACHE_LINESIZE, + XCHAL_ICACHE_WAYS, + XCHAL_ICACHE_SIZE, + XCHAL_DCACHE_LINESIZE, + XCHAL_DCACHE_WAYS, + XCHAL_DCACHE_SIZE); + + return 0; +} + +/* + * We show only CPU #0 info. + */ +static void * +c_start(struct seq_file *f, loff_t *pos) +{ + return (void *) ((*pos == 0) ? (void *)1 : NULL); +} + +static void * +c_next(struct seq_file *f, void *v, loff_t *pos) +{ + return NULL; +} + +static void +c_stop(struct seq_file *f, void *v) +{ +} + +const struct seq_operations cpuinfo_op = +{ + start: c_start, + next: c_next, + stop: c_stop, + show: c_show +}; + +#endif /* CONFIG_PROC_FS */ + diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c new file mode 100644 index 00000000..d78869a0 --- /dev/null +++ b/arch/xtensa/kernel/signal.c @@ -0,0 +1,565 @@ +/* + * arch/xtensa/kernel/signal.c + * + * Default platform functions. + * + * 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) 2005, 2006 Tensilica Inc. + * Copyright (C) 1991, 1992 Linus Torvalds + * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson + * + * Chris Zankel <chris@zankel.net> + * Joe Taylor <joe@tensilica.com> + */ + +#include <linux/signal.h> +#include <linux/errno.h> +#include <linux/ptrace.h> +#include <linux/personality.h> +#include <linux/freezer.h> + +#include <asm/ucontext.h> +#include <asm/uaccess.h> +#include <asm/cacheflush.h> +#include <asm/coprocessor.h> +#include <asm/unistd.h> + +#define DEBUG_SIG 0 + +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + +asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); + +extern struct task_struct *coproc_owners[]; + +struct rt_sigframe +{ + struct siginfo info; + struct ucontext uc; + struct { + xtregs_opt_t opt; + xtregs_user_t user; +#if XTENSA_HAVE_COPROCESSORS + xtregs_coprocessor_t cp; +#endif + } xtregs; + unsigned char retcode[6]; + unsigned int window[4]; +}; + +/* + * Flush register windows stored in pt_regs to stack. + * Returns 1 for errors. + */ + +int +flush_window_regs_user(struct pt_regs *regs) +{ + const unsigned long ws = regs->windowstart; + const unsigned long wb = regs->windowbase; + unsigned long sp = 0; + unsigned long wm; + int err = 1; + int base; + + /* Return if no other frames. */ + + if (regs->wmask == 1) + return 0; + + /* Rotate windowmask and skip empty frames. */ + + wm = (ws >> wb) | (ws << (XCHAL_NUM_AREGS / 4 - wb)); + base = (XCHAL_NUM_AREGS / 4) - (regs->wmask >> 4); + + /* For call8 or call12 frames, we need the previous stack pointer. */ + + if ((regs->wmask & 2) == 0) + if (__get_user(sp, (int*)(regs->areg[base * 4 + 1] - 12))) + goto errout; + + /* Spill frames to stack. */ + + while (base < XCHAL_NUM_AREGS / 4) { + + int m = (wm >> base); + int inc = 0; + + /* Save registers a4..a7 (call8) or a4...a11 (call12) */ + + if (m & 2) { /* call4 */ + inc = 1; + + } else if (m & 4) { /* call8 */ + if (copy_to_user((void*)(sp - 32), + ®s->areg[(base + 1) * 4], 16)) + goto errout; + inc = 2; + + } else if (m & 8) { /* call12 */ + if (copy_to_user((void*)(sp - 48), + ®s->areg[(base + 1) * 4], 32)) + goto errout; + inc = 3; + } + + /* Save current frame a0..a3 under next SP */ + + sp = regs->areg[((base + inc) * 4 + 1) % XCHAL_NUM_AREGS]; + if (copy_to_user((void*)(sp - 16), ®s->areg[base * 4], 16)) + goto errout; + + /* Get current stack pointer for next loop iteration. */ + + sp = regs->areg[base * 4 + 1]; + base += inc; + } + + regs->wmask = 1; + regs->windowstart = 1 << wb; + + return 0; + +errout: + return err; +} + +/* + * Note: We don't copy double exception 'regs', we have to finish double exc. + * first before we return to signal handler! This dbl.exc.handler might cause + * another double exception, but I think we are fine as the situation is the + * same as if we had returned to the signal handerl and got an interrupt + * immediately... + */ + +static int +setup_sigcontext(struct rt_sigframe __user *frame, struct pt_regs *regs) +{ + struct sigcontext __user *sc = &frame->uc.uc_mcontext; + struct thread_info *ti = current_thread_info(); + int err = 0; + +#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x) + COPY(pc); + COPY(ps); + COPY(lbeg); + COPY(lend); + COPY(lcount); + COPY(sar); +#undef COPY + + err |= flush_window_regs_user(regs); + err |= __copy_to_user (sc->sc_a, regs->areg, 16 * 4); + err |= __put_user(0, &sc->sc_xtregs); + + if (err) + return err; + +#if XTENSA_HAVE_COPROCESSORS + coprocessor_flush_all(ti); + coprocessor_release_all(ti); + err |= __copy_to_user(&frame->xtregs.cp, &ti->xtregs_cp, + sizeof (frame->xtregs.cp)); +#endif + err |= __copy_to_user(&frame->xtregs.opt, ®s->xtregs_opt, + sizeof (xtregs_opt_t)); + err |= __copy_to_user(&frame->xtregs.user, &ti->xtregs_user, + sizeof (xtregs_user_t)); + + err |= __put_user(err ? NULL : &frame->xtregs, &sc->sc_xtregs); + + return err; +} + +static int +restore_sigcontext(struct pt_regs *regs, struct rt_sigframe __user *frame) +{ + struct sigcontext __user *sc = &frame->uc.uc_mcontext; + struct thread_info *ti = current_thread_info(); + unsigned int err = 0; + unsigned long ps; + +#define COPY(x) err |= __get_user(regs->x, &sc->sc_##x) + COPY(pc); + COPY(lbeg); + COPY(lend); + COPY(lcount); + COPY(sar); +#undef COPY + + /* All registers were flushed to stack. Start with a prestine frame. */ + + regs->wmask = 1; + regs->windowbase = 0; + regs->windowstart = 1; + + regs->syscall = -1; /* disable syscall checks */ + + /* For PS, restore only PS.CALLINC. + * Assume that all other bits are either the same as for the signal + * handler, or the user mode value doesn't matter (e.g. PS.OWB). + */ + err |= __get_user(ps, &sc->sc_ps); + regs->ps = (regs->ps & ~PS_CALLINC_MASK) | (ps & PS_CALLINC_MASK); + + /* Additional corruption checks */ + + if ((regs->lcount > 0) + && ((regs->lbeg > TASK_SIZE) || (regs->lend > TASK_SIZE)) ) + err = 1; + + err |= __copy_from_user(regs->areg, sc->sc_a, 16 * 4); + + if (err) + return err; + + /* The signal handler may have used coprocessors in which + * case they are still enabled. We disable them to force a + * reloading of the original task's CP state by the lazy + * context-switching mechanisms of CP exception handling. + * Also, we essentially discard any coprocessor state that the + * signal handler created. */ + +#if XTENSA_HAVE_COPROCESSORS + coprocessor_release_all(ti); + err |= __copy_from_user(&ti->xtregs_cp, &frame->xtregs.cp, + sizeof (frame->xtregs.cp)); +#endif + err |= __copy_from_user(&ti->xtregs_user, &frame->xtregs.user, + sizeof (xtregs_user_t)); + err |= __copy_from_user(®s->xtregs_opt, &frame->xtregs.opt, + sizeof (xtregs_opt_t)); + + return err; +} + + +/* + * Do a signal return; undo the signal stack. + */ + +asmlinkage long xtensa_rt_sigreturn(long a0, long a1, long a2, long a3, + long a4, long a5, struct pt_regs *regs) +{ + struct rt_sigframe __user *frame; + sigset_t set; + int ret; + + if (regs->depc > 64) + panic("rt_sigreturn in double exception!\n"); + + frame = (struct rt_sigframe __user *) regs->areg[1]; + + if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + + if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + set_current_blocked(&set); + + if (restore_sigcontext(regs, frame)) + goto badframe; + + ret = regs->areg[2]; + + if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->areg[1]) == -EFAULT) + goto badframe; + + return ret; + +badframe: + force_sig(SIGSEGV, current); + return 0; +} + + + +/* + * Set up a signal frame. + */ + +static int +gen_return_code(unsigned char *codemem) +{ + int err = 0; + + /* + * The 12-bit immediate is really split up within the 24-bit MOVI + * instruction. As long as the above system call numbers fit within + * 8-bits, the following code works fine. See the Xtensa ISA for + * details. + */ + +#if __NR_rt_sigreturn > 255 +# error Generating the MOVI instruction below breaks! +#endif + +#ifdef __XTENSA_EB__ /* Big Endian version */ + /* Generate instruction: MOVI a2, __NR_rt_sigreturn */ + err |= __put_user(0x22, &codemem[0]); + err |= __put_user(0x0a, &codemem[1]); + err |= __put_user(__NR_rt_sigreturn, &codemem[2]); + /* Generate instruction: SYSCALL */ + err |= __put_user(0x00, &codemem[3]); + err |= __put_user(0x05, &codemem[4]); + err |= __put_user(0x00, &codemem[5]); + +#elif defined __XTENSA_EL__ /* Little Endian version */ + /* Generate instruction: MOVI a2, __NR_rt_sigreturn */ + err |= __put_user(0x22, &codemem[0]); + err |= __put_user(0xa0, &codemem[1]); + err |= __put_user(__NR_rt_sigreturn, &codemem[2]); + /* Generate instruction: SYSCALL */ + err |= __put_user(0x00, &codemem[3]); + err |= __put_user(0x50, &codemem[4]); + err |= __put_user(0x00, &codemem[5]); +#else +# error Must use compiler for Xtensa processors. +#endif + + /* Flush generated code out of the data cache */ + + if (err == 0) { + __invalidate_icache_range((unsigned long)codemem, 6UL); + __flush_invalidate_dcache_range((unsigned long)codemem, 6UL); + } + + return err; +} + + +static int setup_frame(int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *set, struct pt_regs *regs) +{ + struct rt_sigframe *frame; + int err = 0; + int signal; + unsigned long sp, ra; + + sp = regs->areg[1]; + + if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp)) { + sp = current->sas_ss_sp + current->sas_ss_size; + } + + frame = (void *)((sp - sizeof(*frame)) & -16ul); + + if (regs->depc > 64) + panic ("Double exception sys_sigreturn\n"); + + 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; + + if (ka->sa.sa_flags & SA_SIGINFO) { + err |= copy_siginfo_to_user(&frame->info, info); + } + + /* Create the user context. */ + + 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->areg[1]), + &frame->uc.uc_stack.ss_flags); + err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); + err |= setup_sigcontext(frame, regs); + err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); + + if (ka->sa.sa_flags & SA_RESTORER) { + ra = (unsigned long)ka->sa.sa_restorer; + } else { + + /* Create sys_rt_sigreturn syscall in stack frame */ + + err |= gen_return_code(frame->retcode); + + if (err) { + goto give_sigsegv; + } + ra = (unsigned long) frame->retcode; + } + + /* + * Create signal handler execution context. + * Return context not modified until this point. + */ + + /* Set up registers for signal handler */ + start_thread(regs, (unsigned long) ka->sa.sa_handler, + (unsigned long) frame); + + /* Set up a stack frame for a call4 + * Note: PS.CALLINC is set to one by start_thread + */ + regs->areg[4] = (((unsigned long) ra) & 0x3fffffff) | 0x40000000; + regs->areg[6] = (unsigned long) signal; + regs->areg[7] = (unsigned long) &frame->info; + regs->areg[8] = (unsigned long) &frame->uc; + + /* Set access mode to USER_DS. Nomenclature is outdated, but + * functionality is used in uaccess.h + */ + set_fs(USER_DS); + +#if DEBUG_SIG + printk("SIG rt deliver (%s:%d): signal=%d sp=%p pc=%08x\n", + current->comm, current->pid, signal, frame, regs->pc); +#endif + + return 0; + +give_sigsegv: + force_sigsegv(sig, current); + return -EFAULT; +} + +/* + * Atomically swap in the new signal mask, and wait for a signal. + */ + +asmlinkage long xtensa_rt_sigsuspend(sigset_t __user *unewset, + size_t sigsetsize, + long a2, long a3, long a4, long a5, + 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); + saveset = current->blocked; + set_current_blocked(&newset); + + regs->areg[2] = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(regs, &saveset)) + return -EINTR; + } +} + +asmlinkage long xtensa_sigaltstack(const stack_t __user *uss, + stack_t __user *uoss, + long a2, long a3, long a4, long a5, + struct pt_regs *regs) +{ + return do_sigaltstack(uss, uoss, regs->areg[1]); +} + + + +/* + * 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; + struct k_sigaction ka; + + if (!user_mode(regs)) + return 0; + + if (try_to_freeze()) + goto no_signal; + + if (!oldset) + oldset = ¤t->blocked; + + task_pt_regs(current)->icountlevel = 0; + + signr = get_signal_to_deliver(&info, &ka, regs, NULL); + + if (signr > 0) { + int ret; + + /* Are we from a system call? */ + + if ((signed)regs->syscall >= 0) { + + /* If so, check system call restarting.. */ + + switch (regs->areg[2]) { + case -ERESTARTNOHAND: + case -ERESTART_RESTARTBLOCK: + regs->areg[2] = -EINTR; + break; + + case -ERESTARTSYS: + if (!(ka.sa.sa_flags & SA_RESTART)) { + regs->areg[2] = -EINTR; + break; + } + /* fallthrough */ + case -ERESTARTNOINTR: + regs->areg[2] = regs->syscall; + regs->pc -= 3; + break; + + default: + /* nothing to do */ + if (regs->areg[2] != 0) + break; + } + } + + /* Whee! Actually deliver the signal. */ + /* Set up the stack frame */ + ret = setup_frame(signr, &ka, &info, oldset, regs); + if (ret) + return ret; + + block_sigmask(&ka, signr); + if (current->ptrace & PT_SINGLESTEP) + task_pt_regs(current)->icountlevel = 1; + + return 1; + } + +no_signal: + /* Did we come from a system call? */ + if ((signed) regs->syscall >= 0) { + /* Restart the system call - no handlers present */ + switch (regs->areg[2]) { + case -ERESTARTNOHAND: + case -ERESTARTSYS: + case -ERESTARTNOINTR: + regs->areg[2] = regs->syscall; + regs->pc -= 3; + break; + case -ERESTART_RESTARTBLOCK: + regs->areg[2] = __NR_restart_syscall; + regs->pc -= 3; + break; + } + } + if (current->ptrace & PT_SINGLESTEP) + task_pt_regs(current)->icountlevel = 1; + return 0; +} + diff --git a/arch/xtensa/kernel/syscall.c b/arch/xtensa/kernel/syscall.c new file mode 100644 index 00000000..816e6d0d --- /dev/null +++ b/arch/xtensa/kernel/syscall.c @@ -0,0 +1,57 @@ +/* + * arch/xtensa/kernel/syscall.c + * + * 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) 2001 - 2005 Tensilica Inc. + * Copyright (C) 2000 Silicon Graphics, Inc. + * Copyright (C) 1995 - 2000 by Ralf Baechle + * + * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com> + * Marc Gauthier <marc@tensilica.com, marc@alumni.uwaterloo.ca> + * Chris Zankel <chris@zankel.net> + * Kevin Chea + * + */ +#include <asm/uaccess.h> +#include <asm/syscall.h> +#include <asm/unistd.h> +#include <linux/linkage.h> +#include <linux/stringify.h> +#include <linux/errno.h> +#include <linux/syscalls.h> +#include <linux/file.h> +#include <linux/fs.h> +#include <linux/mman.h> +#include <linux/shm.h> + +typedef void (*syscall_t)(void); + +syscall_t sys_call_table[__NR_syscall_count] /* FIXME __cacheline_aligned */= { + [0 ... __NR_syscall_count - 1] = (syscall_t)&sys_ni_syscall, + +#undef __SYSCALL +#define __SYSCALL(nr,symbol,nargs) [ nr ] = (syscall_t)symbol, +#undef _XTENSA_UNISTD_H +#undef __KERNEL_SYSCALLS__ +#include <asm/unistd.h> +}; + +asmlinkage long xtensa_shmat(int shmid, char __user *shmaddr, int shmflg) +{ + unsigned long ret; + long err; + + err = do_shmat(shmid, shmaddr, shmflg, &ret); + if (err) + return err; + return (long)ret; +} + +asmlinkage long xtensa_fadvise64_64(int fd, int advice, unsigned long long offset, unsigned long long len) +{ + return sys_fadvise64_64(fd, offset, len, advice); +} + diff --git a/arch/xtensa/kernel/time.c b/arch/xtensa/kernel/time.c new file mode 100644 index 00000000..ac62f9cf --- /dev/null +++ b/arch/xtensa/kernel/time.c @@ -0,0 +1,117 @@ +/* + * arch/xtensa/kernel/time.c + * + * Timer and clock support. + * + * 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) 2005 Tensilica Inc. + * + * Chris Zankel <chris@zankel.net> + */ + +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/clocksource.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/profile.h> +#include <linux/delay.h> + +#include <asm/timex.h> +#include <asm/platform.h> + +#ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT +unsigned long ccount_per_jiffy; /* per 1/HZ */ +unsigned long nsec_per_ccount; /* nsec per ccount increment */ +#endif + +static cycle_t ccount_read(void) +{ + return (cycle_t)get_ccount(); +} + +static struct clocksource ccount_clocksource = { + .name = "ccount", + .rating = 200, + .read = ccount_read, + .mask = CLOCKSOURCE_MASK(32), +}; + +static irqreturn_t timer_interrupt(int irq, void *dev_id); +static struct irqaction timer_irqaction = { + .handler = timer_interrupt, + .flags = IRQF_DISABLED, + .name = "timer", +}; + +void __init time_init(void) +{ +#ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT + printk("Calibrating CPU frequency "); + platform_calibrate_ccount(); + printk("%d.%02d MHz\n", (int)ccount_per_jiffy/(1000000/HZ), + (int)(ccount_per_jiffy/(10000/HZ))%100); +#endif + clocksource_register_hz(&ccount_clocksource, CCOUNT_PER_JIFFY * HZ); + + /* Initialize the linux timer interrupt. */ + + setup_irq(LINUX_TIMER_INT, &timer_irqaction); + set_linux_timer(get_ccount() + CCOUNT_PER_JIFFY); +} + +/* + * The timer interrupt is called HZ times per second. + */ + +irqreturn_t timer_interrupt (int irq, void *dev_id) +{ + + unsigned long next; + + next = get_linux_timer(); + +again: + while ((signed long)(get_ccount() - next) > 0) { + + profile_tick(CPU_PROFILING); +#ifndef CONFIG_SMP + update_process_times(user_mode(get_irq_regs())); +#endif + + xtime_update(1); /* Linux handler in kernel/time/timekeeping */ + + /* Note that writing CCOMPARE clears the interrupt. */ + + next += CCOUNT_PER_JIFFY; + set_linux_timer(next); + } + + /* Allow platform to do something useful (Wdog). */ + + platform_heartbeat(); + + /* Make sure we didn't miss any tick... */ + + if ((signed long)(get_ccount() - next) > 0) + goto again; + + return IRQ_HANDLED; +} + +#ifndef CONFIG_GENERIC_CALIBRATE_DELAY +void __cpuinit calibrate_delay(void) +{ + loops_per_jiffy = CCOUNT_PER_JIFFY; + printk("Calibrating delay loop (skipped)... " + "%lu.%02lu BogoMIPS preset\n", + loops_per_jiffy/(1000000/HZ), + (loops_per_jiffy/(10000/HZ)) % 100); +} +#endif diff --git a/arch/xtensa/kernel/traps.c b/arch/xtensa/kernel/traps.c new file mode 100644 index 00000000..bc1e14cf --- /dev/null +++ b/arch/xtensa/kernel/traps.c @@ -0,0 +1,527 @@ +/* + * arch/xtensa/kernel/traps.c + * + * Exception handling. + * + * Derived from code with the following copyrights: + * Copyright (C) 1994 - 1999 by Ralf Baechle + * Modified for R3000 by Paul M. Antoine, 1995, 1996 + * Complete output from die() by Ulf Carlsson, 1998 + * Copyright (C) 1999 Silicon Graphics, Inc. + * + * Essentially rewritten for the Xtensa architecture port. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + * + * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com> + * Chris Zankel <chris@zankel.net> + * Marc Gauthier<marc@tensilica.com, marc@alumni.uwaterloo.ca> + * Kevin Chea + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/stringify.h> +#include <linux/kallsyms.h> +#include <linux/delay.h> +#include <linux/hardirq.h> + +#include <asm/ptrace.h> +#include <asm/timex.h> +#include <asm/uaccess.h> +#include <asm/pgtable.h> +#include <asm/processor.h> + +#ifdef CONFIG_KGDB +extern int gdb_enter; +extern int return_from_debug_flag; +#endif + +/* + * Machine specific interrupt handlers + */ + +extern void kernel_exception(void); +extern void user_exception(void); + +extern void fast_syscall_kernel(void); +extern void fast_syscall_user(void); +extern void fast_alloca(void); +extern void fast_unaligned(void); +extern void fast_second_level_miss(void); +extern void fast_store_prohibited(void); +extern void fast_coprocessor(void); + +extern void do_illegal_instruction (struct pt_regs*); +extern void do_interrupt (struct pt_regs*); +extern void do_unaligned_user (struct pt_regs*); +extern void do_multihit (struct pt_regs*, unsigned long); +extern void do_page_fault (struct pt_regs*, unsigned long); +extern void do_debug (struct pt_regs*); +extern void system_call (struct pt_regs*); + +/* + * The vector table must be preceded by a save area (which + * implies it must be in RAM, unless one places RAM immediately + * before a ROM and puts the vector at the start of the ROM (!)) + */ + +#define KRNL 0x01 +#define USER 0x02 + +#define COPROCESSOR(x) \ +{ EXCCAUSE_COPROCESSOR ## x ## _DISABLED, USER, fast_coprocessor } + +typedef struct { + int cause; + int fast; + void* handler; +} dispatch_init_table_t; + +static dispatch_init_table_t __initdata dispatch_init_table[] = { + +{ EXCCAUSE_ILLEGAL_INSTRUCTION, 0, do_illegal_instruction}, +{ EXCCAUSE_SYSTEM_CALL, KRNL, fast_syscall_kernel }, +{ EXCCAUSE_SYSTEM_CALL, USER, fast_syscall_user }, +{ EXCCAUSE_SYSTEM_CALL, 0, system_call }, +/* EXCCAUSE_INSTRUCTION_FETCH unhandled */ +/* EXCCAUSE_LOAD_STORE_ERROR unhandled*/ +{ EXCCAUSE_LEVEL1_INTERRUPT, 0, do_interrupt }, +{ EXCCAUSE_ALLOCA, USER|KRNL, fast_alloca }, +/* EXCCAUSE_INTEGER_DIVIDE_BY_ZERO unhandled */ +/* EXCCAUSE_PRIVILEGED unhandled */ +#if XCHAL_UNALIGNED_LOAD_EXCEPTION || XCHAL_UNALIGNED_STORE_EXCEPTION +#ifdef CONFIG_UNALIGNED_USER +{ EXCCAUSE_UNALIGNED, USER, fast_unaligned }, +#else +{ EXCCAUSE_UNALIGNED, 0, do_unaligned_user }, +#endif +{ EXCCAUSE_UNALIGNED, KRNL, fast_unaligned }, +#endif +#ifdef CONFIG_MMU +{ EXCCAUSE_ITLB_MISS, 0, do_page_fault }, +{ EXCCAUSE_ITLB_MISS, USER|KRNL, fast_second_level_miss}, +{ EXCCAUSE_ITLB_MULTIHIT, 0, do_multihit }, +{ EXCCAUSE_ITLB_PRIVILEGE, 0, do_page_fault }, +/* EXCCAUSE_SIZE_RESTRICTION unhandled */ +{ EXCCAUSE_FETCH_CACHE_ATTRIBUTE, 0, do_page_fault }, +{ EXCCAUSE_DTLB_MISS, USER|KRNL, fast_second_level_miss}, +{ EXCCAUSE_DTLB_MISS, 0, do_page_fault }, +{ EXCCAUSE_DTLB_MULTIHIT, 0, do_multihit }, +{ EXCCAUSE_DTLB_PRIVILEGE, 0, do_page_fault }, +/* EXCCAUSE_DTLB_SIZE_RESTRICTION unhandled */ +{ EXCCAUSE_STORE_CACHE_ATTRIBUTE, USER|KRNL, fast_store_prohibited }, +{ EXCCAUSE_STORE_CACHE_ATTRIBUTE, 0, do_page_fault }, +{ EXCCAUSE_LOAD_CACHE_ATTRIBUTE, 0, do_page_fault }, +#endif /* CONFIG_MMU */ +/* XCCHAL_EXCCAUSE_FLOATING_POINT unhandled */ +#if XTENSA_HAVE_COPROCESSOR(0) +COPROCESSOR(0), +#endif +#if XTENSA_HAVE_COPROCESSOR(1) +COPROCESSOR(1), +#endif +#if XTENSA_HAVE_COPROCESSOR(2) +COPROCESSOR(2), +#endif +#if XTENSA_HAVE_COPROCESSOR(3) +COPROCESSOR(3), +#endif +#if XTENSA_HAVE_COPROCESSOR(4) +COPROCESSOR(4), +#endif +#if XTENSA_HAVE_COPROCESSOR(5) +COPROCESSOR(5), +#endif +#if XTENSA_HAVE_COPROCESSOR(6) +COPROCESSOR(6), +#endif +#if XTENSA_HAVE_COPROCESSOR(7) +COPROCESSOR(7), +#endif +{ EXCCAUSE_MAPPED_DEBUG, 0, do_debug }, +{ -1, -1, 0 } + +}; + +/* The exception table <exc_table> serves two functions: + * 1. it contains three dispatch tables (fast_user, fast_kernel, default-c) + * 2. it is a temporary memory buffer for the exception handlers. + */ + +unsigned long exc_table[EXC_TABLE_SIZE/4]; + +void die(const char*, struct pt_regs*, long); + +static inline void +__die_if_kernel(const char *str, struct pt_regs *regs, long err) +{ + if (!user_mode(regs)) + die(str, regs, err); +} + +/* + * Unhandled Exceptions. Kill user task or panic if in kernel space. + */ + +void do_unhandled(struct pt_regs *regs, unsigned long exccause) +{ + __die_if_kernel("Caught unhandled exception - should not happen", + regs, SIGKILL); + + /* If in user mode, send SIGILL signal to current process */ + printk("Caught unhandled exception in '%s' " + "(pid = %d, pc = %#010lx) - should not happen\n" + "\tEXCCAUSE is %ld\n", + current->comm, task_pid_nr(current), regs->pc, exccause); + force_sig(SIGILL, current); +} + +/* + * Multi-hit exception. This if fatal! + */ + +void do_multihit(struct pt_regs *regs, unsigned long exccause) +{ + die("Caught multihit exception", regs, SIGKILL); +} + +/* + * Level-1 interrupt. + * We currently have no priority encoding. + */ + +unsigned long ignored_level1_interrupts; +extern void do_IRQ(int, struct pt_regs *); + +void do_interrupt (struct pt_regs *regs) +{ + unsigned long intread = get_sr (INTREAD); + unsigned long intenable = get_sr (INTENABLE); + int i, mask; + + /* Handle all interrupts (no priorities). + * (Clear the interrupt before processing, in case it's + * edge-triggered or software-generated) + */ + + for (i=0, mask = 1; i < XCHAL_NUM_INTERRUPTS; i++, mask <<= 1) { + if (mask & (intread & intenable)) { + set_sr (mask, INTCLEAR); + do_IRQ (i,regs); + } + } +} + +/* + * Illegal instruction. Fatal if in kernel space. + */ + +void +do_illegal_instruction(struct pt_regs *regs) +{ + __die_if_kernel("Illegal instruction in kernel", regs, SIGKILL); + + /* If in user mode, send SIGILL signal to current process. */ + + printk("Illegal Instruction in '%s' (pid = %d, pc = %#010lx)\n", + current->comm, task_pid_nr(current), regs->pc); + force_sig(SIGILL, current); +} + + +/* + * Handle unaligned memory accesses from user space. Kill task. + * + * If CONFIG_UNALIGNED_USER is not set, we don't allow unaligned memory + * accesses causes from user space. + */ + +#if XCHAL_UNALIGNED_LOAD_EXCEPTION || XCHAL_UNALIGNED_STORE_EXCEPTION +#ifndef CONFIG_UNALIGNED_USER +void +do_unaligned_user (struct pt_regs *regs) +{ + siginfo_t info; + + __die_if_kernel("Unhandled unaligned exception in kernel", + regs, SIGKILL); + + current->thread.bad_vaddr = regs->excvaddr; + current->thread.error_code = -3; + printk("Unaligned memory access to %08lx in '%s' " + "(pid = %d, pc = %#010lx)\n", + regs->excvaddr, current->comm, task_pid_nr(current), regs->pc); + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = BUS_ADRALN; + info.si_addr = (void *) regs->excvaddr; + force_sig_info(SIGSEGV, &info, current); + +} +#endif +#endif + +void +do_debug(struct pt_regs *regs) +{ +#ifdef CONFIG_KGDB + /* If remote debugging is configured AND enabled, we give control to + * kgdb. Otherwise, we fall through, perhaps giving control to the + * native debugger. + */ + + if (gdb_enter) { + extern void gdb_handle_exception(struct pt_regs *); + gdb_handle_exception(regs); + return_from_debug_flag = 1; + return; + } +#endif + + __die_if_kernel("Breakpoint in kernel", regs, SIGKILL); + + /* If in user mode, send SIGTRAP signal to current process */ + + force_sig(SIGTRAP, current); +} + + +/* + * Initialize dispatch tables. + * + * The exception vectors are stored compressed the __init section in the + * dispatch_init_table. This function initializes the following three tables + * from that compressed table: + * - fast user first dispatch table for user exceptions + * - fast kernel first dispatch table for kernel exceptions + * - default C-handler C-handler called by the default fast handler. + * + * See vectors.S for more details. + */ + +#define set_handler(idx,handler) (exc_table[idx] = (unsigned long) (handler)) + +void __init trap_init(void) +{ + int i; + + /* Setup default vectors. */ + + for(i = 0; i < 64; i++) { + set_handler(EXC_TABLE_FAST_USER/4 + i, user_exception); + set_handler(EXC_TABLE_FAST_KERNEL/4 + i, kernel_exception); + set_handler(EXC_TABLE_DEFAULT/4 + i, do_unhandled); + } + + /* Setup specific handlers. */ + + for(i = 0; dispatch_init_table[i].cause >= 0; i++) { + + int fast = dispatch_init_table[i].fast; + int cause = dispatch_init_table[i].cause; + void *handler = dispatch_init_table[i].handler; + + if (fast == 0) + set_handler (EXC_TABLE_DEFAULT/4 + cause, handler); + if (fast && fast & USER) + set_handler (EXC_TABLE_FAST_USER/4 + cause, handler); + if (fast && fast & KRNL) + set_handler (EXC_TABLE_FAST_KERNEL/4 + cause, handler); + } + + /* Initialize EXCSAVE_1 to hold the address of the exception table. */ + + i = (unsigned long)exc_table; + __asm__ __volatile__("wsr %0, "__stringify(EXCSAVE_1)"\n" : : "a" (i)); +} + +/* + * This function dumps the current valid window frame and other base registers. + */ + +void show_regs(struct pt_regs * regs) +{ + int i, wmask; + + wmask = regs->wmask & ~1; + + for (i = 0; i < 16; i++) { + if ((i % 8) == 0) + printk(KERN_INFO "a%02d:", i); + printk(KERN_CONT " %08lx", regs->areg[i]); + } + printk(KERN_CONT "\n"); + + printk("pc: %08lx, ps: %08lx, depc: %08lx, excvaddr: %08lx\n", + regs->pc, regs->ps, regs->depc, regs->excvaddr); + printk("lbeg: %08lx, lend: %08lx lcount: %08lx, sar: %08lx\n", + regs->lbeg, regs->lend, regs->lcount, regs->sar); + if (user_mode(regs)) + printk("wb: %08lx, ws: %08lx, wmask: %08lx, syscall: %ld\n", + regs->windowbase, regs->windowstart, regs->wmask, + regs->syscall); +} + +static __always_inline unsigned long *stack_pointer(struct task_struct *task) +{ + unsigned long *sp; + + if (!task || task == current) + __asm__ __volatile__ ("mov %0, a1\n" : "=a"(sp)); + else + sp = (unsigned long *)task->thread.sp; + + return sp; +} + +static inline void spill_registers(void) +{ + unsigned int a0, ps; + + __asm__ __volatile__ ( + "movi a14," __stringify (PS_EXCM_BIT) " | 1\n\t" + "mov a12, a0\n\t" + "rsr a13," __stringify(SAR) "\n\t" + "xsr a14," __stringify(PS) "\n\t" + "movi a0, _spill_registers\n\t" + "rsync\n\t" + "callx0 a0\n\t" + "mov a0, a12\n\t" + "wsr a13," __stringify(SAR) "\n\t" + "wsr a14," __stringify(PS) "\n\t" + :: "a" (&a0), "a" (&ps) + : "a2", "a3", "a4", "a7", "a11", "a12", "a13", "a14", "a15", "memory"); +} + +void show_trace(struct task_struct *task, unsigned long *sp) +{ + unsigned long a0, a1, pc; + unsigned long sp_start, sp_end; + + if (sp) + a1 = (unsigned long)sp; + else + a1 = (unsigned long)stack_pointer(task); + + sp_start = a1 & ~(THREAD_SIZE-1); + sp_end = sp_start + THREAD_SIZE; + + printk("Call Trace:"); +#ifdef CONFIG_KALLSYMS + printk("\n"); +#endif + spill_registers(); + + while (a1 > sp_start && a1 < sp_end) { + sp = (unsigned long*)a1; + + a0 = *(sp - 4); + a1 = *(sp - 3); + + if (a1 <= (unsigned long) sp) + break; + + pc = MAKE_PC_FROM_RA(a0, a1); + + if (kernel_text_address(pc)) { + printk(" [<%08lx>] ", pc); + print_symbol("%s\n", pc); + } + } + printk("\n"); +} + +/* + * This routine abuses get_user()/put_user() to reference pointers + * with at least a bit of error checking ... + */ + +static int kstack_depth_to_print = 24; + +void show_stack(struct task_struct *task, unsigned long *sp) +{ + int i = 0; + unsigned long *stack; + + if (!sp) + sp = stack_pointer(task); + stack = sp; + + printk("\nStack: "); + + for (i = 0; i < kstack_depth_to_print; i++) { + if (kstack_end(sp)) + break; + if (i && ((i % 8) == 0)) + printk("\n "); + printk("%08lx ", *sp++); + } + printk("\n"); + show_trace(task, stack); +} + +void dump_stack(void) +{ + show_stack(current, NULL); +} + +EXPORT_SYMBOL(dump_stack); + + +void show_code(unsigned int *pc) +{ + long i; + + printk("\nCode:"); + + for(i = -3 ; i < 6 ; i++) { + unsigned long insn; + if (__get_user(insn, pc + i)) { + printk(" (Bad address in pc)\n"); + break; + } + printk("%c%08lx%c",(i?' ':'<'),insn,(i?' ':'>')); + } +} + +DEFINE_SPINLOCK(die_lock); + +void die(const char * str, struct pt_regs * regs, long err) +{ + static int die_counter; + int nl = 0; + + console_verbose(); + spin_lock_irq(&die_lock); + + printk("%s: sig: %ld [#%d]\n", str, err, ++die_counter); +#ifdef CONFIG_PREEMPT + printk("PREEMPT "); + nl = 1; +#endif + if (nl) + printk("\n"); + show_regs(regs); + if (!user_mode(regs)) + show_stack(NULL, (unsigned long*)regs->areg[1]); + + add_taint(TAINT_DIE); + spin_unlock_irq(&die_lock); + + if (in_interrupt()) + panic("Fatal exception in interrupt"); + + if (panic_on_oops) + panic("Fatal exception"); + + do_exit(err); +} + + diff --git a/arch/xtensa/kernel/vectors.S b/arch/xtensa/kernel/vectors.S new file mode 100644 index 00000000..70066e35 --- /dev/null +++ b/arch/xtensa/kernel/vectors.S @@ -0,0 +1,468 @@ +/* + * arch/xtensa/kernel/vectors.S + * + * This file contains all exception vectors (user, kernel, and double), + * as well as the window vectors (overflow and underflow), and the debug + * vector. These are the primary vectors executed by the processor if an + * exception occurs. + * + * 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) 2005 Tensilica, Inc. + * + * Chris Zankel <chris@zankel.net> + * + */ + +/* + * We use a two-level table approach. The user and kernel exception vectors + * use a first-level dispatch table to dispatch the exception to a registered + * fast handler or the default handler, if no fast handler was registered. + * The default handler sets up a C-stack and dispatches the exception to a + * registerd C handler in the second-level dispatch table. + * + * Fast handler entry condition: + * + * a0: trashed, original value saved on stack (PT_AREG0) + * a1: a1 + * a2: new stack pointer, original value in depc + * a3: dispatch table + * depc: a2, original value saved on stack (PT_DEPC) + * excsave_1: a3 + * + * The value for PT_DEPC saved to stack also functions as a boolean to + * indicate that the exception is either a double or a regular exception: + * + * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception + * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception + * + * Note: Neither the kernel nor the user exception handler generate literals. + * + */ + +#include <linux/linkage.h> +#include <asm/ptrace.h> +#include <asm/current.h> +#include <asm/asm-offsets.h> +#include <asm/pgtable.h> +#include <asm/processor.h> +#include <asm/page.h> +#include <asm/thread_info.h> + +#define WINDOW_VECTORS_SIZE 0x180 + + +/* + * User exception vector. (Exceptions with PS.UM == 1, PS.EXCM == 0) + * + * We get here when an exception occurred while we were in userland. + * We switch to the kernel stack and jump to the first level handler + * associated to the exception cause. + * + * Note: the saved kernel stack pointer (EXC_TABLE_KSTK) is already + * decremented by PT_USER_SIZE. + */ + + .section .UserExceptionVector.text, "ax" + +ENTRY(_UserExceptionVector) + + xsr a3, EXCSAVE_1 # save a3 and get dispatch table + wsr a2, DEPC # save a2 + l32i a2, a3, EXC_TABLE_KSTK # load kernel stack to a2 + s32i a0, a2, PT_AREG0 # save a0 to ESF + rsr a0, EXCCAUSE # retrieve exception cause + s32i a0, a2, PT_DEPC # mark it as a regular exception + addx4 a0, a0, a3 # find entry in table + l32i a0, a0, EXC_TABLE_FAST_USER # load handler + jx a0 + +/* + * Kernel exception vector. (Exceptions with PS.UM == 0, PS.EXCM == 0) + * + * We get this exception when we were already in kernel space. + * We decrement the current stack pointer (kernel) by PT_SIZE and + * jump to the first-level handler associated with the exception cause. + * + * Note: we need to preserve space for the spill region. + */ + + .section .KernelExceptionVector.text, "ax" + +ENTRY(_KernelExceptionVector) + + xsr a3, EXCSAVE_1 # save a3, and get dispatch table + wsr a2, DEPC # save a2 + addi a2, a1, -16-PT_SIZE # adjust stack pointer + s32i a0, a2, PT_AREG0 # save a0 to ESF + rsr a0, EXCCAUSE # retrieve exception cause + s32i a0, a2, PT_DEPC # mark it as a regular exception + addx4 a0, a0, a3 # find entry in table + l32i a0, a0, EXC_TABLE_FAST_KERNEL # load handler address + jx a0 + + +/* + * Double exception vector (Exceptions with PS.EXCM == 1) + * We get this exception when another exception occurs while were are + * already in an exception, such as window overflow/underflow exception, + * or 'expected' exceptions, for example memory exception when we were trying + * to read data from an invalid address in user space. + * + * Note that this vector is never invoked for level-1 interrupts, because such + * interrupts are disabled (masked) when PS.EXCM is set. + * + * We decode the exception and take the appropriate action. However, the + * double exception vector is much more careful, because a lot more error + * cases go through the double exception vector than through the user and + * kernel exception vectors. + * + * Occasionally, the kernel expects a double exception to occur. This usually + * happens when accessing user-space memory with the user's permissions + * (l32e/s32e instructions). The kernel state, though, is not always suitable + * for immediate transfer of control to handle_double, where "normal" exception + * processing occurs. Also in kernel mode, TLB misses can occur if accessing + * vmalloc memory, possibly requiring repair in a double exception handler. + * + * The variable at TABLE_FIXUP offset from the pointer in EXCSAVE_1 doubles as + * a boolean variable and a pointer to a fixup routine. If the variable + * EXC_TABLE_FIXUP is non-zero, this handler jumps to that address. A value of + * zero indicates to use the default kernel/user exception handler. + * There is only one exception, when the value is identical to the exc_table + * label, the kernel is in trouble. This mechanism is used to protect critical + * sections, mainly when the handler writes to the stack to assert the stack + * pointer is valid. Once the fixup/default handler leaves that area, the + * EXC_TABLE_FIXUP variable is reset to the fixup handler or zero. + * + * Procedures wishing to use this mechanism should set EXC_TABLE_FIXUP to the + * nonzero address of a fixup routine before it could cause a double exception + * and reset it before it returns. + * + * Some other things to take care of when a fast exception handler doesn't + * specify a particular fixup handler but wants to use the default handlers: + * + * - The original stack pointer (in a1) must not be modified. The fast + * exception handler should only use a2 as the stack pointer. + * + * - If the fast handler manipulates the stack pointer (in a2), it has to + * register a valid fixup handler and cannot use the default handlers. + * + * - The handler can use any other generic register from a3 to a15, but it + * must save the content of these registers to stack (PT_AREG3...PT_AREGx) + * + * - These registers must be saved before a double exception can occur. + * + * - If we ever implement handling signals while in double exceptions, the + * number of registers a fast handler has saved (excluding a0 and a1) must + * be written to PT_AREG1. (1 if only a3 is used, 2 for a3 and a4, etc. ) + * + * The fixup handlers are special handlers: + * + * - Fixup entry conditions differ from regular exceptions: + * + * a0: DEPC + * a1: a1 + * a2: trashed, original value in EXC_TABLE_DOUBLE_A2 + * a3: exctable + * depc: a0 + * excsave_1: a3 + * + * - When the kernel enters the fixup handler, it still assumes it is in a + * critical section, so EXC_TABLE_FIXUP variable is set to exc_table. + * The fixup handler, therefore, has to re-register itself as the fixup + * handler before it returns from the double exception. + * + * - Fixup handler can share the same exception frame with the fast handler. + * The kernel stack pointer is not changed when entering the fixup handler. + * + * - Fixup handlers can jump to the default kernel and user exception + * handlers. Before it jumps, though, it has to setup a exception frame + * on stack. Because the default handler resets the register fixup handler + * the fixup handler must make sure that the default handler returns to + * it instead of the exception address, so it can re-register itself as + * the fixup handler. + * + * In case of a critical condition where the kernel cannot recover, we jump + * to unrecoverable_exception with the following entry conditions. + * All registers a0...a15 are unchanged from the last exception, except: + * + * a0: last address before we jumped to the unrecoverable_exception. + * excsave_1: a0 + * + * + * See the handle_alloca_user and spill_registers routines for example clients. + * + * FIXME: Note: we currently don't allow signal handling coming from a double + * exception, so the item markt with (*) is not required. + */ + + .section .DoubleExceptionVector.text, "ax" + .begin literal_prefix .DoubleExceptionVector + +ENTRY(_DoubleExceptionVector) + + /* Deliberately destroy excsave (don't assume it's value was valid). */ + + wsr a3, EXCSAVE_1 # save a3 + + /* Check for kernel double exception (usually fatal). */ + + rsr a3, PS + _bbci.l a3, PS_UM_BIT, .Lksp + + /* Check if we are currently handling a window exception. */ + /* Note: We don't need to indicate that we enter a critical section. */ + + xsr a0, DEPC # get DEPC, save a0 + + movi a3, XCHAL_WINDOW_VECTORS_VADDR + _bltu a0, a3, .Lfixup + addi a3, a3, WINDOW_VECTORS_SIZE + _bgeu a0, a3, .Lfixup + + /* Window overflow/underflow exception. Get stack pointer. */ + + mov a3, a2 + movi a2, exc_table + l32i a2, a2, EXC_TABLE_KSTK + + /* Check for overflow/underflow exception, jump if overflow. */ + + _bbci.l a0, 6, .Lovfl + + /* a0: depc, a1: a1, a2: kstk, a3: a2, depc: a0, excsave: a3 */ + + /* Restart window underflow exception. + * We return to the instruction in user space that caused the window + * underflow exception. Therefore, we change window base to the value + * before we entered the window underflow exception and prepare the + * registers to return as if we were coming from a regular exception + * by changing depc (in a0). + * Note: We can trash the current window frame (a0...a3) and depc! + */ + + wsr a2, DEPC # save stack pointer temporarily + rsr a0, PS + extui a0, a0, PS_OWB_SHIFT, 4 + wsr a0, WINDOWBASE + rsync + + /* We are now in the previous window frame. Save registers again. */ + + xsr a2, DEPC # save a2 and get stack pointer + s32i a0, a2, PT_AREG0 + + wsr a3, EXCSAVE_1 # save a3 + movi a3, exc_table + + rsr a0, EXCCAUSE + s32i a0, a2, PT_DEPC # mark it as a regular exception + addx4 a0, a0, a3 + l32i a0, a0, EXC_TABLE_FAST_USER + jx a0 + +.Lfixup:/* Check for a fixup handler or if we were in a critical section. */ + + /* a0: depc, a1: a1, a2: a2, a3: trashed, depc: a0, excsave1: a3 */ + + movi a3, exc_table + s32i a2, a3, EXC_TABLE_DOUBLE_SAVE # temporary variable + + /* Enter critical section. */ + + l32i a2, a3, EXC_TABLE_FIXUP + s32i a3, a3, EXC_TABLE_FIXUP + beq a2, a3, .Lunrecoverable_fixup # critical! + beqz a2, .Ldflt # no handler was registered + + /* a0: depc, a1: a1, a2: trash, a3: exctable, depc: a0, excsave: a3 */ + + jx a2 + +.Ldflt: /* Get stack pointer. */ + + l32i a3, a3, EXC_TABLE_DOUBLE_SAVE + addi a2, a3, -PT_USER_SIZE + +.Lovfl: /* Jump to default handlers. */ + + /* a0: depc, a1: a1, a2: kstk, a3: a2, depc: a0, excsave: a3 */ + + xsr a3, DEPC + s32i a0, a2, PT_DEPC + s32i a3, a2, PT_AREG0 + + /* a0: avail, a1: a1, a2: kstk, a3: avail, depc: a2, excsave: a3 */ + + movi a3, exc_table + rsr a0, EXCCAUSE + addx4 a0, a0, a3 + l32i a0, a0, EXC_TABLE_FAST_USER + jx a0 + + /* + * We only allow the ITLB miss exception if we are in kernel space. + * All other exceptions are unexpected and thus unrecoverable! + */ + +#ifdef CONFIG_MMU + .extern fast_second_level_miss_double_kernel + +.Lksp: /* a0: a0, a1: a1, a2: a2, a3: trashed, depc: depc, excsave: a3 */ + + rsr a3, EXCCAUSE + beqi a3, EXCCAUSE_ITLB_MISS, 1f + addi a3, a3, -EXCCAUSE_DTLB_MISS + bnez a3, .Lunrecoverable +1: movi a3, fast_second_level_miss_double_kernel + jx a3 +#else +.equ .Lksp, .Lunrecoverable +#endif + + /* Critical! We can't handle this situation. PANIC! */ + + .extern unrecoverable_exception + +.Lunrecoverable_fixup: + l32i a2, a3, EXC_TABLE_DOUBLE_SAVE + xsr a0, DEPC + +.Lunrecoverable: + rsr a3, EXCSAVE_1 + wsr a0, EXCSAVE_1 + movi a0, unrecoverable_exception + callx0 a0 + + .end literal_prefix + + +/* + * Debug interrupt vector + * + * There is not much space here, so simply jump to another handler. + * EXCSAVE[DEBUGLEVEL] has been set to that handler. + */ + + .section .DebugInterruptVector.text, "ax" + +ENTRY(_DebugInterruptVector) + xsr a0, EXCSAVE + XCHAL_DEBUGLEVEL + jx a0 + + + +/* Window overflow and underflow handlers. + * The handlers must be 64 bytes apart, first starting with the underflow + * handlers underflow-4 to underflow-12, then the overflow handlers + * overflow-4 to overflow-12. + * + * Note: We rerun the underflow handlers if we hit an exception, so + * we try to access any page that would cause a page fault early. + */ + + .section .WindowVectors.text, "ax" + + +/* 4-Register Window Overflow Vector (Handler) */ + + .align 64 +.global _WindowOverflow4 +_WindowOverflow4: + s32e a0, a5, -16 + s32e a1, a5, -12 + s32e a2, a5, -8 + s32e a3, a5, -4 + rfwo + + +/* 4-Register Window Underflow Vector (Handler) */ + + .align 64 +.global _WindowUnderflow4 +_WindowUnderflow4: + l32e a0, a5, -16 + l32e a1, a5, -12 + l32e a2, a5, -8 + l32e a3, a5, -4 + rfwu + + +/* 8-Register Window Overflow Vector (Handler) */ + + .align 64 +.global _WindowOverflow8 +_WindowOverflow8: + s32e a0, a9, -16 + l32e a0, a1, -12 + s32e a2, a9, -8 + s32e a1, a9, -12 + s32e a3, a9, -4 + s32e a4, a0, -32 + s32e a5, a0, -28 + s32e a6, a0, -24 + s32e a7, a0, -20 + rfwo + +/* 8-Register Window Underflow Vector (Handler) */ + + .align 64 +.global _WindowUnderflow8 +_WindowUnderflow8: + l32e a1, a9, -12 + l32e a0, a9, -16 + l32e a7, a1, -12 + l32e a2, a9, -8 + l32e a4, a7, -32 + l32e a3, a9, -4 + l32e a5, a7, -28 + l32e a6, a7, -24 + l32e a7, a7, -20 + rfwu + + +/* 12-Register Window Overflow Vector (Handler) */ + + .align 64 +.global _WindowOverflow12 +_WindowOverflow12: + s32e a0, a13, -16 + l32e a0, a1, -12 + s32e a1, a13, -12 + s32e a2, a13, -8 + s32e a3, a13, -4 + s32e a4, a0, -48 + s32e a5, a0, -44 + s32e a6, a0, -40 + s32e a7, a0, -36 + s32e a8, a0, -32 + s32e a9, a0, -28 + s32e a10, a0, -24 + s32e a11, a0, -20 + rfwo + +/* 12-Register Window Underflow Vector (Handler) */ + + .align 64 +.global _WindowUnderflow12 +_WindowUnderflow12: + l32e a1, a13, -12 + l32e a0, a13, -16 + l32e a11, a1, -12 + l32e a2, a13, -8 + l32e a4, a11, -48 + l32e a8, a11, -32 + l32e a3, a13, -4 + l32e a5, a11, -44 + l32e a6, a11, -40 + l32e a7, a11, -36 + l32e a9, a11, -28 + l32e a10, a11, -24 + l32e a11, a11, -20 + rfwu + + .text + + diff --git a/arch/xtensa/kernel/vmlinux.lds.S b/arch/xtensa/kernel/vmlinux.lds.S new file mode 100644 index 00000000..88ecea3f --- /dev/null +++ b/arch/xtensa/kernel/vmlinux.lds.S @@ -0,0 +1,272 @@ +/* + * arch/xtensa/kernel/vmlinux.lds.S + * + * Xtensa linker script + * + * 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) 2001 - 2005 Tensilica Inc. + * + * Chris Zankel <chris@zankel.net> + * Marc Gauthier <marc@tensilica.com, marc@alumni.uwaterloo.ca> + * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com> + */ + +#include <asm-generic/vmlinux.lds.h> +#include <asm/page.h> +#include <asm/thread_info.h> + +#include <variant/core.h> +#include <platform/hardware.h> +OUTPUT_ARCH(xtensa) +ENTRY(_start) + +#ifdef __XTENSA_EB__ +jiffies = jiffies_64 + 4; +#else +jiffies = jiffies_64; +#endif + +#ifndef KERNELOFFSET +#define KERNELOFFSET 0xd0001000 +#endif + +/* Note: In the following macros, it would be nice to specify only the + vector name and section kind and construct "sym" and "section" using + CPP concatenation, but that does not work reliably. Concatenating a + string with "." produces an invalid token. CPP will not print a + warning because it thinks this is an assembly file, but it leaves + them as multiple tokens and there may or may not be whitespace + between them. */ + +/* Macro for a relocation entry */ + +#define RELOCATE_ENTRY(sym, section) \ + LONG(sym ## _start); \ + LONG(sym ## _end); \ + LONG(LOADADDR(section)) + +/* Macro to define a section for a vector. + * + * Use of the MIN function catches the types of errors illustrated in + * the following example: + * + * Assume the section .DoubleExceptionVector.literal is completely + * full. Then a programmer adds code to .DoubleExceptionVector.text + * that produces another literal. The final literal position will + * overlay onto the first word of the adjacent code section + * .DoubleExceptionVector.text. (In practice, the literals will + * overwrite the code, and the first few instructions will be + * garbage.) + */ + +#define SECTION_VECTOR(sym, section, addr, max_prevsec_size, prevsec) \ + section addr : AT((MIN(LOADADDR(prevsec) + max_prevsec_size, \ + LOADADDR(prevsec) + SIZEOF(prevsec)) + 3) & ~ 3) \ + { \ + . = ALIGN(4); \ + sym ## _start = ABSOLUTE(.); \ + *(section) \ + sym ## _end = ABSOLUTE(.); \ + } + +/* + * Mapping of input sections to output sections when linking. + */ + +SECTIONS +{ + . = KERNELOFFSET; + /* .text section */ + + _text = .; + _stext = .; + _ftext = .; + + .text : + { + /* The HEAD_TEXT section must be the first section! */ + HEAD_TEXT + TEXT_TEXT + VMLINUX_SYMBOL(__sched_text_start) = .; + *(.sched.literal .sched.text) + VMLINUX_SYMBOL(__sched_text_end) = .; + VMLINUX_SYMBOL(__lock_text_start) = .; + *(.spinlock.literal .spinlock.text) + VMLINUX_SYMBOL(__lock_text_end) = .; + + } + _etext = .; + PROVIDE (etext = .); + + . = ALIGN(16); + + RODATA + + /* Relocation table */ + + .fixup : { *(.fixup) } + + EXCEPTION_TABLE(16) + /* Data section */ + + _fdata = .; + RW_DATA_SECTION(XCHAL_ICACHE_LINESIZE, PAGE_SIZE, THREAD_SIZE) + _edata = .; + + /* Initialization code and data: */ + + . = ALIGN(PAGE_SIZE); + __init_begin = .; + INIT_TEXT_SECTION(PAGE_SIZE) + + .init.data : + { + INIT_DATA + . = ALIGN(0x4); + __tagtable_begin = .; + *(.taglist) + __tagtable_end = .; + + . = ALIGN(16); + __boot_reloc_table_start = ABSOLUTE(.); + + RELOCATE_ENTRY(_WindowVectors_text, + .WindowVectors.text); + RELOCATE_ENTRY(_KernelExceptionVector_text, + .KernelExceptionVector.text); + RELOCATE_ENTRY(_UserExceptionVector_text, + .UserExceptionVector.text); + RELOCATE_ENTRY(_DoubleExceptionVector_literal, + .DoubleExceptionVector.literal); + RELOCATE_ENTRY(_DoubleExceptionVector_text, + .DoubleExceptionVector.text); + RELOCATE_ENTRY(_DebugInterruptVector_text, + .DebugInterruptVector.text); + + __boot_reloc_table_end = ABSOLUTE(.) ; + + INIT_SETUP(XCHAL_ICACHE_LINESIZE) + INIT_CALLS + CON_INITCALL + SECURITY_INITCALL + INIT_RAM_FS + } + + PERCPU_SECTION(XCHAL_ICACHE_LINESIZE) + + /* We need this dummy segment here */ + + . = ALIGN(4); + .dummy : { LONG(0) } + + /* The vectors are relocated to the real position at startup time */ + + SECTION_VECTOR (_WindowVectors_text, + .WindowVectors.text, + XCHAL_WINDOW_VECTORS_VADDR, 4, + .dummy) + SECTION_VECTOR (_DebugInterruptVector_literal, + .DebugInterruptVector.literal, + XCHAL_DEBUG_VECTOR_VADDR - 4, + SIZEOF(.WindowVectors.text), + .WindowVectors.text) + SECTION_VECTOR (_DebugInterruptVector_text, + .DebugInterruptVector.text, + XCHAL_DEBUG_VECTOR_VADDR, + 4, + .DebugInterruptVector.literal) + SECTION_VECTOR (_KernelExceptionVector_literal, + .KernelExceptionVector.literal, + XCHAL_KERNEL_VECTOR_VADDR - 4, + SIZEOF(.DebugInterruptVector.text), + .DebugInterruptVector.text) + SECTION_VECTOR (_KernelExceptionVector_text, + .KernelExceptionVector.text, + XCHAL_KERNEL_VECTOR_VADDR, + 4, + .KernelExceptionVector.literal) + SECTION_VECTOR (_UserExceptionVector_literal, + .UserExceptionVector.literal, + XCHAL_USER_VECTOR_VADDR - 4, + SIZEOF(.KernelExceptionVector.text), + .KernelExceptionVector.text) + SECTION_VECTOR (_UserExceptionVector_text, + .UserExceptionVector.text, + XCHAL_USER_VECTOR_VADDR, + 4, + .UserExceptionVector.literal) + SECTION_VECTOR (_DoubleExceptionVector_literal, + .DoubleExceptionVector.literal, + XCHAL_DOUBLEEXC_VECTOR_VADDR - 16, + SIZEOF(.UserExceptionVector.text), + .UserExceptionVector.text) + SECTION_VECTOR (_DoubleExceptionVector_text, + .DoubleExceptionVector.text, + XCHAL_DOUBLEEXC_VECTOR_VADDR, + 32, + .DoubleExceptionVector.literal) + + . = (LOADADDR( .DoubleExceptionVector.text ) + SIZEOF( .DoubleExceptionVector.text ) + 3) & ~ 3; + . = ALIGN(PAGE_SIZE); + + __init_end = .; + + BSS_SECTION(0, 8192, 0) + + _end = .; + + /* only used by the boot loader */ + + . = ALIGN(0x10); + .bootstrap : { *(.bootstrap.literal .bootstrap.text .bootstrap.data) } + + . = ALIGN(0x1000); + __initrd_start = .; + .initrd : { *(.initrd) } + __initrd_end = .; + + .ResetVector.text XCHAL_RESET_VECTOR_VADDR : + { + *(.ResetVector.text) + } + + .xt.lit : { *(.xt.lit) } + .xt.prop : { *(.xt.prop) } + + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + + .xt.insn 0 : + { + *(.xt.insn) + *(.gnu.linkonce.x*) + } + + .xt.lit 0 : + { + *(.xt.lit) + *(.gnu.linkonce.p*) + } + + /* Sections to be discarded */ + DISCARDS + /DISCARD/ : { *(.exit.literal) } +} diff --git a/arch/xtensa/kernel/xtensa_ksyms.c b/arch/xtensa/kernel/xtensa_ksyms.c new file mode 100644 index 00000000..c9a7c5b7 --- /dev/null +++ b/arch/xtensa/kernel/xtensa_ksyms.c @@ -0,0 +1,97 @@ +/* + * arch/xtensa/kernel/xtensa_ksyms.c + * + * Export Xtensa-specific functions for loadable modules. + * + * 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) 2001 - 2005 Tensilica Inc. + * + * Joe Taylor <joe@tensilica.com> + */ + +#include <linux/module.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/interrupt.h> +#include <asm/irq.h> +#include <linux/in6.h> + +#include <asm/uaccess.h> +#include <asm/checksum.h> +#include <asm/dma.h> +#include <asm/io.h> +#include <asm/page.h> +#include <asm/pgalloc.h> +#ifdef CONFIG_BLK_DEV_FD +#include <asm/floppy.h> +#endif +#ifdef CONFIG_NET +#include <net/checksum.h> +#endif /* CONFIG_NET */ + + +/* + * String functions + */ +EXPORT_SYMBOL(memset); +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(memmove); + +EXPORT_SYMBOL(kernel_thread); + +/* + * gcc internal math functions + */ +extern long long __ashrdi3(long long, int); +extern long long __ashldi3(long long, int); +extern long long __lshrdi3(long long, int); +extern int __divsi3(int, int); +extern int __modsi3(int, int); +extern long long __muldi3(long long, long long); +extern int __mulsi3(int, int); +extern unsigned int __udivsi3(unsigned int, unsigned int); +extern unsigned int __umodsi3(unsigned int, unsigned int); +extern unsigned long long __umoddi3(unsigned long long, unsigned long long); +extern unsigned long long __udivdi3(unsigned long long, unsigned long long); + +EXPORT_SYMBOL(__ashldi3); +EXPORT_SYMBOL(__ashrdi3); +EXPORT_SYMBOL(__lshrdi3); +EXPORT_SYMBOL(__divsi3); +EXPORT_SYMBOL(__modsi3); +EXPORT_SYMBOL(__muldi3); +EXPORT_SYMBOL(__mulsi3); +EXPORT_SYMBOL(__udivsi3); +EXPORT_SYMBOL(__umodsi3); +EXPORT_SYMBOL(__udivdi3); +EXPORT_SYMBOL(__umoddi3); + +#ifdef CONFIG_NET +/* + * Networking support + */ +EXPORT_SYMBOL(csum_partial_copy_generic); +#endif /* CONFIG_NET */ + +/* + * Architecture-specific symbols + */ +EXPORT_SYMBOL(__xtensa_copy_user); + +/* + * Kernel hacking ... + */ + +#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE) +// FIXME EXPORT_SYMBOL(screen_info); +#endif + +EXPORT_SYMBOL(outsb); +EXPORT_SYMBOL(outsw); +EXPORT_SYMBOL(outsl); +EXPORT_SYMBOL(insb); +EXPORT_SYMBOL(insw); +EXPORT_SYMBOL(insl); diff --git a/arch/xtensa/lib/Makefile b/arch/xtensa/lib/Makefile new file mode 100644 index 00000000..6c4fdd86 --- /dev/null +++ b/arch/xtensa/lib/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for Xtensa-specific library files. +# + +lib-y += memcopy.o memset.o checksum.o \ + usercopy.o strncpy_user.o strnlen_user.o +lib-$(CONFIG_PCI) += pci-auto.o diff --git a/arch/xtensa/lib/checksum.S b/arch/xtensa/lib/checksum.S new file mode 100644 index 00000000..df397f93 --- /dev/null +++ b/arch/xtensa/lib/checksum.S @@ -0,0 +1,409 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * IP/TCP/UDP checksumming routines + * + * Xtensa version: Copyright (C) 2001 Tensilica, Inc. by Kevin Chea + * Optimized by Joe Taylor + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <asm/errno.h> +#include <linux/linkage.h> +#include <variant/core.h> + +/* + * computes a partial checksum, e.g. for TCP/UDP fragments + */ + +/* + * unsigned int csum_partial(const unsigned char *buf, int len, + * unsigned int sum); + * a2 = buf + * a3 = len + * a4 = sum + * + * This function assumes 2- or 4-byte alignment. Other alignments will fail! + */ + +/* ONES_ADD converts twos-complement math to ones-complement. */ +#define ONES_ADD(sum, val) \ + add sum, sum, val ; \ + bgeu sum, val, 99f ; \ + addi sum, sum, 1 ; \ +99: ; + +.text +ENTRY(csum_partial) + /* + * Experiments with Ethernet and SLIP connections show that buf + * is aligned on either a 2-byte or 4-byte boundary. + */ + entry sp, 32 + extui a5, a2, 0, 2 + bnez a5, 8f /* branch if 2-byte aligned */ + /* Fall-through on common case, 4-byte alignment */ +1: + srli a5, a3, 5 /* 32-byte chunks */ +#if XCHAL_HAVE_LOOPS + loopgtz a5, 2f +#else + beqz a5, 2f + slli a5, a5, 5 + add a5, a5, a2 /* a5 = end of last 32-byte chunk */ +.Loop1: +#endif + l32i a6, a2, 0 + l32i a7, a2, 4 + ONES_ADD(a4, a6) + ONES_ADD(a4, a7) + l32i a6, a2, 8 + l32i a7, a2, 12 + ONES_ADD(a4, a6) + ONES_ADD(a4, a7) + l32i a6, a2, 16 + l32i a7, a2, 20 + ONES_ADD(a4, a6) + ONES_ADD(a4, a7) + l32i a6, a2, 24 + l32i a7, a2, 28 + ONES_ADD(a4, a6) + ONES_ADD(a4, a7) + addi a2, a2, 4*8 +#if !XCHAL_HAVE_LOOPS + blt a2, a5, .Loop1 +#endif +2: + extui a5, a3, 2, 3 /* remaining 4-byte chunks */ +#if XCHAL_HAVE_LOOPS + loopgtz a5, 3f +#else + beqz a5, 3f + slli a5, a5, 2 + add a5, a5, a2 /* a5 = end of last 4-byte chunk */ +.Loop2: +#endif + l32i a6, a2, 0 + ONES_ADD(a4, a6) + addi a2, a2, 4 +#if !XCHAL_HAVE_LOOPS + blt a2, a5, .Loop2 +#endif +3: + _bbci.l a3, 1, 5f /* remaining 2-byte chunk */ + l16ui a6, a2, 0 + ONES_ADD(a4, a6) + addi a2, a2, 2 +5: + _bbci.l a3, 0, 7f /* remaining 1-byte chunk */ +6: l8ui a6, a2, 0 +#ifdef __XTENSA_EB__ + slli a6, a6, 8 /* load byte into bits 8..15 */ +#endif + ONES_ADD(a4, a6) +7: + mov a2, a4 + retw + + /* uncommon case, buf is 2-byte aligned */ +8: + beqz a3, 7b /* branch if len == 0 */ + beqi a3, 1, 6b /* branch if len == 1 */ + + extui a5, a2, 0, 1 + bnez a5, 8f /* branch if 1-byte aligned */ + + l16ui a6, a2, 0 /* common case, len >= 2 */ + ONES_ADD(a4, a6) + addi a2, a2, 2 /* adjust buf */ + addi a3, a3, -2 /* adjust len */ + j 1b /* now buf is 4-byte aligned */ + + /* case: odd-byte aligned, len > 1 + * This case is dog slow, so don't give us an odd address. + * (I don't think this ever happens, but just in case.) + */ +8: + srli a5, a3, 2 /* 4-byte chunks */ +#if XCHAL_HAVE_LOOPS + loopgtz a5, 2f +#else + beqz a5, 2f + slli a5, a5, 2 + add a5, a5, a2 /* a5 = end of last 4-byte chunk */ +.Loop3: +#endif + l8ui a6, a2, 0 /* bits 24..31 */ + l16ui a7, a2, 1 /* bits 8..23 */ + l8ui a8, a2, 3 /* bits 0.. 8 */ +#ifdef __XTENSA_EB__ + slli a6, a6, 24 +#else + slli a8, a8, 24 +#endif + slli a7, a7, 8 + or a7, a7, a6 + or a7, a7, a8 + ONES_ADD(a4, a7) + addi a2, a2, 4 +#if !XCHAL_HAVE_LOOPS + blt a2, a5, .Loop3 +#endif +2: + _bbci.l a3, 1, 3f /* remaining 2-byte chunk, still odd addr */ + l8ui a6, a2, 0 + l8ui a7, a2, 1 +#ifdef __XTENSA_EB__ + slli a6, a6, 8 +#else + slli a7, a7, 8 +#endif + or a7, a7, a6 + ONES_ADD(a4, a7) + addi a2, a2, 2 +3: + j 5b /* branch to handle the remaining byte */ + + + +/* + * Copy from ds while checksumming, otherwise like csum_partial + * + * The macros SRC and DST specify the type of access for the instruction. + * thus we can call a custom exception handler for each access type. + */ + +#define SRC(y...) \ + 9999: y; \ + .section __ex_table, "a"; \ + .long 9999b, 6001f ; \ + .previous + +#define DST(y...) \ + 9999: y; \ + .section __ex_table, "a"; \ + .long 9999b, 6002f ; \ + .previous + +/* +unsigned int csum_partial_copy_generic (const char *src, char *dst, int len, + int sum, int *src_err_ptr, int *dst_err_ptr) + a2 = src + a3 = dst + a4 = len + a5 = sum + a6 = src_err_ptr + a7 = dst_err_ptr + a8 = temp + a9 = temp + a10 = temp + a11 = original len for exception handling + a12 = original dst for exception handling + + This function is optimized for 4-byte aligned addresses. Other + alignments work, but not nearly as efficiently. + */ + +ENTRY(csum_partial_copy_generic) + entry sp, 32 + mov a12, a3 + mov a11, a4 + or a10, a2, a3 + + /* We optimize the following alignment tests for the 4-byte + aligned case. Two bbsi.l instructions might seem more optimal + (commented out below). However, both labels 5: and 3: are out + of the imm8 range, so the assembler relaxes them into + equivalent bbci.l, j combinations, which is actually + slower. */ + + extui a9, a10, 0, 2 + beqz a9, 1f /* branch if both are 4-byte aligned */ + bbsi.l a10, 0, 5f /* branch if one address is odd */ + j 3f /* one address is 2-byte aligned */ + +/* _bbsi.l a10, 0, 5f */ /* branch if odd address */ +/* _bbsi.l a10, 1, 3f */ /* branch if 2-byte-aligned address */ + +1: + /* src and dst are both 4-byte aligned */ + srli a10, a4, 5 /* 32-byte chunks */ +#if XCHAL_HAVE_LOOPS + loopgtz a10, 2f +#else + beqz a10, 2f + slli a10, a10, 5 + add a10, a10, a2 /* a10 = end of last 32-byte src chunk */ +.Loop5: +#endif +SRC( l32i a9, a2, 0 ) +SRC( l32i a8, a2, 4 ) +DST( s32i a9, a3, 0 ) +DST( s32i a8, a3, 4 ) + ONES_ADD(a5, a9) + ONES_ADD(a5, a8) +SRC( l32i a9, a2, 8 ) +SRC( l32i a8, a2, 12 ) +DST( s32i a9, a3, 8 ) +DST( s32i a8, a3, 12 ) + ONES_ADD(a5, a9) + ONES_ADD(a5, a8) +SRC( l32i a9, a2, 16 ) +SRC( l32i a8, a2, 20 ) +DST( s32i a9, a3, 16 ) +DST( s32i a8, a3, 20 ) + ONES_ADD(a5, a9) + ONES_ADD(a5, a8) +SRC( l32i a9, a2, 24 ) +SRC( l32i a8, a2, 28 ) +DST( s32i a9, a3, 24 ) +DST( s32i a8, a3, 28 ) + ONES_ADD(a5, a9) + ONES_ADD(a5, a8) + addi a2, a2, 32 + addi a3, a3, 32 +#if !XCHAL_HAVE_LOOPS + blt a2, a10, .Loop5 +#endif +2: + extui a10, a4, 2, 3 /* remaining 4-byte chunks */ + extui a4, a4, 0, 2 /* reset len for general-case, 2-byte chunks */ +#if XCHAL_HAVE_LOOPS + loopgtz a10, 3f +#else + beqz a10, 3f + slli a10, a10, 2 + add a10, a10, a2 /* a10 = end of last 4-byte src chunk */ +.Loop6: +#endif +SRC( l32i a9, a2, 0 ) +DST( s32i a9, a3, 0 ) + ONES_ADD(a5, a9) + addi a2, a2, 4 + addi a3, a3, 4 +#if !XCHAL_HAVE_LOOPS + blt a2, a10, .Loop6 +#endif +3: + /* + Control comes to here in two cases: (1) It may fall through + to here from the 4-byte alignment case to process, at most, + one 2-byte chunk. (2) It branches to here from above if + either src or dst is 2-byte aligned, and we process all bytes + here, except for perhaps a trailing odd byte. It's + inefficient, so align your addresses to 4-byte boundaries. + + a2 = src + a3 = dst + a4 = len + a5 = sum + */ + srli a10, a4, 1 /* 2-byte chunks */ +#if XCHAL_HAVE_LOOPS + loopgtz a10, 4f +#else + beqz a10, 4f + slli a10, a10, 1 + add a10, a10, a2 /* a10 = end of last 2-byte src chunk */ +.Loop7: +#endif +SRC( l16ui a9, a2, 0 ) +DST( s16i a9, a3, 0 ) + ONES_ADD(a5, a9) + addi a2, a2, 2 + addi a3, a3, 2 +#if !XCHAL_HAVE_LOOPS + blt a2, a10, .Loop7 +#endif +4: + /* This section processes a possible trailing odd byte. */ + _bbci.l a4, 0, 8f /* 1-byte chunk */ +SRC( l8ui a9, a2, 0 ) +DST( s8i a9, a3, 0 ) +#ifdef __XTENSA_EB__ + slli a9, a9, 8 /* shift byte to bits 8..15 */ +#endif + ONES_ADD(a5, a9) +8: + mov a2, a5 + retw + +5: + /* Control branch to here when either src or dst is odd. We + process all bytes using 8-bit accesses. Grossly inefficient, + so don't feed us an odd address. */ + + srli a10, a4, 1 /* handle in pairs for 16-bit csum */ +#if XCHAL_HAVE_LOOPS + loopgtz a10, 6f +#else + beqz a10, 6f + slli a10, a10, 1 + add a10, a10, a2 /* a10 = end of last odd-aligned, 2-byte src chunk */ +.Loop8: +#endif +SRC( l8ui a9, a2, 0 ) +SRC( l8ui a8, a2, 1 ) +DST( s8i a9, a3, 0 ) +DST( s8i a8, a3, 1 ) +#ifdef __XTENSA_EB__ + slli a9, a9, 8 /* combine into a single 16-bit value */ +#else /* for checksum computation */ + slli a8, a8, 8 +#endif + or a9, a9, a8 + ONES_ADD(a5, a9) + addi a2, a2, 2 + addi a3, a3, 2 +#if !XCHAL_HAVE_LOOPS + blt a2, a10, .Loop8 +#endif +6: + j 4b /* process the possible trailing odd byte */ + + +# Exception handler: +.section .fixup, "ax" +/* + a6 = src_err_ptr + a7 = dst_err_ptr + a11 = original len for exception handling + a12 = original dst for exception handling +*/ + +6001: + _movi a2, -EFAULT + s32i a2, a6, 0 /* src_err_ptr */ + + # clear the complete destination - computing the rest + # is too much work + movi a2, 0 +#if XCHAL_HAVE_LOOPS + loopgtz a11, 2f +#else + beqz a11, 2f + add a11, a11, a12 /* a11 = ending address */ +.Leloop: +#endif + s8i a2, a12, 0 + addi a12, a12, 1 +#if !XCHAL_HAVE_LOOPS + blt a12, a11, .Leloop +#endif +2: + retw + +6002: + movi a2, -EFAULT + s32i a2, a7, 0 /* dst_err_ptr */ + movi a2, 0 + retw + +.previous + diff --git a/arch/xtensa/lib/memcopy.S b/arch/xtensa/lib/memcopy.S new file mode 100644 index 00000000..ea59dcd0 --- /dev/null +++ b/arch/xtensa/lib/memcopy.S @@ -0,0 +1,315 @@ +/* + * arch/xtensa/lib/hal/memcopy.S -- Core HAL library functions + * xthal_memcpy and xthal_bcopy + * + * 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 - 2005 Tensilica Inc. + */ + +#include <variant/core.h> + + .macro src_b r, w0, w1 +#ifdef __XTENSA_EB__ + src \r, \w0, \w1 +#else + src \r, \w1, \w0 +#endif + .endm + + .macro ssa8 r +#ifdef __XTENSA_EB__ + ssa8b \r +#else + ssa8l \r +#endif + .endm + + +/* + * void *memcpy(void *dst, const void *src, size_t len); + * void *memmove(void *dst, const void *src, size_t len); + * void *bcopy(const void *src, void *dst, size_t len); + * + * This function is intended to do the same thing as the standard + * library function memcpy() (or bcopy()) for most cases. + * However, where the source and/or destination references + * an instruction RAM or ROM or a data RAM or ROM, that + * source and/or destination will always be accessed with + * 32-bit load and store instructions (as required for these + * types of devices). + * + * !!!!!!! XTFIXME: + * !!!!!!! Handling of IRAM/IROM has not yet + * !!!!!!! been implemented. + * + * The bcopy version is provided here to avoid the overhead + * of an extra call, for callers that require this convention. + * + * The (general case) algorithm is as follows: + * If destination is unaligned, align it by conditionally + * copying 1 and 2 bytes. + * If source is aligned, + * do 16 bytes with a loop, and then finish up with + * 8, 4, 2, and 1 byte copies conditional on the length; + * else (if source is unaligned), + * do the same, but use SRC to align the source data. + * This code tries to use fall-through branches for the common + * case of aligned source and destination and multiple + * of 4 (or 8) length. + * + * Register use: + * a0/ return address + * a1/ stack pointer + * a2/ return value + * a3/ src + * a4/ length + * a5/ dst + * a6/ tmp + * a7/ tmp + * a8/ tmp + * a9/ tmp + * a10/ tmp + * a11/ tmp + */ + + .text + .align 4 + .global bcopy + .type bcopy,@function +bcopy: + entry sp, 16 # minimal stack frame + # a2=src, a3=dst, a4=len + mov a5, a3 # copy dst so that a2 is return value + mov a3, a2 + mov a2, a5 + j .Lcommon # go to common code for memcpy+bcopy + + +/* + * Byte by byte copy + */ + .align 4 + .byte 0 # 1 mod 4 alignment for LOOPNEZ + # (0 mod 4 alignment for LBEG) +.Lbytecopy: +#if XCHAL_HAVE_LOOPS + loopnez a4, .Lbytecopydone +#else /* !XCHAL_HAVE_LOOPS */ + beqz a4, .Lbytecopydone + add a7, a3, a4 # a7 = end address for source +#endif /* !XCHAL_HAVE_LOOPS */ +.Lnextbyte: + l8ui a6, a3, 0 + addi a3, a3, 1 + s8i a6, a5, 0 + addi a5, a5, 1 +#if !XCHAL_HAVE_LOOPS + blt a3, a7, .Lnextbyte +#endif /* !XCHAL_HAVE_LOOPS */ +.Lbytecopydone: + retw + +/* + * Destination is unaligned + */ + + .align 4 +.Ldst1mod2: # dst is only byte aligned + _bltui a4, 7, .Lbytecopy # do short copies byte by byte + + # copy 1 byte + l8ui a6, a3, 0 + addi a3, a3, 1 + addi a4, a4, -1 + s8i a6, a5, 0 + addi a5, a5, 1 + _bbci.l a5, 1, .Ldstaligned # if dst is now aligned, then + # return to main algorithm +.Ldst2mod4: # dst 16-bit aligned + # copy 2 bytes + _bltui a4, 6, .Lbytecopy # do short copies byte by byte + l8ui a6, a3, 0 + l8ui a7, a3, 1 + addi a3, a3, 2 + addi a4, a4, -2 + s8i a6, a5, 0 + s8i a7, a5, 1 + addi a5, a5, 2 + j .Ldstaligned # dst is now aligned, return to main algorithm + + .align 4 + .global memcpy + .type memcpy,@function +memcpy: + .global memmove + .type memmove,@function +memmove: + + entry sp, 16 # minimal stack frame + # a2/ dst, a3/ src, a4/ len + mov a5, a2 # copy dst so that a2 is return value +.Lcommon: + _bbsi.l a2, 0, .Ldst1mod2 # if dst is 1 mod 2 + _bbsi.l a2, 1, .Ldst2mod4 # if dst is 2 mod 4 +.Ldstaligned: # return here from .Ldst?mod? once dst is aligned + srli a7, a4, 4 # number of loop iterations with 16B + # per iteration + movi a8, 3 # if source is not aligned, + _bany a3, a8, .Lsrcunaligned # then use shifting copy + /* + * Destination and source are word-aligned, use word copy. + */ + # copy 16 bytes per iteration for word-aligned dst and word-aligned src +#if XCHAL_HAVE_LOOPS + loopnez a7, .Loop1done +#else /* !XCHAL_HAVE_LOOPS */ + beqz a7, .Loop1done + slli a8, a7, 4 + add a8, a8, a3 # a8 = end of last 16B source chunk +#endif /* !XCHAL_HAVE_LOOPS */ +.Loop1: + l32i a6, a3, 0 + l32i a7, a3, 4 + s32i a6, a5, 0 + l32i a6, a3, 8 + s32i a7, a5, 4 + l32i a7, a3, 12 + s32i a6, a5, 8 + addi a3, a3, 16 + s32i a7, a5, 12 + addi a5, a5, 16 +#if !XCHAL_HAVE_LOOPS + blt a3, a8, .Loop1 +#endif /* !XCHAL_HAVE_LOOPS */ +.Loop1done: + bbci.l a4, 3, .L2 + # copy 8 bytes + l32i a6, a3, 0 + l32i a7, a3, 4 + addi a3, a3, 8 + s32i a6, a5, 0 + s32i a7, a5, 4 + addi a5, a5, 8 +.L2: + bbsi.l a4, 2, .L3 + bbsi.l a4, 1, .L4 + bbsi.l a4, 0, .L5 + retw +.L3: + # copy 4 bytes + l32i a6, a3, 0 + addi a3, a3, 4 + s32i a6, a5, 0 + addi a5, a5, 4 + bbsi.l a4, 1, .L4 + bbsi.l a4, 0, .L5 + retw +.L4: + # copy 2 bytes + l16ui a6, a3, 0 + addi a3, a3, 2 + s16i a6, a5, 0 + addi a5, a5, 2 + bbsi.l a4, 0, .L5 + retw +.L5: + # copy 1 byte + l8ui a6, a3, 0 + s8i a6, a5, 0 + retw + +/* + * Destination is aligned, Source is unaligned + */ + + .align 4 +.Lsrcunaligned: + _beqz a4, .Ldone # avoid loading anything for zero-length copies + # copy 16 bytes per iteration for word-aligned dst and unaligned src + ssa8 a3 # set shift amount from byte offset +#define SIM_CHECKS_ALIGNMENT 1 /* set to 1 when running on ISS (simulator) with the + lint or ferret client, or 0 to save a few cycles */ +#if XCHAL_UNALIGNED_LOAD_EXCEPTION || SIM_CHECKS_ALIGNMENT + and a11, a3, a8 # save unalignment offset for below + sub a3, a3, a11 # align a3 +#endif + l32i a6, a3, 0 # load first word +#if XCHAL_HAVE_LOOPS + loopnez a7, .Loop2done +#else /* !XCHAL_HAVE_LOOPS */ + beqz a7, .Loop2done + slli a10, a7, 4 + add a10, a10, a3 # a10 = end of last 16B source chunk +#endif /* !XCHAL_HAVE_LOOPS */ +.Loop2: + l32i a7, a3, 4 + l32i a8, a3, 8 + src_b a6, a6, a7 + s32i a6, a5, 0 + l32i a9, a3, 12 + src_b a7, a7, a8 + s32i a7, a5, 4 + l32i a6, a3, 16 + src_b a8, a8, a9 + s32i a8, a5, 8 + addi a3, a3, 16 + src_b a9, a9, a6 + s32i a9, a5, 12 + addi a5, a5, 16 +#if !XCHAL_HAVE_LOOPS + blt a3, a10, .Loop2 +#endif /* !XCHAL_HAVE_LOOPS */ +.Loop2done: + bbci.l a4, 3, .L12 + # copy 8 bytes + l32i a7, a3, 4 + l32i a8, a3, 8 + src_b a6, a6, a7 + s32i a6, a5, 0 + addi a3, a3, 8 + src_b a7, a7, a8 + s32i a7, a5, 4 + addi a5, a5, 8 + mov a6, a8 +.L12: + bbci.l a4, 2, .L13 + # copy 4 bytes + l32i a7, a3, 4 + addi a3, a3, 4 + src_b a6, a6, a7 + s32i a6, a5, 0 + addi a5, a5, 4 + mov a6, a7 +.L13: +#if XCHAL_UNALIGNED_LOAD_EXCEPTION || SIM_CHECKS_ALIGNMENT + add a3, a3, a11 # readjust a3 with correct misalignment +#endif + bbsi.l a4, 1, .L14 + bbsi.l a4, 0, .L15 +.Ldone: retw +.L14: + # copy 2 bytes + l8ui a6, a3, 0 + l8ui a7, a3, 1 + addi a3, a3, 2 + s8i a6, a5, 0 + s8i a7, a5, 1 + addi a5, a5, 2 + bbsi.l a4, 0, .L15 + retw +.L15: + # copy 1 byte + l8ui a6, a3, 0 + s8i a6, a5, 0 + retw + +/* + * Local Variables: + * mode:fundamental + * comment-start: "# " + * comment-start-skip: "# *" + * End: + */ diff --git a/arch/xtensa/lib/memset.S b/arch/xtensa/lib/memset.S new file mode 100644 index 00000000..10b8c400 --- /dev/null +++ b/arch/xtensa/lib/memset.S @@ -0,0 +1,160 @@ +/* + * arch/xtensa/lib/memset.S + * + * ANSI C standard library function memset + * (Well, almost. .fixup code might return zero.) + * + * 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 Tensilica Inc. + */ + +#include <variant/core.h> + +/* + * void *memset(void *dst, int c, size_t length) + * + * The algorithm is as follows: + * Create a word with c in all byte positions + * If the destination is aligned, + * do 16B chucks with a loop, and then finish up with + * 8B, 4B, 2B, and 1B stores conditional on the length. + * If destination is unaligned, align it by conditionally + * setting 1B and 2B and then go to aligned case. + * This code tries to use fall-through branches for the common + * case of an aligned destination (except for the branches to + * the alignment labels). + */ + +/* Load or store instructions that may cause exceptions use the EX macro. */ + +#define EX(insn,reg1,reg2,offset,handler) \ +9: insn reg1, reg2, offset; \ + .section __ex_table, "a"; \ + .word 9b, handler; \ + .previous + + +.text +.align 4 +.global memset +.type memset,@function +memset: + entry sp, 16 # minimal stack frame + # a2/ dst, a3/ c, a4/ length + extui a3, a3, 0, 8 # mask to just 8 bits + slli a7, a3, 8 # duplicate character in all bytes of word + or a3, a3, a7 # ... + slli a7, a3, 16 # ... + or a3, a3, a7 # ... + mov a5, a2 # copy dst so that a2 is return value + movi a6, 3 # for alignment tests + bany a2, a6, .Ldstunaligned # if dst is unaligned +.L0: # return here from .Ldstunaligned when dst is aligned + srli a7, a4, 4 # number of loop iterations with 16B + # per iteration + bnez a4, .Laligned + retw + +/* + * Destination is word-aligned. + */ + # set 16 bytes per iteration for word-aligned dst + .align 4 # 1 mod 4 alignment for LOOPNEZ + .byte 0 # (0 mod 4 alignment for LBEG) +.Laligned: +#if XCHAL_HAVE_LOOPS + loopnez a7, .Loop1done +#else /* !XCHAL_HAVE_LOOPS */ + beqz a7, .Loop1done + slli a6, a7, 4 + add a6, a6, a5 # a6 = end of last 16B chunk +#endif /* !XCHAL_HAVE_LOOPS */ +.Loop1: + EX(s32i, a3, a5, 0, memset_fixup) + EX(s32i, a3, a5, 4, memset_fixup) + EX(s32i, a3, a5, 8, memset_fixup) + EX(s32i, a3, a5, 12, memset_fixup) + addi a5, a5, 16 +#if !XCHAL_HAVE_LOOPS + blt a5, a6, .Loop1 +#endif /* !XCHAL_HAVE_LOOPS */ +.Loop1done: + bbci.l a4, 3, .L2 + # set 8 bytes + EX(s32i, a3, a5, 0, memset_fixup) + EX(s32i, a3, a5, 4, memset_fixup) + addi a5, a5, 8 +.L2: + bbci.l a4, 2, .L3 + # set 4 bytes + EX(s32i, a3, a5, 0, memset_fixup) + addi a5, a5, 4 +.L3: + bbci.l a4, 1, .L4 + # set 2 bytes + EX(s16i, a3, a5, 0, memset_fixup) + addi a5, a5, 2 +.L4: + bbci.l a4, 0, .L5 + # set 1 byte + EX(s8i, a3, a5, 0, memset_fixup) +.L5: +.Lret1: + retw + +/* + * Destination is unaligned + */ + +.Ldstunaligned: + bltui a4, 8, .Lbyteset # do short copies byte by byte + bbci.l a5, 0, .L20 # branch if dst alignment half-aligned + # dst is only byte aligned + # set 1 byte + EX(s8i, a3, a5, 0, memset_fixup) + addi a5, a5, 1 + addi a4, a4, -1 + # now retest if dst aligned + bbci.l a5, 1, .L0 # if now aligned, return to main algorithm +.L20: + # dst half-aligned + # set 2 bytes + EX(s16i, a3, a5, 0, memset_fixup) + addi a5, a5, 2 + addi a4, a4, -2 + j .L0 # dst is now aligned, return to main algorithm + +/* + * Byte by byte set + */ + .align 4 + .byte 0 # 1 mod 4 alignment for LOOPNEZ + # (0 mod 4 alignment for LBEG) +.Lbyteset: +#if XCHAL_HAVE_LOOPS + loopnez a4, .Lbytesetdone +#else /* !XCHAL_HAVE_LOOPS */ + beqz a4, .Lbytesetdone + add a6, a5, a4 # a6 = ending address +#endif /* !XCHAL_HAVE_LOOPS */ +.Lbyteloop: + EX(s8i, a3, a5, 0, memset_fixup) + addi a5, a5, 1 +#if !XCHAL_HAVE_LOOPS + blt a5, a6, .Lbyteloop +#endif /* !XCHAL_HAVE_LOOPS */ +.Lbytesetdone: + retw + + + .section .fixup, "ax" + .align 4 + +/* We return zero if a failure occurred. */ + +memset_fixup: + movi a2, 0 + retw diff --git a/arch/xtensa/lib/pci-auto.c b/arch/xtensa/lib/pci-auto.c new file mode 100644 index 00000000..a71733ae --- /dev/null +++ b/arch/xtensa/lib/pci-auto.c @@ -0,0 +1,352 @@ +/* + * arch/xtensa/lib/pci-auto.c + * + * PCI autoconfiguration library + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + * + * Chris Zankel <zankel@tensilica.com, cez@zankel.net> + * + * Based on work from Matt Porter <mporter@mvista.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/pci.h> + +#include <asm/pci-bridge.h> + + +/* + * + * Setting up a PCI + * + * pci_ctrl->first_busno = <first bus number (0)> + * pci_ctrl->last_busno = <last bus number (0xff)> + * pci_ctrl->ops = <PCI config operations> + * pci_ctrl->map_irq = <function to return the interrupt number for a device> + * + * pci_ctrl->io_space.start = <IO space start address (PCI view)> + * pci_ctrl->io_space.end = <IO space end address (PCI view)> + * pci_ctrl->io_space.base = <IO space offset: address 0 from CPU space> + * pci_ctrl->mem_space.start = <MEM space start address (PCI view)> + * pci_ctrl->mem_space.end = <MEM space end address (PCI view)> + * pci_ctrl->mem_space.base = <MEM space offset: address 0 from CPU space> + * + * pcibios_init_resource(&pci_ctrl->io_resource, <IO space start>, + * <IO space end>, IORESOURCE_IO, "PCI host bridge"); + * pcibios_init_resource(&pci_ctrl->mem_resources[0], <MEM space start>, + * <MEM space end>, IORESOURCE_MEM, "PCI host bridge"); + * + * pci_ctrl->last_busno = pciauto_bus_scan(pci_ctrl,pci_ctrl->first_busno); + * + * int __init pciauto_bus_scan(struct pci_controller *pci_ctrl, int current_bus) + * + */ + + +/* define DEBUG to print some debugging messages. */ + +#undef DEBUG + +#ifdef DEBUG +# define DBG(x...) printk(x) +#else +# define DBG(x...) +#endif + +static int pciauto_upper_iospc; +static int pciauto_upper_memspc; + +static struct pci_dev pciauto_dev; +static struct pci_bus pciauto_bus; + +/* + * Helper functions + */ + +/* Initialize the bars of a PCI device. */ + +static void __init +pciauto_setup_bars(struct pci_dev *dev, int bar_limit) +{ + int bar_size; + int bar, bar_nr; + int *upper_limit; + int found_mem64 = 0; + + for (bar = PCI_BASE_ADDRESS_0, bar_nr = 0; + bar <= bar_limit; + bar+=4, bar_nr++) + { + /* Tickle the BAR and get the size */ + pci_write_config_dword(dev, bar, 0xffffffff); + pci_read_config_dword(dev, bar, &bar_size); + + /* If BAR is not implemented go to the next BAR */ + if (!bar_size) + continue; + + /* Check the BAR type and set our address mask */ + if (bar_size & PCI_BASE_ADDRESS_SPACE_IO) + { + bar_size &= PCI_BASE_ADDRESS_IO_MASK; + upper_limit = &pciauto_upper_iospc; + DBG("PCI Autoconfig: BAR %d, I/O, ", bar_nr); + } + else + { + if ((bar_size & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == + PCI_BASE_ADDRESS_MEM_TYPE_64) + found_mem64 = 1; + + bar_size &= PCI_BASE_ADDRESS_MEM_MASK; + upper_limit = &pciauto_upper_memspc; + DBG("PCI Autoconfig: BAR %d, Mem, ", bar_nr); + } + + /* Allocate a base address (bar_size is negative!) */ + *upper_limit = (*upper_limit + bar_size) & bar_size; + + /* Write it out and update our limit */ + pci_write_config_dword(dev, bar, *upper_limit); + + /* + * If we are a 64-bit decoder then increment to the + * upper 32 bits of the bar and force it to locate + * in the lower 4GB of memory. + */ + + if (found_mem64) + pci_write_config_dword(dev, (bar+=4), 0x00000000); + + DBG("size=0x%x, address=0x%x\n", ~bar_size + 1, *upper_limit); + } +} + +/* Initialize the interrupt number. */ + +static void __init +pciauto_setup_irq(struct pci_controller* pci_ctrl,struct pci_dev *dev,int devfn) +{ + u8 pin; + int irq = 0; + + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); + + /* Fix illegal pin numbers. */ + + if (pin == 0 || pin > 4) + pin = 1; + + if (pci_ctrl->map_irq) + irq = pci_ctrl->map_irq(dev, PCI_SLOT(devfn), pin); + + if (irq == -1) + irq = 0; + + DBG("PCI Autoconfig: Interrupt %d, pin %d\n", irq, pin); + + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); +} + + +static void __init +pciauto_prescan_setup_bridge(struct pci_dev *dev, int current_bus, + int sub_bus, int *iosave, int *memsave) +{ + /* Configure bus number registers */ + pci_write_config_byte(dev, PCI_PRIMARY_BUS, current_bus); + pci_write_config_byte(dev, PCI_SECONDARY_BUS, sub_bus + 1); + pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, 0xff); + + /* Round memory allocator to 1MB boundary */ + pciauto_upper_memspc &= ~(0x100000 - 1); + *memsave = pciauto_upper_memspc; + + /* Round I/O allocator to 4KB boundary */ + pciauto_upper_iospc &= ~(0x1000 - 1); + *iosave = pciauto_upper_iospc; + + /* Set up memory and I/O filter limits, assume 32-bit I/O space */ + pci_write_config_word(dev, PCI_MEMORY_LIMIT, + ((pciauto_upper_memspc - 1) & 0xfff00000) >> 16); + pci_write_config_byte(dev, PCI_IO_LIMIT, + ((pciauto_upper_iospc - 1) & 0x0000f000) >> 8); + pci_write_config_word(dev, PCI_IO_LIMIT_UPPER16, + ((pciauto_upper_iospc - 1) & 0xffff0000) >> 16); +} + +static void __init +pciauto_postscan_setup_bridge(struct pci_dev *dev, int current_bus, int sub_bus, + int *iosave, int *memsave) +{ + int cmdstat; + + /* Configure bus number registers */ + pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, sub_bus); + + /* + * Round memory allocator to 1MB boundary. + * If no space used, allocate minimum. + */ + pciauto_upper_memspc &= ~(0x100000 - 1); + if (*memsave == pciauto_upper_memspc) + pciauto_upper_memspc -= 0x00100000; + + pci_write_config_word(dev, PCI_MEMORY_BASE, pciauto_upper_memspc >> 16); + + /* Allocate 1MB for pre-fretch */ + pci_write_config_word(dev, PCI_PREF_MEMORY_LIMIT, + ((pciauto_upper_memspc - 1) & 0xfff00000) >> 16); + + pciauto_upper_memspc -= 0x100000; + + pci_write_config_word(dev, PCI_PREF_MEMORY_BASE, + pciauto_upper_memspc >> 16); + + /* Round I/O allocator to 4KB boundary */ + pciauto_upper_iospc &= ~(0x1000 - 1); + if (*iosave == pciauto_upper_iospc) + pciauto_upper_iospc -= 0x1000; + + pci_write_config_byte(dev, PCI_IO_BASE, + (pciauto_upper_iospc & 0x0000f000) >> 8); + pci_write_config_word(dev, PCI_IO_BASE_UPPER16, + pciauto_upper_iospc >> 16); + + /* Enable memory and I/O accesses, enable bus master */ + pci_read_config_dword(dev, PCI_COMMAND, &cmdstat); + pci_write_config_dword(dev, PCI_COMMAND, + cmdstat | + PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER); +} + +/* + * Scan the current PCI bus. + */ + + +int __init pciauto_bus_scan(struct pci_controller *pci_ctrl, int current_bus) +{ + int sub_bus, pci_devfn, pci_class, cmdstat, found_multi=0; + unsigned short vid; + unsigned char header_type; + struct pci_dev *dev = &pciauto_dev; + + pciauto_dev.bus = &pciauto_bus; + pciauto_dev.sysdata = pci_ctrl; + pciauto_bus.ops = pci_ctrl->ops; + + /* + * Fetch our I/O and memory space upper boundaries used + * to allocated base addresses on this pci_controller. + */ + + if (current_bus == pci_ctrl->first_busno) + { + pciauto_upper_iospc = pci_ctrl->io_resource.end + 1; + pciauto_upper_memspc = pci_ctrl->mem_resources[0].end + 1; + } + + sub_bus = current_bus; + + for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) + { + /* Skip our host bridge */ + if ((current_bus == pci_ctrl->first_busno) && (pci_devfn == 0)) + continue; + + if (PCI_FUNC(pci_devfn) && !found_multi) + continue; + + pciauto_bus.number = current_bus; + pciauto_dev.devfn = pci_devfn; + + /* If config space read fails from this device, move on */ + if (pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type)) + continue; + + if (!PCI_FUNC(pci_devfn)) + found_multi = header_type & 0x80; + pci_read_config_word(dev, PCI_VENDOR_ID, &vid); + + if (vid == 0xffff || vid == 0x0000) { + found_multi = 0; + continue; + } + + pci_read_config_dword(dev, PCI_CLASS_REVISION, &pci_class); + + if ((pci_class >> 16) == PCI_CLASS_BRIDGE_PCI) { + + int iosave, memsave; + + DBG("PCI Autoconfig: Found P2P bridge, device %d\n", + PCI_SLOT(pci_devfn)); + + /* Allocate PCI I/O and/or memory space */ + pciauto_setup_bars(dev, PCI_BASE_ADDRESS_1); + + pciauto_prescan_setup_bridge(dev, current_bus, sub_bus, + &iosave, &memsave); + sub_bus = pciauto_bus_scan(pci_ctrl, sub_bus+1); + pciauto_postscan_setup_bridge(dev, current_bus, sub_bus, + &iosave, &memsave); + pciauto_bus.number = current_bus; + + continue; + + } + + +#if 0 + /* Skip legacy mode IDE controller */ + + if ((pci_class >> 16) == PCI_CLASS_STORAGE_IDE) { + + unsigned char prg_iface; + pci_read_config_byte(dev, PCI_CLASS_PROG, &prg_iface); + + if (!(prg_iface & PCIAUTO_IDE_MODE_MASK)) { + DBG("PCI Autoconfig: Skipping legacy mode " + "IDE controller\n"); + continue; + } + } +#endif + + /* + * Found a peripheral, enable some standard + * settings + */ + + pci_read_config_dword(dev, PCI_COMMAND, &cmdstat); + pci_write_config_dword(dev, PCI_COMMAND, + cmdstat | + PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x80); + + /* Allocate PCI I/O and/or memory space */ + DBG("PCI Autoconfig: Found Bus %d, Device %d, Function %d\n", + current_bus, PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn) ); + + pciauto_setup_bars(dev, PCI_BASE_ADDRESS_5); + pciauto_setup_irq(pci_ctrl, dev, pci_devfn); + } + return sub_bus; +} + + + + + diff --git a/arch/xtensa/lib/strncpy_user.S b/arch/xtensa/lib/strncpy_user.S new file mode 100644 index 00000000..9f603cda --- /dev/null +++ b/arch/xtensa/lib/strncpy_user.S @@ -0,0 +1,225 @@ +/* + * arch/xtensa/lib/strncpy_user.S + * + * 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. + * + * Returns: -EFAULT if exception before terminator, N if the entire + * buffer filled, else strlen. + * + * Copyright (C) 2002 Tensilica Inc. + */ + +#include <variant/core.h> +#include <linux/errno.h> + +/* Load or store instructions that may cause exceptions use the EX macro. */ + +#define EX(insn,reg1,reg2,offset,handler) \ +9: insn reg1, reg2, offset; \ + .section __ex_table, "a"; \ + .word 9b, handler; \ + .previous + +/* + * char *__strncpy_user(char *dst, const char *src, size_t len) + */ + +#ifdef __XTENSA_EB__ +# define MASK0 0xff000000 +# define MASK1 0x00ff0000 +# define MASK2 0x0000ff00 +# define MASK3 0x000000ff +#else +# define MASK0 0x000000ff +# define MASK1 0x0000ff00 +# define MASK2 0x00ff0000 +# define MASK3 0xff000000 +#endif + +# Register use +# a0/ return address +# a1/ stack pointer +# a2/ return value +# a3/ src +# a4/ len +# a5/ mask0 +# a6/ mask1 +# a7/ mask2 +# a8/ mask3 +# a9/ tmp +# a10/ tmp +# a11/ dst +# a12/ tmp + +.text +.align 4 +.global __strncpy_user +.type __strncpy_user,@function +__strncpy_user: + entry sp, 16 # minimal stack frame + # a2/ dst, a3/ src, a4/ len + mov a11, a2 # leave dst in return value register + beqz a4, .Lret # if len is zero + movi a5, MASK0 # mask for byte 0 + movi a6, MASK1 # mask for byte 1 + movi a7, MASK2 # mask for byte 2 + movi a8, MASK3 # mask for byte 3 + bbsi.l a3, 0, .Lsrc1mod2 # if only 8-bit aligned + bbsi.l a3, 1, .Lsrc2mod4 # if only 16-bit aligned +.Lsrcaligned: # return here when src is word-aligned + srli a12, a4, 2 # number of loop iterations with 4B per loop + movi a9, 3 + bnone a11, a9, .Laligned + j .Ldstunaligned + +.Lsrc1mod2: # src address is odd + EX(l8ui, a9, a3, 0, fixup_l) # get byte 0 + addi a3, a3, 1 # advance src pointer + EX(s8i, a9, a11, 0, fixup_s) # store byte 0 + beqz a9, .Lret # if byte 0 is zero + addi a11, a11, 1 # advance dst pointer + addi a4, a4, -1 # decrement len + beqz a4, .Lret # if len is zero + bbci.l a3, 1, .Lsrcaligned # if src is now word-aligned + +.Lsrc2mod4: # src address is 2 mod 4 + EX(l8ui, a9, a3, 0, fixup_l) # get byte 0 + /* 1-cycle interlock */ + EX(s8i, a9, a11, 0, fixup_s) # store byte 0 + beqz a9, .Lret # if byte 0 is zero + addi a11, a11, 1 # advance dst pointer + addi a4, a4, -1 # decrement len + beqz a4, .Lret # if len is zero + EX(l8ui, a9, a3, 1, fixup_l) # get byte 0 + addi a3, a3, 2 # advance src pointer + EX(s8i, a9, a11, 0, fixup_s) # store byte 0 + beqz a9, .Lret # if byte 0 is zero + addi a11, a11, 1 # advance dst pointer + addi a4, a4, -1 # decrement len + bnez a4, .Lsrcaligned # if len is nonzero +.Lret: + sub a2, a11, a2 # compute strlen + retw + +/* + * dst is word-aligned, src is word-aligned + */ + .align 4 # 1 mod 4 alignment for LOOPNEZ + .byte 0 # (0 mod 4 alignment for LBEG) +.Laligned: +#if XCHAL_HAVE_LOOPS + loopnez a12, .Loop1done +#else + beqz a12, .Loop1done + slli a12, a12, 2 + add a12, a12, a11 # a12 = end of last 4B chunck +#endif +.Loop1: + EX(l32i, a9, a3, 0, fixup_l) # get word from src + addi a3, a3, 4 # advance src pointer + bnone a9, a5, .Lz0 # if byte 0 is zero + bnone a9, a6, .Lz1 # if byte 1 is zero + bnone a9, a7, .Lz2 # if byte 2 is zero + EX(s32i, a9, a11, 0, fixup_s) # store word to dst + bnone a9, a8, .Lz3 # if byte 3 is zero + addi a11, a11, 4 # advance dst pointer +#if !XCHAL_HAVE_LOOPS + blt a11, a12, .Loop1 +#endif + +.Loop1done: + bbci.l a4, 1, .L100 + # copy 2 bytes + EX(l16ui, a9, a3, 0, fixup_l) + addi a3, a3, 2 # advance src pointer +#ifdef __XTENSA_EB__ + bnone a9, a7, .Lz0 # if byte 2 is zero + bnone a9, a8, .Lz1 # if byte 3 is zero +#else + bnone a9, a5, .Lz0 # if byte 0 is zero + bnone a9, a6, .Lz1 # if byte 1 is zero +#endif + EX(s16i, a9, a11, 0, fixup_s) + addi a11, a11, 2 # advance dst pointer +.L100: + bbci.l a4, 0, .Lret + EX(l8ui, a9, a3, 0, fixup_l) + /* slot */ + EX(s8i, a9, a11, 0, fixup_s) + beqz a9, .Lret # if byte is zero + addi a11, a11, 1-3 # advance dst ptr 1, but also cancel + # the effect of adding 3 in .Lz3 code + /* fall thru to .Lz3 and "retw" */ + +.Lz3: # byte 3 is zero + addi a11, a11, 3 # advance dst pointer + sub a2, a11, a2 # compute strlen + retw +.Lz0: # byte 0 is zero +#ifdef __XTENSA_EB__ + movi a9, 0 +#endif /* __XTENSA_EB__ */ + EX(s8i, a9, a11, 0, fixup_s) + sub a2, a11, a2 # compute strlen + retw +.Lz1: # byte 1 is zero +#ifdef __XTENSA_EB__ + extui a9, a9, 16, 16 +#endif /* __XTENSA_EB__ */ + EX(s16i, a9, a11, 0, fixup_s) + addi a11, a11, 1 # advance dst pointer + sub a2, a11, a2 # compute strlen + retw +.Lz2: # byte 2 is zero +#ifdef __XTENSA_EB__ + extui a9, a9, 16, 16 +#endif /* __XTENSA_EB__ */ + EX(s16i, a9, a11, 0, fixup_s) + movi a9, 0 + EX(s8i, a9, a11, 2, fixup_s) + addi a11, a11, 2 # advance dst pointer + sub a2, a11, a2 # compute strlen + retw + + .align 4 # 1 mod 4 alignment for LOOPNEZ + .byte 0 # (0 mod 4 alignment for LBEG) +.Ldstunaligned: +/* + * for now just use byte copy loop + */ +#if XCHAL_HAVE_LOOPS + loopnez a4, .Lunalignedend +#else + beqz a4, .Lunalignedend + add a12, a11, a4 # a12 = ending address +#endif /* XCHAL_HAVE_LOOPS */ +.Lnextbyte: + EX(l8ui, a9, a3, 0, fixup_l) + addi a3, a3, 1 + EX(s8i, a9, a11, 0, fixup_s) + beqz a9, .Lunalignedend + addi a11, a11, 1 +#if !XCHAL_HAVE_LOOPS + blt a11, a12, .Lnextbyte +#endif + +.Lunalignedend: + sub a2, a11, a2 # compute strlen + retw + + + .section .fixup, "ax" + .align 4 + + /* For now, just return -EFAULT. Future implementations might + * like to clear remaining kernel space, like the fixup + * implementation in memset(). Thus, we differentiate between + * load/store fixups. */ + +fixup_s: +fixup_l: + movi a2, -EFAULT + retw + diff --git a/arch/xtensa/lib/strnlen_user.S b/arch/xtensa/lib/strnlen_user.S new file mode 100644 index 00000000..23f2a898 --- /dev/null +++ b/arch/xtensa/lib/strnlen_user.S @@ -0,0 +1,148 @@ +/* + * arch/xtensa/lib/strnlen_user.S + * + * 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. + * + * Returns strnlen, including trailing zero terminator. + * Zero indicates error. + * + * Copyright (C) 2002 Tensilica Inc. + */ + +#include <variant/core.h> + +/* Load or store instructions that may cause exceptions use the EX macro. */ + +#define EX(insn,reg1,reg2,offset,handler) \ +9: insn reg1, reg2, offset; \ + .section __ex_table, "a"; \ + .word 9b, handler; \ + .previous + +/* + * size_t __strnlen_user(const char *s, size_t len) + */ + +#ifdef __XTENSA_EB__ +# define MASK0 0xff000000 +# define MASK1 0x00ff0000 +# define MASK2 0x0000ff00 +# define MASK3 0x000000ff +#else +# define MASK0 0x000000ff +# define MASK1 0x0000ff00 +# define MASK2 0x00ff0000 +# define MASK3 0xff000000 +#endif + +# Register use: +# a2/ src +# a3/ len +# a4/ tmp +# a5/ mask0 +# a6/ mask1 +# a7/ mask2 +# a8/ mask3 +# a9/ tmp +# a10/ tmp + +.text +.align 4 +.global __strnlen_user +.type __strnlen_user,@function +__strnlen_user: + entry sp, 16 # minimal stack frame + # a2/ s, a3/ len + addi a4, a2, -4 # because we overincrement at the end; + # we compensate with load offsets of 4 + movi a5, MASK0 # mask for byte 0 + movi a6, MASK1 # mask for byte 1 + movi a7, MASK2 # mask for byte 2 + movi a8, MASK3 # mask for byte 3 + bbsi.l a2, 0, .L1mod2 # if only 8-bit aligned + bbsi.l a2, 1, .L2mod4 # if only 16-bit aligned + +/* + * String is word-aligned. + */ +.Laligned: + srli a10, a3, 2 # number of loop iterations with 4B per loop +#if XCHAL_HAVE_LOOPS + loopnez a10, .Ldone +#else + beqz a10, .Ldone + slli a10, a10, 2 + add a10, a10, a4 # a10 = end of last 4B chunk +#endif /* XCHAL_HAVE_LOOPS */ +.Loop: + EX(l32i, a9, a4, 4, lenfixup) # get next word of string + addi a4, a4, 4 # advance string pointer + bnone a9, a5, .Lz0 # if byte 0 is zero + bnone a9, a6, .Lz1 # if byte 1 is zero + bnone a9, a7, .Lz2 # if byte 2 is zero + bnone a9, a8, .Lz3 # if byte 3 is zero +#if !XCHAL_HAVE_LOOPS + blt a4, a10, .Loop +#endif + +.Ldone: + EX(l32i, a9, a4, 4, lenfixup) # load 4 bytes for remaining checks + + bbci.l a3, 1, .L100 + # check two more bytes (bytes 0, 1 of word) + addi a4, a4, 2 # advance string pointer + bnone a9, a5, .Lz0 # if byte 0 is zero + bnone a9, a6, .Lz1 # if byte 1 is zero +.L100: + bbci.l a3, 0, .L101 + # check one more byte (byte 2 of word) + # Actually, we don't need to check. Zero or nonzero, we'll add one. + # Do not add an extra one for the NULL terminator since we have + # exhausted the original len parameter. + addi a4, a4, 1 # advance string pointer +.L101: + sub a2, a4, a2 # compute length + retw + +# NOTE that in several places below, we point to the byte just after +# the zero byte in order to include the NULL terminator in the count. + +.Lz3: # byte 3 is zero + addi a4, a4, 3 # point to zero byte +.Lz0: # byte 0 is zero + addi a4, a4, 1 # point just beyond zero byte + sub a2, a4, a2 # subtract to get length + retw +.Lz1: # byte 1 is zero + addi a4, a4, 1+1 # point just beyond zero byte + sub a2, a4, a2 # subtract to get length + retw +.Lz2: # byte 2 is zero + addi a4, a4, 2+1 # point just beyond zero byte + sub a2, a4, a2 # subtract to get length + retw + +.L1mod2: # address is odd + EX(l8ui, a9, a4, 4, lenfixup) # get byte 0 + addi a4, a4, 1 # advance string pointer + beqz a9, .Lz3 # if byte 0 is zero + bbci.l a4, 1, .Laligned # if string pointer is now word-aligned + +.L2mod4: # address is 2 mod 4 + addi a4, a4, 2 # advance ptr for aligned access + EX(l32i, a9, a4, 0, lenfixup) # get word with first two bytes of string + bnone a9, a7, .Lz2 # if byte 2 (of word, not string) is zero + bany a9, a8, .Laligned # if byte 3 (of word, not string) is nonzero + # byte 3 is zero + addi a4, a4, 3+1 # point just beyond zero byte + sub a2, a4, a2 # subtract to get length + retw + + .section .fixup, "ax" + .align 4 +lenfixup: + movi a2, 0 + retw + diff --git a/arch/xtensa/lib/usercopy.S b/arch/xtensa/lib/usercopy.S new file mode 100644 index 00000000..46d60314 --- /dev/null +++ b/arch/xtensa/lib/usercopy.S @@ -0,0 +1,321 @@ +/* + * arch/xtensa/lib/usercopy.S + * + * Copy to/from user space (derived from arch/xtensa/lib/hal/memcopy.S) + * + * DO NOT COMBINE this function with <arch/xtensa/lib/hal/memcopy.S>. + * It needs to remain separate and distinct. The hal files are part + * of the Xtensa link-time HAL, and those files may differ per + * processor configuration. Patching the kernel for another + * processor configuration includes replacing the hal files, and we + * could lose the special functionality for accessing user-space + * memory during such a patch. We sacrifice a little code space here + * in favor to simplify code maintenance. + * + * 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 Tensilica Inc. + */ + + +/* + * size_t __xtensa_copy_user (void *dst, const void *src, size_t len); + * + * The returned value is the number of bytes not copied. Implies zero + * is success. + * + * The general case algorithm is as follows: + * If the destination and source are both aligned, + * do 16B chunks with a loop, and then finish up with + * 8B, 4B, 2B, and 1B copies conditional on the length. + * If destination is aligned and source unaligned, + * do the same, but use SRC to align the source data. + * If destination is unaligned, align it by conditionally + * copying 1B and 2B and then retest. + * This code tries to use fall-through braches for the common + * case of aligned destinations (except for the branches to + * the alignment label). + * + * Register use: + * a0/ return address + * a1/ stack pointer + * a2/ return value + * a3/ src + * a4/ length + * a5/ dst + * a6/ tmp + * a7/ tmp + * a8/ tmp + * a9/ tmp + * a10/ tmp + * a11/ original length + */ + +#include <variant/core.h> + +#ifdef __XTENSA_EB__ +#define ALIGN(R, W0, W1) src R, W0, W1 +#define SSA8(R) ssa8b R +#else +#define ALIGN(R, W0, W1) src R, W1, W0 +#define SSA8(R) ssa8l R +#endif + +/* Load or store instructions that may cause exceptions use the EX macro. */ + +#define EX(insn,reg1,reg2,offset,handler) \ +9: insn reg1, reg2, offset; \ + .section __ex_table, "a"; \ + .word 9b, handler; \ + .previous + + + .text + .align 4 + .global __xtensa_copy_user + .type __xtensa_copy_user,@function +__xtensa_copy_user: + entry sp, 16 # minimal stack frame + # a2/ dst, a3/ src, a4/ len + mov a5, a2 # copy dst so that a2 is return value + mov a11, a4 # preserve original len for error case +.Lcommon: + bbsi.l a2, 0, .Ldst1mod2 # if dst is 1 mod 2 + bbsi.l a2, 1, .Ldst2mod4 # if dst is 2 mod 4 +.Ldstaligned: # return here from .Ldstunaligned when dst is aligned + srli a7, a4, 4 # number of loop iterations with 16B + # per iteration + movi a8, 3 # if source is also aligned, + bnone a3, a8, .Laligned # then use word copy + SSA8( a3) # set shift amount from byte offset + bnez a4, .Lsrcunaligned + movi a2, 0 # return success for len==0 + retw + +/* + * Destination is unaligned + */ + +.Ldst1mod2: # dst is only byte aligned + bltui a4, 7, .Lbytecopy # do short copies byte by byte + + # copy 1 byte + EX(l8ui, a6, a3, 0, l_fixup) + addi a3, a3, 1 + EX(s8i, a6, a5, 0, s_fixup) + addi a5, a5, 1 + addi a4, a4, -1 + bbci.l a5, 1, .Ldstaligned # if dst is now aligned, then + # return to main algorithm +.Ldst2mod4: # dst 16-bit aligned + # copy 2 bytes + bltui a4, 6, .Lbytecopy # do short copies byte by byte + EX(l8ui, a6, a3, 0, l_fixup) + EX(l8ui, a7, a3, 1, l_fixup) + addi a3, a3, 2 + EX(s8i, a6, a5, 0, s_fixup) + EX(s8i, a7, a5, 1, s_fixup) + addi a5, a5, 2 + addi a4, a4, -2 + j .Ldstaligned # dst is now aligned, return to main algorithm + +/* + * Byte by byte copy + */ + .align 4 + .byte 0 # 1 mod 4 alignment for LOOPNEZ + # (0 mod 4 alignment for LBEG) +.Lbytecopy: +#if XCHAL_HAVE_LOOPS + loopnez a4, .Lbytecopydone +#else /* !XCHAL_HAVE_LOOPS */ + beqz a4, .Lbytecopydone + add a7, a3, a4 # a7 = end address for source +#endif /* !XCHAL_HAVE_LOOPS */ +.Lnextbyte: + EX(l8ui, a6, a3, 0, l_fixup) + addi a3, a3, 1 + EX(s8i, a6, a5, 0, s_fixup) + addi a5, a5, 1 +#if !XCHAL_HAVE_LOOPS + blt a3, a7, .Lnextbyte +#endif /* !XCHAL_HAVE_LOOPS */ +.Lbytecopydone: + movi a2, 0 # return success for len bytes copied + retw + +/* + * Destination and source are word-aligned. + */ + # copy 16 bytes per iteration for word-aligned dst and word-aligned src + .align 4 # 1 mod 4 alignment for LOOPNEZ + .byte 0 # (0 mod 4 alignment for LBEG) +.Laligned: +#if XCHAL_HAVE_LOOPS + loopnez a7, .Loop1done +#else /* !XCHAL_HAVE_LOOPS */ + beqz a7, .Loop1done + slli a8, a7, 4 + add a8, a8, a3 # a8 = end of last 16B source chunk +#endif /* !XCHAL_HAVE_LOOPS */ +.Loop1: + EX(l32i, a6, a3, 0, l_fixup) + EX(l32i, a7, a3, 4, l_fixup) + EX(s32i, a6, a5, 0, s_fixup) + EX(l32i, a6, a3, 8, l_fixup) + EX(s32i, a7, a5, 4, s_fixup) + EX(l32i, a7, a3, 12, l_fixup) + EX(s32i, a6, a5, 8, s_fixup) + addi a3, a3, 16 + EX(s32i, a7, a5, 12, s_fixup) + addi a5, a5, 16 +#if !XCHAL_HAVE_LOOPS + blt a3, a8, .Loop1 +#endif /* !XCHAL_HAVE_LOOPS */ +.Loop1done: + bbci.l a4, 3, .L2 + # copy 8 bytes + EX(l32i, a6, a3, 0, l_fixup) + EX(l32i, a7, a3, 4, l_fixup) + addi a3, a3, 8 + EX(s32i, a6, a5, 0, s_fixup) + EX(s32i, a7, a5, 4, s_fixup) + addi a5, a5, 8 +.L2: + bbci.l a4, 2, .L3 + # copy 4 bytes + EX(l32i, a6, a3, 0, l_fixup) + addi a3, a3, 4 + EX(s32i, a6, a5, 0, s_fixup) + addi a5, a5, 4 +.L3: + bbci.l a4, 1, .L4 + # copy 2 bytes + EX(l16ui, a6, a3, 0, l_fixup) + addi a3, a3, 2 + EX(s16i, a6, a5, 0, s_fixup) + addi a5, a5, 2 +.L4: + bbci.l a4, 0, .L5 + # copy 1 byte + EX(l8ui, a6, a3, 0, l_fixup) + EX(s8i, a6, a5, 0, s_fixup) +.L5: + movi a2, 0 # return success for len bytes copied + retw + +/* + * Destination is aligned, Source is unaligned + */ + + .align 4 + .byte 0 # 1 mod 4 alignement for LOOPNEZ + # (0 mod 4 alignment for LBEG) +.Lsrcunaligned: + # copy 16 bytes per iteration for word-aligned dst and unaligned src + and a10, a3, a8 # save unalignment offset for below + sub a3, a3, a10 # align a3 (to avoid sim warnings only; not needed for hardware) + EX(l32i, a6, a3, 0, l_fixup) # load first word +#if XCHAL_HAVE_LOOPS + loopnez a7, .Loop2done +#else /* !XCHAL_HAVE_LOOPS */ + beqz a7, .Loop2done + slli a10, a7, 4 + add a10, a10, a3 # a10 = end of last 16B source chunk +#endif /* !XCHAL_HAVE_LOOPS */ +.Loop2: + EX(l32i, a7, a3, 4, l_fixup) + EX(l32i, a8, a3, 8, l_fixup) + ALIGN( a6, a6, a7) + EX(s32i, a6, a5, 0, s_fixup) + EX(l32i, a9, a3, 12, l_fixup) + ALIGN( a7, a7, a8) + EX(s32i, a7, a5, 4, s_fixup) + EX(l32i, a6, a3, 16, l_fixup) + ALIGN( a8, a8, a9) + EX(s32i, a8, a5, 8, s_fixup) + addi a3, a3, 16 + ALIGN( a9, a9, a6) + EX(s32i, a9, a5, 12, s_fixup) + addi a5, a5, 16 +#if !XCHAL_HAVE_LOOPS + blt a3, a10, .Loop2 +#endif /* !XCHAL_HAVE_LOOPS */ +.Loop2done: + bbci.l a4, 3, .L12 + # copy 8 bytes + EX(l32i, a7, a3, 4, l_fixup) + EX(l32i, a8, a3, 8, l_fixup) + ALIGN( a6, a6, a7) + EX(s32i, a6, a5, 0, s_fixup) + addi a3, a3, 8 + ALIGN( a7, a7, a8) + EX(s32i, a7, a5, 4, s_fixup) + addi a5, a5, 8 + mov a6, a8 +.L12: + bbci.l a4, 2, .L13 + # copy 4 bytes + EX(l32i, a7, a3, 4, l_fixup) + addi a3, a3, 4 + ALIGN( a6, a6, a7) + EX(s32i, a6, a5, 0, s_fixup) + addi a5, a5, 4 + mov a6, a7 +.L13: + add a3, a3, a10 # readjust a3 with correct misalignment + bbci.l a4, 1, .L14 + # copy 2 bytes + EX(l8ui, a6, a3, 0, l_fixup) + EX(l8ui, a7, a3, 1, l_fixup) + addi a3, a3, 2 + EX(s8i, a6, a5, 0, s_fixup) + EX(s8i, a7, a5, 1, s_fixup) + addi a5, a5, 2 +.L14: + bbci.l a4, 0, .L15 + # copy 1 byte + EX(l8ui, a6, a3, 0, l_fixup) + EX(s8i, a6, a5, 0, s_fixup) +.L15: + movi a2, 0 # return success for len bytes copied + retw + + + .section .fixup, "ax" + .align 4 + +/* a2 = original dst; a5 = current dst; a11= original len + * bytes_copied = a5 - a2 + * retval = bytes_not_copied = original len - bytes_copied + * retval = a11 - (a5 - a2) + * + * Clearing the remaining pieces of kernel memory plugs security + * holes. This functionality is the equivalent of the *_zeroing + * functions that some architectures provide. + */ + +.Lmemset: + .word memset + +s_fixup: + sub a2, a5, a2 /* a2 <-- bytes copied */ + sub a2, a11, a2 /* a2 <-- bytes not copied */ + retw + +l_fixup: + sub a2, a5, a2 /* a2 <-- bytes copied */ + sub a2, a11, a2 /* a2 <-- bytes not copied == return value */ + + /* void *memset(void *s, int c, size_t n); */ + mov a6, a5 /* s */ + movi a7, 0 /* c */ + mov a8, a2 /* n */ + l32r a4, .Lmemset + callx4 a4 + /* Ignore memset return value in a6. */ + /* a2 still contains bytes not copied. */ + retw + diff --git a/arch/xtensa/mm/Makefile b/arch/xtensa/mm/Makefile new file mode 100644 index 00000000..f0b646d2 --- /dev/null +++ b/arch/xtensa/mm/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for the Linux/Xtensa-specific parts of the memory manager. +# + +obj-y := init.o cache.o misc.o +obj-$(CONFIG_MMU) += fault.o mmu.o tlb.o diff --git a/arch/xtensa/mm/cache.c b/arch/xtensa/mm/cache.c new file mode 100644 index 00000000..85df4655 --- /dev/null +++ b/arch/xtensa/mm/cache.c @@ -0,0 +1,255 @@ +/* + * arch/xtensa/mm/cache.c + * + * 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) 2001-2006 Tensilica Inc. + * + * Chris Zankel <chris@zankel.net> + * Joe Taylor + * Marc Gauthier + * + */ + +#include <linux/init.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/types.h> +#include <linux/ptrace.h> +#include <linux/bootmem.h> +#include <linux/swap.h> +#include <linux/pagemap.h> + +#include <asm/bootparam.h> +#include <asm/mmu_context.h> +#include <asm/tlb.h> +#include <asm/tlbflush.h> +#include <asm/page.h> +#include <asm/pgalloc.h> +#include <asm/pgtable.h> + +//#define printd(x...) printk(x) +#define printd(x...) do { } while(0) + +/* + * Note: + * The kernel provides one architecture bit PG_arch_1 in the page flags that + * can be used for cache coherency. + * + * I$-D$ coherency. + * + * The Xtensa architecture doesn't keep the instruction cache coherent with + * the data cache. We use the architecture bit to indicate if the caches + * are coherent. The kernel clears this bit whenever a page is added to the + * page cache. At that time, the caches might not be in sync. We, therefore, + * define this flag as 'clean' if set. + * + * D-cache aliasing. + * + * With cache aliasing, we have to always flush the cache when pages are + * unmapped (see tlb_start_vma(). So, we use this flag to indicate a dirty + * page. + * + * + * + */ + +#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK + +/* + * Any time the kernel writes to a user page cache page, or it is about to + * read from a page cache page this routine is called. + * + */ + +void flush_dcache_page(struct page *page) +{ + struct address_space *mapping = page_mapping(page); + + /* + * If we have a mapping but the page is not mapped to user-space + * yet, we simply mark this page dirty and defer flushing the + * caches until update_mmu(). + */ + + if (mapping && !mapping_mapped(mapping)) { + if (!test_bit(PG_arch_1, &page->flags)) + set_bit(PG_arch_1, &page->flags); + return; + + } else { + + unsigned long phys = page_to_phys(page); + unsigned long temp = page->index << PAGE_SHIFT; + unsigned long alias = !(DCACHE_ALIAS_EQ(temp, phys)); + unsigned long virt; + + /* + * Flush the page in kernel space and user space. + * Note that we can omit that step if aliasing is not + * an issue, but we do have to synchronize I$ and D$ + * if we have a mapping. + */ + + if (!alias && !mapping) + return; + + __flush_invalidate_dcache_page((long)page_address(page)); + + virt = TLBTEMP_BASE_1 + (temp & DCACHE_ALIAS_MASK); + + if (alias) + __flush_invalidate_dcache_page_alias(virt, phys); + + if (mapping) + __invalidate_icache_page_alias(virt, phys); + } + + /* There shouldn't be an entry in the cache for this page anymore. */ +} + + +/* + * For now, flush the whole cache. FIXME?? + */ + +void flush_cache_range(struct vm_area_struct* vma, + unsigned long start, unsigned long end) +{ + __flush_invalidate_dcache_all(); + __invalidate_icache_all(); +} + +/* + * Remove any entry in the cache for this page. + * + * Note that this function is only called for user pages, so use the + * alias versions of the cache flush functions. + */ + +void flush_cache_page(struct vm_area_struct* vma, unsigned long address, + unsigned long pfn) +{ + /* Note that we have to use the 'alias' address to avoid multi-hit */ + + unsigned long phys = page_to_phys(pfn_to_page(pfn)); + unsigned long virt = TLBTEMP_BASE_1 + (address & DCACHE_ALIAS_MASK); + + __flush_invalidate_dcache_page_alias(virt, phys); + __invalidate_icache_page_alias(virt, phys); +} + +#endif + +void +update_mmu_cache(struct vm_area_struct * vma, unsigned long addr, pte_t *ptep) +{ + unsigned long pfn = pte_pfn(*ptep); + struct page *page; + + if (!pfn_valid(pfn)) + return; + + page = pfn_to_page(pfn); + + /* Invalidate old entry in TLBs */ + + invalidate_itlb_mapping(addr); + invalidate_dtlb_mapping(addr); + +#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK + + if (!PageReserved(page) && test_bit(PG_arch_1, &page->flags)) { + + unsigned long vaddr = TLBTEMP_BASE_1 + (addr & DCACHE_ALIAS_MASK); + unsigned long paddr = (unsigned long) page_address(page); + unsigned long phys = page_to_phys(page); + + __flush_invalidate_dcache_page(paddr); + + __flush_invalidate_dcache_page_alias(vaddr, phys); + __invalidate_icache_page_alias(vaddr, phys); + + clear_bit(PG_arch_1, &page->flags); + } +#else + if (!PageReserved(page) && !test_bit(PG_arch_1, &page->flags) + && (vma->vm_flags & VM_EXEC) != 0) { + unsigned long paddr = (unsigned long) page_address(page); + __flush_dcache_page(paddr); + __invalidate_icache_page(paddr); + set_bit(PG_arch_1, &page->flags); + } +#endif +} + +/* + * access_process_vm() has called get_user_pages(), which has done a + * flush_dcache_page() on the page. + */ + +#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK + +void copy_to_user_page(struct vm_area_struct *vma, struct page *page, + unsigned long vaddr, void *dst, const void *src, + unsigned long len) +{ + unsigned long phys = page_to_phys(page); + unsigned long alias = !(DCACHE_ALIAS_EQ(vaddr, phys)); + + /* Flush and invalidate user page if aliased. */ + + if (alias) { + unsigned long temp = TLBTEMP_BASE_1 + (vaddr & DCACHE_ALIAS_MASK); + __flush_invalidate_dcache_page_alias(temp, phys); + } + + /* Copy data */ + + memcpy(dst, src, len); + + /* + * Flush and invalidate kernel page if aliased and synchronize + * data and instruction caches for executable pages. + */ + + if (alias) { + unsigned long temp = TLBTEMP_BASE_1 + (vaddr & DCACHE_ALIAS_MASK); + + __flush_invalidate_dcache_range((unsigned long) dst, len); + if ((vma->vm_flags & VM_EXEC) != 0) { + __invalidate_icache_page_alias(temp, phys); + } + + } else if ((vma->vm_flags & VM_EXEC) != 0) { + __flush_dcache_range((unsigned long)dst,len); + __invalidate_icache_range((unsigned long) dst, len); + } +} + +extern void copy_from_user_page(struct vm_area_struct *vma, struct page *page, + unsigned long vaddr, void *dst, const void *src, + unsigned long len) +{ + unsigned long phys = page_to_phys(page); + unsigned long alias = !(DCACHE_ALIAS_EQ(vaddr, phys)); + + /* + * Flush user page if aliased. + * (Note: a simply flush would be sufficient) + */ + + if (alias) { + unsigned long temp = TLBTEMP_BASE_1 + (vaddr & DCACHE_ALIAS_MASK); + __flush_invalidate_dcache_page_alias(temp, phys); + } + + memcpy(dst, src, len); +} + +#endif diff --git a/arch/xtensa/mm/fault.c b/arch/xtensa/mm/fault.c new file mode 100644 index 00000000..b17885a0 --- /dev/null +++ b/arch/xtensa/mm/fault.c @@ -0,0 +1,236 @@ +// TODO VM_EXEC flag work-around, cache aliasing +/* + * arch/xtensa/mm/fault.c + * + * 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) 2001 - 2005 Tensilica Inc. + * + * Chris Zankel <chris@zankel.net> + * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com> + */ + +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/hardirq.h> +#include <asm/mmu_context.h> +#include <asm/cacheflush.h> +#include <asm/hardirq.h> +#include <asm/uaccess.h> +#include <asm/pgalloc.h> + +unsigned long asid_cache = ASID_USER_FIRST; +void bad_page_fault(struct pt_regs*, unsigned long, int); + +#undef DEBUG_PAGE_FAULT + +/* + * This routine handles page faults. It determines the address, + * and the problem, and then passes it off to one of the appropriate + * routines. + * + * Note: does not handle Miss and MultiHit. + */ + +void do_page_fault(struct pt_regs *regs) +{ + struct vm_area_struct * vma; + struct mm_struct *mm = current->mm; + unsigned int exccause = regs->exccause; + unsigned int address = regs->excvaddr; + siginfo_t info; + + int is_write, is_exec; + int fault; + + info.si_code = SEGV_MAPERR; + + /* We fault-in kernel-space virtual memory on-demand. The + * 'reference' page table is init_mm.pgd. + */ + if (address >= TASK_SIZE && !user_mode(regs)) + goto vmalloc_fault; + + /* If we're in an interrupt or have no user + * context, we must not take the fault.. + */ + if (in_atomic() || !mm) { + bad_page_fault(regs, address, SIGSEGV); + return; + } + + is_write = (exccause == EXCCAUSE_STORE_CACHE_ATTRIBUTE) ? 1 : 0; + is_exec = (exccause == EXCCAUSE_ITLB_PRIVILEGE || + exccause == EXCCAUSE_ITLB_MISS || + exccause == EXCCAUSE_FETCH_CACHE_ATTRIBUTE) ? 1 : 0; + +#ifdef DEBUG_PAGE_FAULT + printk("[%s:%d:%08x:%d:%08x:%s%s]\n", current->comm, current->pid, + address, exccause, regs->pc, is_write? "w":"", is_exec? "x":""); +#endif + + down_read(&mm->mmap_sem); + vma = find_vma(mm, address); + + if (!vma) + goto bad_area; + if (vma->vm_start <= address) + goto good_area; + if (!(vma->vm_flags & VM_GROWSDOWN)) + goto bad_area; + if (expand_stack(vma, address)) + goto bad_area; + + /* Ok, we have a good vm_area for this memory access, so + * we can handle it.. + */ + +good_area: + info.si_code = SEGV_ACCERR; + + if (is_write) { + if (!(vma->vm_flags & VM_WRITE)) + goto bad_area; + } else if (is_exec) { + if (!(vma->vm_flags & VM_EXEC)) + goto bad_area; + } else /* Allow read even from write-only pages. */ + if (!(vma->vm_flags & (VM_READ | VM_WRITE))) + 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. + */ + fault = handle_mm_fault(mm, vma, address, is_write ? FAULT_FLAG_WRITE : 0); + if (unlikely(fault & VM_FAULT_ERROR)) { + if (fault & VM_FAULT_OOM) + goto out_of_memory; + else if (fault & VM_FAULT_SIGBUS) + goto do_sigbus; + BUG(); + } + if (fault & VM_FAULT_MAJOR) + current->maj_flt++; + else + current->min_flt++; + + 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: + up_read(&mm->mmap_sem); + if (user_mode(regs)) { + current->thread.bad_vaddr = address; + current->thread.error_code = is_write; + info.si_signo = SIGSEGV; + info.si_errno = 0; + /* info.si_code has been set above */ + info.si_addr = (void *) address; + force_sig_info(SIGSEGV, &info, current); + return; + } + bad_page_fault(regs, address, SIGSEGV); + return; + + + /* 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: + up_read(&mm->mmap_sem); + if (!user_mode(regs)) + bad_page_fault(regs, address, SIGKILL); + else + pagefault_out_of_memory(); + return; + +do_sigbus: + up_read(&mm->mmap_sem); + + /* Send a sigbus, regardless of whether we were in kernel + * or user mode. + */ + current->thread.bad_vaddr = address; + info.si_code = SIGBUS; + info.si_errno = 0; + info.si_code = BUS_ADRERR; + info.si_addr = (void *) address; + force_sig_info(SIGBUS, &info, current); + + /* Kernel mode? Handle exceptions or die */ + if (!user_mode(regs)) + bad_page_fault(regs, address, SIGBUS); + +vmalloc_fault: + { + /* Synchronize this task's top level page-table + * with the 'reference' page table. + */ + struct mm_struct *act_mm = current->active_mm; + int index = pgd_index(address); + pgd_t *pgd, *pgd_k; + pmd_t *pmd, *pmd_k; + pte_t *pte_k; + + if (act_mm == NULL) + goto bad_page_fault; + + pgd = act_mm->pgd + index; + pgd_k = init_mm.pgd + index; + + if (!pgd_present(*pgd_k)) + goto bad_page_fault; + + pgd_val(*pgd) = pgd_val(*pgd_k); + + pmd = pmd_offset(pgd, address); + pmd_k = pmd_offset(pgd_k, address); + if (!pmd_present(*pmd) || !pmd_present(*pmd_k)) + goto bad_page_fault; + + pmd_val(*pmd) = pmd_val(*pmd_k); + pte_k = pte_offset_kernel(pmd_k, address); + + if (!pte_present(*pte_k)) + goto bad_page_fault; + return; + } +bad_page_fault: + bad_page_fault(regs, address, SIGKILL); + return; +} + + +void +bad_page_fault(struct pt_regs *regs, unsigned long address, int sig) +{ + extern void die(const char*, struct pt_regs*, long); + const struct exception_table_entry *entry; + + /* Are we prepared to handle this kernel fault? */ + if ((entry = search_exception_tables(regs->pc)) != NULL) { +#ifdef DEBUG_PAGE_FAULT + printk(KERN_DEBUG "%s: Exception at pc=%#010lx (%lx)\n", + current->comm, regs->pc, entry->fixup); +#endif + current->thread.bad_uaddr = address; + regs->pc = entry->fixup; + return; + } + + /* Oops. The kernel tried to access some bad page. We'll have to + * terminate things with extreme prejudice. + */ + printk(KERN_ALERT "Unable to handle kernel paging request at virtual " + "address %08lx\n pc = %08lx, ra = %08lx\n", + address, regs->pc, regs->areg[0]); + die("Oops", regs, sig); + do_exit(sig); +} + diff --git a/arch/xtensa/mm/init.c b/arch/xtensa/mm/init.c new file mode 100644 index 00000000..ba150e5d --- /dev/null +++ b/arch/xtensa/mm/init.c @@ -0,0 +1,243 @@ +/* + * arch/xtensa/mm/init.c + * + * Derived from MIPS, PPC. + * + * 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) 2001 - 2005 Tensilica Inc. + * + * Chris Zankel <chris@zankel.net> + * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com> + * Marc Gauthier + * Kevin Chea + */ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/bootmem.h> +#include <linux/gfp.h> +#include <linux/swap.h> +#include <linux/mman.h> +#include <linux/nodemask.h> +#include <linux/mm.h> + +#include <asm/bootparam.h> +#include <asm/page.h> + +/* References to section boundaries */ + +extern char _ftext, _etext, _fdata, _edata, _rodata_end; +extern char __init_begin, __init_end; + +/* + * mem_reserve(start, end, must_exist) + * + * Reserve some memory from the memory pool. + * + * Parameters: + * start Start of region, + * end End of region, + * must_exist Must exist in memory pool. + * + * Returns: + * 0 (memory area couldn't be mapped) + * -1 (success) + */ + +int __init mem_reserve(unsigned long start, unsigned long end, int must_exist) +{ + int i; + + if (start == end) + return 0; + + start = start & PAGE_MASK; + end = PAGE_ALIGN(end); + + for (i = 0; i < sysmem.nr_banks; i++) + if (start < sysmem.bank[i].end + && end >= sysmem.bank[i].start) + break; + + if (i == sysmem.nr_banks) { + if (must_exist) + printk (KERN_WARNING "mem_reserve: [0x%0lx, 0x%0lx) " + "not in any region!\n", start, end); + return 0; + } + + if (start > sysmem.bank[i].start) { + if (end < sysmem.bank[i].end) { + /* split entry */ + if (sysmem.nr_banks >= SYSMEM_BANKS_MAX) + panic("meminfo overflow\n"); + sysmem.bank[sysmem.nr_banks].start = end; + sysmem.bank[sysmem.nr_banks].end = sysmem.bank[i].end; + sysmem.nr_banks++; + } + sysmem.bank[i].end = start; + } else { + if (end < sysmem.bank[i].end) + sysmem.bank[i].start = end; + else { + /* remove entry */ + sysmem.nr_banks--; + sysmem.bank[i].start = sysmem.bank[sysmem.nr_banks].start; + sysmem.bank[i].end = sysmem.bank[sysmem.nr_banks].end; + } + } + return -1; +} + + +/* + * Initialize the bootmem system and give it all the memory we have available. + */ + +void __init bootmem_init(void) +{ + unsigned long pfn; + unsigned long bootmap_start, bootmap_size; + int i; + + max_low_pfn = max_pfn = 0; + min_low_pfn = ~0; + + for (i=0; i < sysmem.nr_banks; i++) { + pfn = PAGE_ALIGN(sysmem.bank[i].start) >> PAGE_SHIFT; + if (pfn < min_low_pfn) + min_low_pfn = pfn; + pfn = PAGE_ALIGN(sysmem.bank[i].end - 1) >> PAGE_SHIFT; + if (pfn > max_pfn) + max_pfn = pfn; + } + + if (min_low_pfn > max_pfn) + panic("No memory found!\n"); + + max_low_pfn = max_pfn < MAX_MEM_PFN >> PAGE_SHIFT ? + max_pfn : MAX_MEM_PFN >> PAGE_SHIFT; + + /* Find an area to use for the bootmem bitmap. */ + + bootmap_size = bootmem_bootmap_pages(max_low_pfn - min_low_pfn); + bootmap_size <<= PAGE_SHIFT; + bootmap_start = ~0; + + for (i=0; i<sysmem.nr_banks; i++) + if (sysmem.bank[i].end - sysmem.bank[i].start >= bootmap_size) { + bootmap_start = sysmem.bank[i].start; + break; + } + + if (bootmap_start == ~0UL) + panic("Cannot find %ld bytes for bootmap\n", bootmap_size); + + /* Reserve the bootmem bitmap area */ + + mem_reserve(bootmap_start, bootmap_start + bootmap_size, 1); + bootmap_size = init_bootmem_node(NODE_DATA(0), + bootmap_start >> PAGE_SHIFT, + min_low_pfn, + max_low_pfn); + + /* Add all remaining memory pieces into the bootmem map */ + + for (i=0; i<sysmem.nr_banks; i++) + free_bootmem(sysmem.bank[i].start, + sysmem.bank[i].end - sysmem.bank[i].start); + +} + + +void __init zones_init(void) +{ + unsigned long zones_size[MAX_NR_ZONES]; + int i; + + /* All pages are DMA-able, so we put them all in the DMA zone. */ + + zones_size[ZONE_DMA] = max_low_pfn - ARCH_PFN_OFFSET; + for (i = 1; i < MAX_NR_ZONES; i++) + zones_size[i] = 0; + +#ifdef CONFIG_HIGHMEM + zones_size[ZONE_HIGHMEM] = max_pfn - max_low_pfn; +#endif + + free_area_init_node(0, zones_size, ARCH_PFN_OFFSET, NULL); +} + +/* + * Initialize memory pages. + */ + +void __init mem_init(void) +{ + unsigned long codesize, reservedpages, datasize, initsize; + unsigned long highmemsize, tmp, ram; + + max_mapnr = num_physpages = max_low_pfn - ARCH_PFN_OFFSET; + high_memory = (void *) __va(max_low_pfn << PAGE_SHIFT); + highmemsize = 0; + +#ifdef CONFIG_HIGHMEM +#error HIGHGMEM not implemented in init.c +#endif + + totalram_pages += free_all_bootmem(); + + reservedpages = ram = 0; + for (tmp = 0; tmp < max_mapnr; tmp++) { + ram++; + if (PageReserved(mem_map+tmp)) + reservedpages++; + } + + codesize = (unsigned long) &_etext - (unsigned long) &_ftext; + datasize = (unsigned long) &_edata - (unsigned long) &_fdata; + initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; + + printk("Memory: %luk/%luk available (%ldk kernel code, %ldk reserved, " + "%ldk data, %ldk init %ldk highmem)\n", + nr_free_pages() << (PAGE_SHIFT-10), + ram << (PAGE_SHIFT-10), + codesize >> 10, + reservedpages << (PAGE_SHIFT-10), + datasize >> 10, + initsize >> 10, + highmemsize >> 10); +} + +void +free_reserved_mem(void *start, void *end) +{ + for (; start < end; start += PAGE_SIZE) { + ClearPageReserved(virt_to_page(start)); + init_page_count(virt_to_page(start)); + free_page((unsigned long)start); + totalram_pages++; + } +} + +#ifdef CONFIG_BLK_DEV_INITRD +extern int initrd_is_mapped; + +void free_initrd_mem(unsigned long start, unsigned long end) +{ + if (initrd_is_mapped) { + free_reserved_mem((void*)start, (void*)end); + printk ("Freeing initrd memory: %ldk freed\n",(end-start)>>10); + } +} +#endif + +void free_initmem(void) +{ + free_reserved_mem(&__init_begin, &__init_end); + printk("Freeing unused kernel memory: %dk freed\n", + (&__init_end - &__init_begin) >> 10); +} diff --git a/arch/xtensa/mm/misc.S b/arch/xtensa/mm/misc.S new file mode 100644 index 00000000..b048406d --- /dev/null +++ b/arch/xtensa/mm/misc.S @@ -0,0 +1,447 @@ +/* + * arch/xtensa/mm/misc.S + * + * Miscellaneous assembly functions. + * + * 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) 2001 - 2007 Tensilica Inc. + * + * Chris Zankel <chris@zankel.net> + */ + + +#include <linux/linkage.h> +#include <asm/page.h> +#include <asm/pgtable.h> +#include <asm/asmmacro.h> +#include <asm/cacheasm.h> +#include <asm/tlbflush.h> + + +/* + * clear_page and clear_user_page are the same for non-cache-aliased configs. + * + * clear_page (unsigned long page) + * a2 + */ + +ENTRY(clear_page) + entry a1, 16 + + movi a3, 0 + __loopi a2, a7, PAGE_SIZE, 32 + s32i a3, a2, 0 + s32i a3, a2, 4 + s32i a3, a2, 8 + s32i a3, a2, 12 + s32i a3, a2, 16 + s32i a3, a2, 20 + s32i a3, a2, 24 + s32i a3, a2, 28 + __endla a2, a7, 32 + + retw + +/* + * copy_page and copy_user_page are the same for non-cache-aliased configs. + * + * copy_page (void *to, void *from) + * a2 a3 + */ + +ENTRY(copy_page) + entry a1, 16 + + __loopi a2, a4, PAGE_SIZE, 32 + + l32i a8, a3, 0 + l32i a9, a3, 4 + s32i a8, a2, 0 + s32i a9, a2, 4 + + l32i a8, a3, 8 + l32i a9, a3, 12 + s32i a8, a2, 8 + s32i a9, a2, 12 + + l32i a8, a3, 16 + l32i a9, a3, 20 + s32i a8, a2, 16 + s32i a9, a2, 20 + + l32i a8, a3, 24 + l32i a9, a3, 28 + s32i a8, a2, 24 + s32i a9, a2, 28 + + addi a2, a2, 32 + addi a3, a3, 32 + + __endl a2, a4 + + retw + +#ifdef CONFIG_MMU +/* + * If we have to deal with cache aliasing, we use temporary memory mappings + * to ensure that the source and destination pages have the same color as + * the virtual address. We use way 0 and 1 for temporary mappings in such cases. + * + * The temporary DTLB entries shouldn't be flushed by interrupts, but are + * flushed by preemptive task switches. Special code in the + * fast_second_level_miss handler re-established the temporary mapping. + * It requires that the PPNs for the destination and source addresses are + * in a6, and a7, respectively. + */ + +/* TLB miss exceptions are treated special in the following region */ + +ENTRY(__tlbtemp_mapping_start) + +#if (DCACHE_WAY_SIZE > PAGE_SIZE) + +/* + * clear_user_page (void *addr, unsigned long vaddr, struct page *page) + * a2 a3 a4 + */ + +ENTRY(clear_user_page) + entry a1, 32 + + /* Mark page dirty and determine alias. */ + + movi a7, (1 << PG_ARCH_1) + l32i a5, a4, PAGE_FLAGS + xor a6, a2, a3 + extui a3, a3, PAGE_SHIFT, DCACHE_ALIAS_ORDER + extui a6, a6, PAGE_SHIFT, DCACHE_ALIAS_ORDER + or a5, a5, a7 + slli a3, a3, PAGE_SHIFT + s32i a5, a4, PAGE_FLAGS + + /* Skip setting up a temporary DTLB if not aliased. */ + + beqz a6, 1f + + /* Invalidate kernel page. */ + + mov a10, a2 + call8 __invalidate_dcache_page + + /* Setup a temporary DTLB with the color of the VPN */ + + movi a4, -PAGE_OFFSET + (PAGE_KERNEL | _PAGE_HW_WRITE) + movi a5, TLBTEMP_BASE_1 # virt + add a6, a2, a4 # ppn + add a2, a5, a3 # add 'color' + + wdtlb a6, a2 + dsync + +1: movi a3, 0 + __loopi a2, a7, PAGE_SIZE, 32 + s32i a3, a2, 0 + s32i a3, a2, 4 + s32i a3, a2, 8 + s32i a3, a2, 12 + s32i a3, a2, 16 + s32i a3, a2, 20 + s32i a3, a2, 24 + s32i a3, a2, 28 + __endla a2, a7, 32 + + bnez a6, 1f + retw + + /* We need to invalidate the temporary idtlb entry, if any. */ + +1: addi a2, a2, -PAGE_SIZE + idtlb a2 + dsync + + retw + +/* + * copy_page_user (void *to, void *from, unsigned long vaddr, struct page *page) + * a2 a3 a4 a5 + */ + +ENTRY(copy_user_page) + + entry a1, 32 + + /* Mark page dirty and determine alias for destination. */ + + movi a8, (1 << PG_ARCH_1) + l32i a9, a5, PAGE_FLAGS + xor a6, a2, a4 + xor a7, a3, a4 + extui a4, a4, PAGE_SHIFT, DCACHE_ALIAS_ORDER + extui a6, a6, PAGE_SHIFT, DCACHE_ALIAS_ORDER + extui a7, a7, PAGE_SHIFT, DCACHE_ALIAS_ORDER + or a9, a9, a8 + slli a4, a4, PAGE_SHIFT + s32i a9, a5, PAGE_FLAGS + movi a5, -PAGE_OFFSET + (PAGE_KERNEL | _PAGE_HW_WRITE) + + beqz a6, 1f + + /* Invalidate dcache */ + + mov a10, a2 + call8 __invalidate_dcache_page + + /* Setup a temporary DTLB with a matching color. */ + + movi a8, TLBTEMP_BASE_1 # base + add a6, a2, a5 # ppn + add a2, a8, a4 # add 'color' + + wdtlb a6, a2 + dsync + + /* Skip setting up a temporary DTLB for destination if not aliased. */ + +1: beqz a7, 1f + + /* Setup a temporary DTLB with a matching color. */ + + movi a8, TLBTEMP_BASE_2 # base + add a7, a3, a5 # ppn + add a3, a8, a4 + addi a8, a3, 1 # way1 + + wdtlb a7, a8 + dsync + +1: __loopi a2, a4, PAGE_SIZE, 32 + + l32i a8, a3, 0 + l32i a9, a3, 4 + s32i a8, a2, 0 + s32i a9, a2, 4 + + l32i a8, a3, 8 + l32i a9, a3, 12 + s32i a8, a2, 8 + s32i a9, a2, 12 + + l32i a8, a3, 16 + l32i a9, a3, 20 + s32i a8, a2, 16 + s32i a9, a2, 20 + + l32i a8, a3, 24 + l32i a9, a3, 28 + s32i a8, a2, 24 + s32i a9, a2, 28 + + addi a2, a2, 32 + addi a3, a3, 32 + + __endl a2, a4 + + /* We need to invalidate any temporary mapping! */ + + bnez a6, 1f + bnez a7, 2f + retw + +1: addi a2, a2, -PAGE_SIZE + idtlb a2 + dsync + bnez a7, 2f + retw + +2: addi a3, a3, -PAGE_SIZE+1 + idtlb a3 + dsync + + retw + +#endif + +#if (DCACHE_WAY_SIZE > PAGE_SIZE) + +/* + * void __flush_invalidate_dcache_page_alias (addr, phys) + * a2 a3 + */ + +ENTRY(__flush_invalidate_dcache_page_alias) + entry sp, 16 + + movi a7, 0 # required for exception handler + addi a6, a3, (PAGE_KERNEL | _PAGE_HW_WRITE) + mov a4, a2 + wdtlb a6, a2 + dsync + + ___flush_invalidate_dcache_page a2 a3 + + idtlb a4 + dsync + + retw + +#endif + +ENTRY(__tlbtemp_mapping_itlb) + +#if (ICACHE_WAY_SIZE > PAGE_SIZE) + +ENTRY(__invalidate_icache_page_alias) + entry sp, 16 + + addi a6, a3, (PAGE_KERNEL_EXEC | _PAGE_HW_WRITE) + mov a4, a2 + witlb a6, a2 + isync + + ___invalidate_icache_page a2 a3 + + iitlb a4 + isync + retw + +#endif + +/* End of special treatment in tlb miss exception */ + +ENTRY(__tlbtemp_mapping_end) +#endif /* CONFIG_MMU + +/* + * void __invalidate_icache_page(ulong start) + */ + +ENTRY(__invalidate_icache_page) + entry sp, 16 + + ___invalidate_icache_page a2 a3 + isync + + retw + +/* + * void __invalidate_dcache_page(ulong start) + */ + +ENTRY(__invalidate_dcache_page) + entry sp, 16 + + ___invalidate_dcache_page a2 a3 + dsync + + retw + +/* + * void __flush_invalidate_dcache_page(ulong start) + */ + +ENTRY(__flush_invalidate_dcache_page) + entry sp, 16 + + ___flush_invalidate_dcache_page a2 a3 + + dsync + retw + +/* + * void __flush_dcache_page(ulong start) + */ + +ENTRY(__flush_dcache_page) + entry sp, 16 + + ___flush_dcache_page a2 a3 + + dsync + retw + +/* + * void __invalidate_icache_range(ulong start, ulong size) + */ + +ENTRY(__invalidate_icache_range) + entry sp, 16 + + ___invalidate_icache_range a2 a3 a4 + isync + + retw + +/* + * void __flush_invalidate_dcache_range(ulong start, ulong size) + */ + +ENTRY(__flush_invalidate_dcache_range) + entry sp, 16 + + ___flush_invalidate_dcache_range a2 a3 a4 + dsync + + retw + +/* + * void _flush_dcache_range(ulong start, ulong size) + */ + +ENTRY(__flush_dcache_range) + entry sp, 16 + + ___flush_dcache_range a2 a3 a4 + dsync + + retw + +/* + * void _invalidate_dcache_range(ulong start, ulong size) + */ + +ENTRY(__invalidate_dcache_range) + entry sp, 16 + + ___invalidate_dcache_range a2 a3 a4 + + retw + +/* + * void _invalidate_icache_all(void) + */ + +ENTRY(__invalidate_icache_all) + entry sp, 16 + + ___invalidate_icache_all a2 a3 + isync + + retw + +/* + * void _flush_invalidate_dcache_all(void) + */ + +ENTRY(__flush_invalidate_dcache_all) + entry sp, 16 + + ___flush_invalidate_dcache_all a2 a3 + dsync + + retw + +/* + * void _invalidate_dcache_all(void) + */ + +ENTRY(__invalidate_dcache_all) + entry sp, 16 + + ___invalidate_dcache_all a2 a3 + dsync + + retw + diff --git a/arch/xtensa/mm/mmu.c b/arch/xtensa/mm/mmu.c new file mode 100644 index 00000000..ca81654f --- /dev/null +++ b/arch/xtensa/mm/mmu.c @@ -0,0 +1,68 @@ +/* + * xtensa mmu stuff + * + * Extracted from init.c + */ +#include <linux/percpu.h> +#include <linux/init.h> +#include <linux/string.h> +#include <linux/slab.h> +#include <linux/cache.h> + +#include <asm/tlb.h> +#include <asm/tlbflush.h> +#include <asm/mmu_context.h> +#include <asm/page.h> + +void __init paging_init(void) +{ + memset(swapper_pg_dir, 0, PAGE_SIZE); +} + +/* + * Flush the mmu and reset associated register to default values. + */ +void __init init_mmu(void) +{ + /* Writing zeros to the <t>TLBCFG special registers ensure + * that valid values exist in the register. For existing + * PGSZID<w> fields, zero selects the first element of the + * page-size array. For nonexistent PGSZID<w> fields, zero is + * the best value to write. Also, when changing PGSZID<w> + * fields, the corresponding TLB must be flushed. + */ + set_itlbcfg_register(0); + set_dtlbcfg_register(0); + flush_tlb_all(); + + /* Set rasid register to a known value. */ + + set_rasid_register(ASID_USER_FIRST); + + /* Set PTEVADDR special register to the start of the page + * table, which is in kernel mappable space (ie. not + * statically mapped). This register's value is undefined on + * reset. + */ + set_ptevaddr_register(PGTABLE_START); +} + +struct kmem_cache *pgtable_cache __read_mostly; + +static void pgd_ctor(void *addr) +{ + pte_t *ptep = (pte_t *)addr; + int i; + + for (i = 0; i < 1024; i++, ptep++) + pte_clear(NULL, 0, ptep); + +} + +void __init pgtable_cache_init(void) +{ + pgtable_cache = kmem_cache_create("pgd", + PAGE_SIZE, PAGE_SIZE, + SLAB_HWCACHE_ALIGN, + pgd_ctor); +} diff --git a/arch/xtensa/mm/tlb.c b/arch/xtensa/mm/tlb.c new file mode 100644 index 00000000..e2700b21 --- /dev/null +++ b/arch/xtensa/mm/tlb.c @@ -0,0 +1,143 @@ +/* + * arch/xtensa/mm/tlb.c + * + * Logic that manipulates the Xtensa MMU. Derived from MIPS. + * + * 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) 2001 - 2003 Tensilica Inc. + * + * Joe Taylor + * Chris Zankel <chris@zankel.net> + * Marc Gauthier + */ + +#include <linux/mm.h> +#include <asm/processor.h> +#include <asm/mmu_context.h> +#include <asm/tlbflush.h> +#include <asm/cacheflush.h> + + +static inline void __flush_itlb_all (void) +{ + int w, i; + + for (w = 0; w < ITLB_ARF_WAYS; w++) { + for (i = 0; i < (1 << XCHAL_ITLB_ARF_ENTRIES_LOG2); i++) { + int e = w + (i << PAGE_SHIFT); + invalidate_itlb_entry_no_isync(e); + } + } + asm volatile ("isync\n"); +} + +static inline void __flush_dtlb_all (void) +{ + int w, i; + + for (w = 0; w < DTLB_ARF_WAYS; w++) { + for (i = 0; i < (1 << XCHAL_DTLB_ARF_ENTRIES_LOG2); i++) { + int e = w + (i << PAGE_SHIFT); + invalidate_dtlb_entry_no_isync(e); + } + } + asm volatile ("isync\n"); +} + + +void flush_tlb_all (void) +{ + __flush_itlb_all(); + __flush_dtlb_all(); +} + +/* If mm is current, we simply assign the current task a new ASID, thus, + * invalidating all previous tlb entries. If mm is someone else's user mapping, + * wie invalidate the context, thus, when that user mapping is swapped in, + * a new context will be assigned to it. + */ + +void flush_tlb_mm(struct mm_struct *mm) +{ + if (mm == current->active_mm) { + int flags; + local_save_flags(flags); + __get_new_mmu_context(mm); + __load_mmu_context(mm); + local_irq_restore(flags); + } + else + mm->context = 0; +} + +#define _ITLB_ENTRIES (ITLB_ARF_WAYS << XCHAL_ITLB_ARF_ENTRIES_LOG2) +#define _DTLB_ENTRIES (DTLB_ARF_WAYS << XCHAL_DTLB_ARF_ENTRIES_LOG2) +#if _ITLB_ENTRIES > _DTLB_ENTRIES +# define _TLB_ENTRIES _ITLB_ENTRIES +#else +# define _TLB_ENTRIES _DTLB_ENTRIES +#endif + +void flush_tlb_range (struct vm_area_struct *vma, + unsigned long start, unsigned long end) +{ + struct mm_struct *mm = vma->vm_mm; + unsigned long flags; + + if (mm->context == NO_CONTEXT) + return; + +#if 0 + printk("[tlbrange<%02lx,%08lx,%08lx>]\n", + (unsigned long)mm->context, start, end); +#endif + local_save_flags(flags); + + if (end-start + (PAGE_SIZE-1) <= _TLB_ENTRIES << PAGE_SHIFT) { + int oldpid = get_rasid_register(); + set_rasid_register (ASID_INSERT(mm->context)); + start &= PAGE_MASK; + if (vma->vm_flags & VM_EXEC) + while(start < end) { + invalidate_itlb_mapping(start); + invalidate_dtlb_mapping(start); + start += PAGE_SIZE; + } + else + while(start < end) { + invalidate_dtlb_mapping(start); + start += PAGE_SIZE; + } + + set_rasid_register(oldpid); + } else { + flush_tlb_mm(mm); + } + local_irq_restore(flags); +} + +void flush_tlb_page (struct vm_area_struct *vma, unsigned long page) +{ + struct mm_struct* mm = vma->vm_mm; + unsigned long flags; + int oldpid; + + if(mm->context == NO_CONTEXT) + return; + + local_save_flags(flags); + + oldpid = get_rasid_register(); + + if (vma->vm_flags & VM_EXEC) + invalidate_itlb_mapping(page); + invalidate_dtlb_mapping(page); + + set_rasid_register(oldpid); + + local_irq_restore(flags); +} + diff --git a/arch/xtensa/platforms/iss/Makefile b/arch/xtensa/platforms/iss/Makefile new file mode 100644 index 00000000..af96e314 --- /dev/null +++ b/arch/xtensa/platforms/iss/Makefile @@ -0,0 +1,8 @@ +# $Id: Makefile,v 1.1.1.1 2002/08/28 16:10:14 aroll Exp $ +# +# Makefile for the Xtensa Instruction Set Simulator (ISS) +# "prom monitor" library routines under Linux. +# + +obj-y = io.o console.o setup.o network.o + diff --git a/arch/xtensa/platforms/iss/console.c b/arch/xtensa/platforms/iss/console.c new file mode 100644 index 00000000..f9726f6a --- /dev/null +++ b/arch/xtensa/platforms/iss/console.c @@ -0,0 +1,291 @@ +/* + * arch/xtensa/platforms/iss/console.c + * + * 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) 2001-2005 Tensilica Inc. + * Authors Christian Zankel, Joe Taylor + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/console.h> +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/major.h> +#include <linux/param.h> +#include <linux/seq_file.h> +#include <linux/serial.h> + +#include <asm/uaccess.h> +#include <asm/irq.h> + +#include <platform/simcall.h> + +#include <linux/tty.h> +#include <linux/tty_flip.h> + +#ifdef SERIAL_INLINE +#define _INLINE_ inline +#endif + +#define SERIAL_MAX_NUM_LINES 1 +#define SERIAL_TIMER_VALUE (20 * HZ) + +static struct tty_driver *serial_driver; +static struct tty_port serial_port; +static struct timer_list serial_timer; + +static DEFINE_SPINLOCK(timer_lock); + +int errno; + +static int __simc (int a, int b, int c, int d, int e, int f) __attribute__((__noinline__)); +static int __simc (int a, int b, int c, int d, int e, int f) +{ + int ret; + __asm__ __volatile__ ("simcall\n" + "mov %0, a2\n" + "mov %1, a3\n" : "=a" (ret), "=a" (errno) + : : "a2", "a3"); + return ret; +} + +static char *serial_version = "0.1"; +static char *serial_name = "ISS serial driver"; + +/* + * This routine is called whenever a serial port is opened. It + * enables interrupts for a serial port, linking in its async structure into + * the IRQ chain. It also performs the serial-specific + * initialization for the tty structure. + */ + +static void rs_poll(unsigned long); + +static int rs_open(struct tty_struct *tty, struct file * filp) +{ + tty->port = &serial_port; + spin_lock(&timer_lock); + if (tty->count == 1) { + setup_timer(&serial_timer, rs_poll, (unsigned long)tty); + mod_timer(&serial_timer, jiffies + SERIAL_TIMER_VALUE); + } + spin_unlock(&timer_lock); + + return 0; +} + + +/* + * ------------------------------------------------------------ + * iss_serial_close() + * + * This routine is called when the serial port gets closed. First, we + * wait for the last remaining data to be sent. Then, we unlink its + * async structure from the interrupt chain if necessary, and we free + * that IRQ if nothing is left in the chain. + * ------------------------------------------------------------ + */ +static void rs_close(struct tty_struct *tty, struct file * filp) +{ + spin_lock_bh(&timer_lock); + if (tty->count == 1) + del_timer_sync(&serial_timer); + spin_unlock_bh(&timer_lock); +} + + +static int rs_write(struct tty_struct * tty, + const unsigned char *buf, int count) +{ + /* see drivers/char/serialX.c to reference original version */ + + __simc (SYS_write, 1, (unsigned long)buf, count, 0, 0); + return count; +} + +static void rs_poll(unsigned long priv) +{ + struct tty_struct* tty = (struct tty_struct*) priv; + + struct timeval tv = { .tv_sec = 0, .tv_usec = 0 }; + int i = 0; + unsigned char c; + + spin_lock(&timer_lock); + + while (__simc(SYS_select_one, 0, XTISS_SELECT_ONE_READ, (int)&tv,0,0)){ + __simc (SYS_read, 0, (unsigned long)&c, 1, 0, 0); + tty_insert_flip_char(tty, c, TTY_NORMAL); + i++; + } + + if (i) + tty_flip_buffer_push(tty); + + + mod_timer(&serial_timer, jiffies + SERIAL_TIMER_VALUE); + spin_unlock(&timer_lock); +} + + +static int rs_put_char(struct tty_struct *tty, unsigned char ch) +{ + char buf[2]; + + buf[0] = ch; + buf[1] = '\0'; /* Is this NULL necessary? */ + __simc (SYS_write, 1, (unsigned long) buf, 1, 0, 0); + return 1; +} + +static void rs_flush_chars(struct tty_struct *tty) +{ +} + +static int rs_write_room(struct tty_struct *tty) +{ + /* Let's say iss can always accept 2K characters.. */ + return 2 * 1024; +} + +static int rs_chars_in_buffer(struct tty_struct *tty) +{ + /* the iss doesn't buffer characters */ + return 0; +} + +static void rs_hangup(struct tty_struct *tty) +{ + /* Stub, once again.. */ +} + +static void rs_wait_until_sent(struct tty_struct *tty, int timeout) +{ + /* Stub, once again.. */ +} + +static int rs_proc_show(struct seq_file *m, void *v) +{ + seq_printf(m, "serinfo:1.0 driver:%s\n", serial_version); + return 0; +} + +static int rs_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, rs_proc_show, NULL); +} + +static const struct file_operations rs_proc_fops = { + .owner = THIS_MODULE, + .open = rs_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct tty_operations serial_ops = { + .open = rs_open, + .close = rs_close, + .write = rs_write, + .put_char = rs_put_char, + .flush_chars = rs_flush_chars, + .write_room = rs_write_room, + .chars_in_buffer = rs_chars_in_buffer, + .hangup = rs_hangup, + .wait_until_sent = rs_wait_until_sent, + .proc_fops = &rs_proc_fops, +}; + +int __init rs_init(void) +{ + tty_port_init(&serial_port); + + serial_driver = alloc_tty_driver(SERIAL_MAX_NUM_LINES); + + printk ("%s %s\n", serial_name, serial_version); + + /* Initialize the tty_driver structure */ + + serial_driver->driver_name = "iss_serial"; + serial_driver->name = "ttyS"; + serial_driver->major = TTY_MAJOR; + serial_driver->minor_start = 64; + serial_driver->type = TTY_DRIVER_TYPE_SERIAL; + serial_driver->subtype = SERIAL_TYPE_NORMAL; + serial_driver->init_termios = tty_std_termios; + serial_driver->init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + serial_driver->flags = TTY_DRIVER_REAL_RAW; + + tty_set_operations(serial_driver, &serial_ops); + + if (tty_register_driver(serial_driver)) + panic("Couldn't register serial driver\n"); + return 0; +} + + +static __exit void rs_exit(void) +{ + int error; + + if ((error = tty_unregister_driver(serial_driver))) + printk("ISS_SERIAL: failed to unregister serial driver (%d)\n", + error); + put_tty_driver(serial_driver); +} + + +/* We use `late_initcall' instead of just `__initcall' as a workaround for + * the fact that (1) simcons_tty_init can't be called before tty_init, + * (2) tty_init is called via `module_init', (3) if statically linked, + * module_init == device_init, and (4) there's no ordering of init lists. + * We can do this easily because simcons is always statically linked, but + * other tty drivers that depend on tty_init and which must use + * `module_init' to declare their init routines are likely to be broken. + */ + +late_initcall(rs_init); + + +#ifdef CONFIG_SERIAL_CONSOLE + +static void iss_console_write(struct console *co, const char *s, unsigned count) +{ + int len = strlen(s); + + if (s != 0 && *s != 0) + __simc (SYS_write, 1, (unsigned long)s, + count < len ? count : len,0,0); +} + +static struct tty_driver* iss_console_device(struct console *c, int *index) +{ + *index = c->index; + return serial_driver; +} + + +static struct console sercons = { + .name = "ttyS", + .write = iss_console_write, + .device = iss_console_device, + .flags = CON_PRINTBUFFER, + .index = -1 +}; + +static int __init iss_console_init(void) +{ + register_console(&sercons); + return 0; +} + +console_initcall(iss_console_init); + +#endif /* CONFIG_SERIAL_CONSOLE */ + diff --git a/arch/xtensa/platforms/iss/include/platform/hardware.h b/arch/xtensa/platforms/iss/include/platform/hardware.h new file mode 100644 index 00000000..6930c12a --- /dev/null +++ b/arch/xtensa/platforms/iss/include/platform/hardware.h @@ -0,0 +1,29 @@ +/* + * include/asm-xtensa/platform-iss/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. + * + * Copyright (C) 2001 Tensilica Inc. + */ + +/* + * This file contains the default configuration of ISS. + */ + +#ifndef _XTENSA_PLATFORM_ISS_HARDWARE_H +#define _XTENSA_PLATFORM_ISS_HARDWARE_H + +/* + * Memory configuration. + */ + +#define PLATFORM_DEFAULT_MEM_START 0x00000000 +#define PLATFORM_DEFAULT_MEM_SIZE 0x08000000 + +/* + * Interrupt configuration. + */ + +#endif /* _XTENSA_PLATFORM_ISS_HARDWARE_H */ diff --git a/arch/xtensa/platforms/iss/include/platform/simcall.h b/arch/xtensa/platforms/iss/include/platform/simcall.h new file mode 100644 index 00000000..b7952c06 --- /dev/null +++ b/arch/xtensa/platforms/iss/include/platform/simcall.h @@ -0,0 +1,62 @@ +/* + * include/asm-xtensa/platform-iss/simcall.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001 Tensilica Inc. + */ + +#ifndef _XTENSA_PLATFORM_ISS_SIMCALL_H +#define _XTENSA_PLATFORM_ISS_SIMCALL_H + + +/* + * System call like services offered by the simulator host. + */ + +#define SYS_nop 0 /* unused */ +#define SYS_exit 1 /*x*/ +#define SYS_fork 2 +#define SYS_read 3 /*x*/ +#define SYS_write 4 /*x*/ +#define SYS_open 5 /*x*/ +#define SYS_close 6 /*x*/ +#define SYS_rename 7 /*x 38 - waitpid */ +#define SYS_creat 8 /*x*/ +#define SYS_link 9 /*x (not implemented on WIN32) */ +#define SYS_unlink 10 /*x*/ +#define SYS_execv 11 /* n/a - execve */ +#define SYS_execve 12 /* 11 - chdir */ +#define SYS_pipe 13 /* 42 - time */ +#define SYS_stat 14 /* 106 - mknod */ +#define SYS_chmod 15 +#define SYS_chown 16 /* 202 - lchown */ +#define SYS_utime 17 /* 30 - break */ +#define SYS_wait 18 /* n/a - oldstat */ +#define SYS_lseek 19 /*x*/ +#define SYS_getpid 20 +#define SYS_isatty 21 /* n/a - mount */ +#define SYS_fstat 22 /* 108 - oldumount */ +#define SYS_time 23 /* 13 - setuid */ +#define SYS_gettimeofday 24 /*x 78 - getuid (not implemented on WIN32) */ +#define SYS_times 25 /*X 43 - stime (Xtensa-specific implementation) */ +#define SYS_socket 26 +#define SYS_sendto 27 +#define SYS_recvfrom 28 +#define SYS_select_one 29 /* not compitible select, one file descriptor at the time */ +#define SYS_bind 30 +#define SYS_ioctl 31 + +/* + * SYS_select_one specifiers + */ + +#define XTISS_SELECT_ONE_READ 1 +#define XTISS_SELECT_ONE_WRITE 2 +#define XTISS_SELECT_ONE_EXCEPT 3 + + +#endif /* _XTENSA_PLATFORM_ISS_SIMCALL_H */ + diff --git a/arch/xtensa/platforms/iss/io.c b/arch/xtensa/platforms/iss/io.c new file mode 100644 index 00000000..571d0b24 --- /dev/null +++ b/arch/xtensa/platforms/iss/io.c @@ -0,0 +1,32 @@ +/* This file isn't really needed right now. */ + +#if 0 + +#include <asm/io.h> +#include <platform/platform-iss/simcall.h> + +extern int __simc (); + + +char iss_serial_getc() +{ + char c; + __simc( SYS_read, 0, &c, 1 ); + return c; +} + +void iss_serial_putc( char c ) +{ + __simc( SYS_write, 1, &c, 1 ); +} + +void iss_serial_puts( char *s ) +{ + if( s != 0 && *s != 0 ) + __simc( SYS_write, 1, s, strlen(s) ); +} + +/*#error Need I/O ports to specific hardware!*/ + +#endif + diff --git a/arch/xtensa/platforms/iss/network.c b/arch/xtensa/platforms/iss/network.c new file mode 100644 index 00000000..7dde2445 --- /dev/null +++ b/arch/xtensa/platforms/iss/network.c @@ -0,0 +1,826 @@ +/* + * + * arch/xtensa/platforms/iss/network.c + * + * Platform specific initialization. + * + * Authors: Chris Zankel <chris@zankel.net> + * Based on work form the UML team. + * + * Copyright 2005 Tensilica Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/list.h> +#include <linux/irq.h> +#include <linux/spinlock.h> +#include <linux/slab.h> +#include <linux/timer.h> +#include <linux/if_ether.h> +#include <linux/inetdevice.h> +#include <linux/init.h> +#include <linux/if_tun.h> +#include <linux/etherdevice.h> +#include <linux/interrupt.h> +#include <linux/ioctl.h> +#include <linux/bootmem.h> +#include <linux/ethtool.h> +#include <linux/rtnetlink.h> +#include <linux/platform_device.h> + +#include <platform/simcall.h> + +#define DRIVER_NAME "iss-netdev" +#define ETH_MAX_PACKET 1500 +#define ETH_HEADER_OTHER 14 +#define ISS_NET_TIMER_VALUE (2 * HZ) + + +static DEFINE_SPINLOCK(opened_lock); +static LIST_HEAD(opened); + +static DEFINE_SPINLOCK(devices_lock); +static LIST_HEAD(devices); + +/* ------------------------------------------------------------------------- */ + +/* We currently only support the TUNTAP transport protocol. */ + +#define TRANSPORT_TUNTAP_NAME "tuntap" +#define TRANSPORT_TUNTAP_MTU ETH_MAX_PACKET + +struct tuntap_info { + char dev_name[IFNAMSIZ]; + int fixed_config; + unsigned char gw[ETH_ALEN]; + int fd; +}; + +/* ------------------------------------------------------------------------- */ + + +/* This structure contains out private information for the driver. */ + +struct iss_net_private { + + struct list_head device_list; + struct list_head opened_list; + + spinlock_t lock; + struct net_device *dev; + struct platform_device pdev; + struct timer_list tl; + struct net_device_stats stats; + + struct timer_list timer; + unsigned int timer_val; + + int index; + int mtu; + + unsigned char mac[ETH_ALEN]; + int have_mac; + + struct { + union { + struct tuntap_info tuntap; + } info; + + int (*open)(struct iss_net_private *lp); + void (*close)(struct iss_net_private *lp); + int (*read)(struct iss_net_private *lp, struct sk_buff **skb); + int (*write)(struct iss_net_private *lp, struct sk_buff **skb); + unsigned short (*protocol)(struct sk_buff *skb); + int (*poll)(struct iss_net_private *lp); + } tp; + +}; + +/* ======================= ISS SIMCALL INTERFACE =========================== */ + +/* Note: __simc must _not_ be declared inline! */ + +static int errno; + +static int __simc (int a, int b, int c, int d, int e, int f) __attribute__((__noinline__)); +static int __simc (int a, int b, int c, int d, int e, int f) +{ + int ret; + __asm__ __volatile__ ("simcall\n" + "mov %0, a2\n" + "mov %1, a3\n" : "=a" (ret), "=a" (errno) + : : "a2", "a3"); + return ret; +} + +static int inline simc_open(char *file, int flags, int mode) +{ + return __simc(SYS_open, (int) file, flags, mode, 0, 0); +} + +static int inline simc_close(int fd) +{ + return __simc(SYS_close, fd, 0, 0, 0, 0); +} + +static int inline simc_ioctl(int fd, int request, void *arg) +{ + return __simc(SYS_ioctl, fd, request, (int) arg, 0, 0); +} + +static int inline simc_read(int fd, void *buf, size_t count) +{ + return __simc(SYS_read, fd, (int) buf, count, 0, 0); +} + +static int inline simc_write(int fd, void *buf, size_t count) +{ + return __simc(SYS_write, fd, (int) buf, count, 0, 0); +} + +static int inline simc_poll(int fd) +{ + struct timeval tv = { .tv_sec = 0, .tv_usec = 0 }; + + return __simc(SYS_select_one, fd, XTISS_SELECT_ONE_READ, (int)&tv,0,0); +} + +/* ================================ HELPERS ================================ */ + + +static char *split_if_spec(char *str, ...) +{ + char **arg, *end; + va_list ap; + + va_start(ap, str); + while ((arg = va_arg(ap, char**)) != NULL) { + if (*str == '\0') + return NULL; + end = strchr(str, ','); + if (end != str) + *arg = str; + if (end == NULL) + return NULL; + *end ++ = '\0'; + str = end; + } + va_end(ap); + return str; +} + + +#if 0 +/* Adjust SKB. */ + +struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra) +{ + if ((skb != NULL) && (skb_tailroom(skb) < extra)) { + struct sk_buff *skb2; + + skb2 = skb_copy_expand(skb, 0, extra, GFP_ATOMIC); + dev_kfree_skb(skb); + skb = skb2; + } + if (skb != NULL) + skb_put(skb, extra); + + return skb; +} +#endif + +/* Return the IP address as a string for a given device. */ + +static void dev_ip_addr(void *d, char *buf, char *bin_buf) +{ + struct net_device *dev = d; + struct in_device *ip = dev->ip_ptr; + struct in_ifaddr *in; + __be32 addr; + + if ((ip == NULL) || ((in = ip->ifa_list) == NULL)) { + printk(KERN_WARNING "Device not assigned an IP address!\n"); + return; + } + + addr = in->ifa_address; + sprintf(buf, "%d.%d.%d.%d", addr & 0xff, (addr >> 8) & 0xff, + (addr >> 16) & 0xff, addr >> 24); + + if (bin_buf) { + bin_buf[0] = addr & 0xff; + bin_buf[1] = (addr >> 8) & 0xff; + bin_buf[2] = (addr >> 16) & 0xff; + bin_buf[3] = addr >> 24; + } +} + +/* Set Ethernet address of the specified device. */ + +static void inline set_ether_mac(void *d, unsigned char *addr) +{ + struct net_device *dev = d; + memcpy(dev->dev_addr, addr, ETH_ALEN); +} + + +/* ======================= TUNTAP TRANSPORT INTERFACE ====================== */ + +static int tuntap_open(struct iss_net_private *lp) +{ + struct ifreq ifr; + char *dev_name = lp->tp.info.tuntap.dev_name; + int err = -EINVAL; + int fd; + + /* We currently only support a fixed configuration. */ + + if (!lp->tp.info.tuntap.fixed_config) + return -EINVAL; + + if ((fd = simc_open("/dev/net/tun", 02, 0)) < 0) { /* O_RDWR */ + printk("Failed to open /dev/net/tun, returned %d " + "(errno = %d)\n", fd, errno); + return fd; + } + + memset(&ifr, 0, sizeof ifr); + ifr.ifr_flags = IFF_TAP | IFF_NO_PI; + strlcpy(ifr.ifr_name, dev_name, sizeof ifr.ifr_name); + + if ((err = simc_ioctl(fd, TUNSETIFF, (void*) &ifr)) < 0) { + printk("Failed to set interface, returned %d " + "(errno = %d)\n", err, errno); + simc_close(fd); + return err; + } + + lp->tp.info.tuntap.fd = fd; + return err; +} + +static void tuntap_close(struct iss_net_private *lp) +{ +#if 0 + if (lp->tp.info.tuntap.fixed_config) + iter_addresses(lp->tp.info.tuntap.dev, close_addr, lp->host.dev_name); +#endif + simc_close(lp->tp.info.tuntap.fd); + lp->tp.info.tuntap.fd = -1; +} + +static int tuntap_read (struct iss_net_private *lp, struct sk_buff **skb) +{ +#if 0 + *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER); + if (*skb == NULL) + return -ENOMEM; +#endif + + return simc_read(lp->tp.info.tuntap.fd, + (*skb)->data, (*skb)->dev->mtu + ETH_HEADER_OTHER); +} + +static int tuntap_write (struct iss_net_private *lp, struct sk_buff **skb) +{ + return simc_write(lp->tp.info.tuntap.fd, (*skb)->data, (*skb)->len); +} + +unsigned short tuntap_protocol(struct sk_buff *skb) +{ + return eth_type_trans(skb, skb->dev); +} + +static int tuntap_poll(struct iss_net_private *lp) +{ + return simc_poll(lp->tp.info.tuntap.fd); +} + +/* + * Currently only a device name is supported. + * ethX=tuntap[,[mac address][,[device name]]] + */ + +static int tuntap_probe(struct iss_net_private *lp, int index, char *init) +{ + const int len = strlen(TRANSPORT_TUNTAP_NAME); + char *dev_name = NULL, *mac_str = NULL, *rem = NULL; + + /* Transport should be 'tuntap': ethX=tuntap,mac,dev_name */ + + if (strncmp(init, TRANSPORT_TUNTAP_NAME, len)) + return 0; + + if (*(init += strlen(TRANSPORT_TUNTAP_NAME)) == ',') { + if ((rem=split_if_spec(init+1, &mac_str, &dev_name)) != NULL) { + printk("Extra garbage on specification : '%s'\n", rem); + return 0; + } + } else if (*init != '\0') { + printk("Invalid argument: %s. Skipping device!\n", init); + return 0; + } + + if (dev_name) { + strncpy(lp->tp.info.tuntap.dev_name, dev_name, + sizeof lp->tp.info.tuntap.dev_name); + lp->tp.info.tuntap.fixed_config = 1; + } else + strcpy(lp->tp.info.tuntap.dev_name, TRANSPORT_TUNTAP_NAME); + + +#if 0 + if (setup_etheraddr(mac_str, lp->mac)) + lp->have_mac = 1; +#endif + lp->mtu = TRANSPORT_TUNTAP_MTU; + + //lp->info.tuntap.gate_addr = gate_addr; + + lp->tp.info.tuntap.fd = -1; + + lp->tp.open = tuntap_open; + lp->tp.close = tuntap_close; + lp->tp.read = tuntap_read; + lp->tp.write = tuntap_write; + lp->tp.protocol = tuntap_protocol; + lp->tp.poll = tuntap_poll; + + printk("TUN/TAP backend - "); +#if 0 + if (lp->host.gate_addr != NULL) + printk("IP = %s", lp->host.gate_addr); +#endif + printk("\n"); + + return 1; +} + +/* ================================ ISS NET ================================ */ + +static int iss_net_rx(struct net_device *dev) +{ + struct iss_net_private *lp = netdev_priv(dev); + int pkt_len; + struct sk_buff *skb; + + /* Check if there is any new data. */ + + if (lp->tp.poll(lp) == 0) + return 0; + + /* Try to allocate memory, if it fails, try again next round. */ + + if ((skb = dev_alloc_skb(dev->mtu + 2 + ETH_HEADER_OTHER)) == NULL) { + lp->stats.rx_dropped++; + return 0; + } + + skb_reserve(skb, 2); + + /* Setup skb */ + + skb->dev = dev; + skb_reset_mac_header(skb); + pkt_len = lp->tp.read(lp, &skb); + skb_put(skb, pkt_len); + + if (pkt_len > 0) { + skb_trim(skb, pkt_len); + skb->protocol = lp->tp.protocol(skb); + + lp->stats.rx_bytes += skb->len; + lp->stats.rx_packets++; + // netif_rx(skb); + netif_rx_ni(skb); + return pkt_len; + } + kfree_skb(skb); + return pkt_len; +} + +static int iss_net_poll(void) +{ + struct list_head *ele; + int err, ret = 0; + + spin_lock(&opened_lock); + + list_for_each(ele, &opened) { + struct iss_net_private *lp; + + lp = list_entry(ele, struct iss_net_private, opened_list); + + if (!netif_running(lp->dev)) + break; + + spin_lock(&lp->lock); + + while ((err = iss_net_rx(lp->dev)) > 0) + ret++; + + spin_unlock(&lp->lock); + + if (err < 0) { + printk(KERN_ERR "Device '%s' read returned %d, " + "shutting it down\n", lp->dev->name, err); + dev_close(lp->dev); + } else { + // FIXME reactivate_fd(lp->fd, ISS_ETH_IRQ); + } + } + + spin_unlock(&opened_lock); + return ret; +} + + +static void iss_net_timer(unsigned long priv) +{ + struct iss_net_private* lp = (struct iss_net_private*) priv; + + spin_lock(&lp->lock); + + iss_net_poll(); + + mod_timer(&lp->timer, jiffies + lp->timer_val); + + spin_unlock(&lp->lock); +} + + +static int iss_net_open(struct net_device *dev) +{ + struct iss_net_private *lp = netdev_priv(dev); + char addr[sizeof "255.255.255.255\0"]; + int err; + + spin_lock(&lp->lock); + + if ((err = lp->tp.open(lp)) < 0) + goto out; + + if (!lp->have_mac) { + dev_ip_addr(dev, addr, &lp->mac[2]); + set_ether_mac(dev, lp->mac); + } + + netif_start_queue(dev); + + /* clear buffer - it can happen that the host side of the interface + * is full when we get here. In this case, new data is never queued, + * SIGIOs never arrive, and the net never works. + */ + while ((err = iss_net_rx(dev)) > 0) + ; + + spin_lock(&opened_lock); + list_add(&lp->opened_list, &opened); + spin_unlock(&opened_lock); + + init_timer(&lp->timer); + lp->timer_val = ISS_NET_TIMER_VALUE; + lp->timer.data = (unsigned long) lp; + lp->timer.function = iss_net_timer; + mod_timer(&lp->timer, jiffies + lp->timer_val); + +out: + spin_unlock(&lp->lock); + return err; +} + +static int iss_net_close(struct net_device *dev) +{ + struct iss_net_private *lp = netdev_priv(dev); +printk("iss_net_close!\n"); + netif_stop_queue(dev); + spin_lock(&lp->lock); + + spin_lock(&opened_lock); + list_del(&opened); + spin_unlock(&opened_lock); + + del_timer_sync(&lp->timer); + + lp->tp.close(lp); + + spin_unlock(&lp->lock); + return 0; +} + +static int iss_net_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct iss_net_private *lp = netdev_priv(dev); + unsigned long flags; + int len; + + netif_stop_queue(dev); + spin_lock_irqsave(&lp->lock, flags); + + len = lp->tp.write(lp, &skb); + + if (len == skb->len) { + lp->stats.tx_packets++; + lp->stats.tx_bytes += skb->len; + dev->trans_start = jiffies; + netif_start_queue(dev); + + /* this is normally done in the interrupt when tx finishes */ + netif_wake_queue(dev); + + } else if (len == 0) { + netif_start_queue(dev); + lp->stats.tx_dropped++; + + } else { + netif_start_queue(dev); + printk(KERN_ERR "iss_net_start_xmit: failed(%d)\n", len); + } + + spin_unlock_irqrestore(&lp->lock, flags); + + dev_kfree_skb(skb); + return NETDEV_TX_OK; +} + + +static struct net_device_stats *iss_net_get_stats(struct net_device *dev) +{ + struct iss_net_private *lp = netdev_priv(dev); + return &lp->stats; +} + +static void iss_net_set_multicast_list(struct net_device *dev) +{ +#if 0 + if (dev->flags & IFF_PROMISC) + return; + else if (!netdev_mc_empty(dev)) + dev->flags |= IFF_ALLMULTI; + else + dev->flags &= ~IFF_ALLMULTI; +#endif +} + +static void iss_net_tx_timeout(struct net_device *dev) +{ +#if 0 + dev->trans_start = jiffies; + netif_wake_queue(dev); +#endif +} + +static int iss_net_set_mac(struct net_device *dev, void *addr) +{ +#if 0 + struct iss_net_private *lp = netdev_priv(dev); + struct sockaddr *hwaddr = addr; + + spin_lock(&lp->lock); + memcpy(dev->dev_addr, hwaddr->sa_data, ETH_ALEN); + spin_unlock(&lp->lock); +#endif + + return 0; +} + +static int iss_net_change_mtu(struct net_device *dev, int new_mtu) +{ +#if 0 + struct iss_net_private *lp = netdev_priv(dev); + int err = 0; + + spin_lock(&lp->lock); + + // FIXME not needed new_mtu = transport_set_mtu(new_mtu, &lp->user); + + if (new_mtu < 0) + err = new_mtu; + else + dev->mtu = new_mtu; + + spin_unlock(&lp->lock); + return err; +#endif + return -EINVAL; +} + +void iss_net_user_timer_expire(unsigned long _conn) +{ +} + + +static struct platform_driver iss_net_driver = { + .driver = { + .name = DRIVER_NAME, + }, +}; + +static int driver_registered; + +static const struct net_device_ops iss_netdev_ops = { + .ndo_open = iss_net_open, + .ndo_stop = iss_net_close, + .ndo_get_stats = iss_net_get_stats, + .ndo_start_xmit = iss_net_start_xmit, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = iss_net_change_mtu, + .ndo_set_mac_address = iss_net_set_mac, + //.ndo_do_ioctl = iss_net_ioctl, + .ndo_tx_timeout = iss_net_tx_timeout, + .ndo_set_rx_mode = iss_net_set_multicast_list, +}; + +static int iss_net_configure(int index, char *init) +{ + struct net_device *dev; + struct iss_net_private *lp; + int err; + + if ((dev = alloc_etherdev(sizeof *lp)) == NULL) { + printk(KERN_ERR "eth_configure: failed to allocate device\n"); + return 1; + } + + /* Initialize private element. */ + + lp = netdev_priv(dev); + *lp = ((struct iss_net_private) { + .device_list = LIST_HEAD_INIT(lp->device_list), + .opened_list = LIST_HEAD_INIT(lp->opened_list), + .lock = __SPIN_LOCK_UNLOCKED(lp.lock), + .dev = dev, + .index = index, + //.fd = -1, + .mac = { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0 }, + .have_mac = 0, + }); + + /* + * Try all transport protocols. + * Note: more protocols can be added by adding '&& !X_init(lp, eth)'. + */ + + if (!tuntap_probe(lp, index, init)) { + printk("Invalid arguments. Skipping device!\n"); + goto errout; + } + + printk(KERN_INFO "Netdevice %d ", index); + if (lp->have_mac) + printk("(%pM) ", lp->mac); + printk(": "); + + /* sysfs register */ + + if (!driver_registered) { + platform_driver_register(&iss_net_driver); + driver_registered = 1; + } + + spin_lock(&devices_lock); + list_add(&lp->device_list, &devices); + spin_unlock(&devices_lock); + + lp->pdev.id = index; + lp->pdev.name = DRIVER_NAME; + platform_device_register(&lp->pdev); + SET_NETDEV_DEV(dev,&lp->pdev.dev); + + /* + * If this name ends up conflicting with an existing registered + * netdevice, that is OK, register_netdev{,ice}() will notice this + * and fail. + */ + snprintf(dev->name, sizeof dev->name, "eth%d", index); + + dev->netdev_ops = &iss_netdev_ops; + dev->mtu = lp->mtu; + dev->watchdog_timeo = (HZ >> 1); + dev->irq = -1; + + rtnl_lock(); + err = register_netdevice(dev); + rtnl_unlock(); + + if (err) { + printk("Error registering net device!\n"); + /* XXX: should we call ->remove() here? */ + free_netdev(dev); + return 1; + } + + init_timer(&lp->tl); + lp->tl.function = iss_net_user_timer_expire; + +#if 0 + if (lp->have_mac) + set_ether_mac(dev, lp->mac); +#endif + return 0; + +errout: + // FIXME: unregister; free, etc.. + return -EIO; + +} + +/* ------------------------------------------------------------------------- */ + +/* Filled in during early boot */ + +struct list_head eth_cmd_line = LIST_HEAD_INIT(eth_cmd_line); + +struct iss_net_init { + struct list_head list; + char *init; /* init string */ + int index; +}; + +/* + * Parse the command line and look for 'ethX=...' fields, and register all + * those fields. They will be later initialized in iss_net_init. + */ + +#define ERR KERN_ERR "iss_net_setup: " + +static int iss_net_setup(char *str) +{ + struct iss_net_private *device = NULL; + struct iss_net_init *new; + struct list_head *ele; + char *end; + int n; + + n = simple_strtoul(str, &end, 0); + if (end == str) { + printk(ERR "Failed to parse '%s'\n", str); + return 1; + } + if (n < 0) { + printk(ERR "Device %d is negative\n", n); + return 1; + } + if (*(str = end) != '=') { + printk(ERR "Expected '=' after device number\n"); + return 1; + } + + spin_lock(&devices_lock); + + list_for_each(ele, &devices) { + device = list_entry(ele, struct iss_net_private, device_list); + if (device->index == n) + break; + } + + spin_unlock(&devices_lock); + + if (device && device->index == n) { + printk(ERR "Device %d already configured\n", n); + return 1; + } + + if ((new = alloc_bootmem(sizeof new)) == NULL) { + printk("Alloc_bootmem failed\n"); + return 1; + } + + INIT_LIST_HEAD(&new->list); + new->index = n; + new->init = str + 1; + + list_add_tail(&new->list, ð_cmd_line); + return 1; +} + +#undef ERR + +__setup("eth=", iss_net_setup); + +/* + * Initialize all ISS Ethernet devices previously registered in iss_net_setup. + */ + +static int iss_net_init(void) +{ + struct list_head *ele, *next; + + /* Walk through all Ethernet devices specified in the command line. */ + + list_for_each_safe(ele, next, ð_cmd_line) { + struct iss_net_init *eth; + eth = list_entry(ele, struct iss_net_init, list); + iss_net_configure(eth->index, eth->init); + } + + return 1; +} + +module_init(iss_net_init); + diff --git a/arch/xtensa/platforms/iss/setup.c b/arch/xtensa/platforms/iss/setup.c new file mode 100644 index 00000000..f60c8cf6 --- /dev/null +++ b/arch/xtensa/platforms/iss/setup.c @@ -0,0 +1,110 @@ +/* + * + * arch/xtensa/platform-iss/setup.c + * + * Platform specific initialization. + * + * Authors: Chris Zankel <chris@zankel.net> + * Joe Taylor <joe@tensilica.com> + * + * Copyright 2001 - 2005 Tensilica Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/reboot.h> +#include <linux/kdev_t.h> +#include <linux/types.h> +#include <linux/major.h> +#include <linux/blkdev.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/stringify.h> +#include <linux/notifier.h> + +#include <asm/platform.h> +#include <asm/bootparam.h> + + +void __init platform_init(bp_tag_t* bootparam) +{ + +} + +void platform_halt(void) +{ + printk (" ** Called platform_halt(), looping forever! **\n"); + while (1); +} + +void platform_power_off(void) +{ + printk (" ** Called platform_power_off(), looping forever! **\n"); + while (1); +} +void platform_restart(void) +{ + /* Flush and reset the mmu, simulate a processor reset, and + * jump to the reset vector. */ + + __asm__ __volatile__("movi a2, 15\n\t" + "wsr a2, " __stringify(ICOUNTLEVEL) "\n\t" + "movi a2, 0\n\t" + "wsr a2, " __stringify(ICOUNT) "\n\t" + "wsr a2, " __stringify(IBREAKENABLE) "\n\t" + "wsr a2, " __stringify(LCOUNT) "\n\t" + "movi a2, 0x1f\n\t" + "wsr a2, " __stringify(PS) "\n\t" + "isync\n\t" + "jx %0\n\t" + : + : "a" (XCHAL_RESET_VECTOR_VADDR) + : "a2"); + + /* control never gets here */ +} + +extern void iss_net_poll(void); + +const char twirl[]="|/-\\|/-\\"; + +void platform_heartbeat(void) +{ +#if 0 + static int i = 0, j = 0; + + if (--i < 0) { + i = 99; + printk("\r%c\r", twirl[j++]); + if (j == 8) + j = 0; + } +#endif +} + + + +static int +iss_panic_event(struct notifier_block *this, unsigned long event, void *ptr) +{ + __asm__ __volatile__("movi a2, -1; simcall\n"); + return NOTIFY_DONE; +} + +static struct notifier_block iss_panic_block = { + iss_panic_event, + NULL, + 0 +}; + +void __init platform_setup(char **p_cmdline) +{ + atomic_notifier_chain_register(&panic_notifier_list, &iss_panic_block); +} diff --git a/arch/xtensa/platforms/s6105/Makefile b/arch/xtensa/platforms/s6105/Makefile new file mode 100644 index 00000000..0be6194b --- /dev/null +++ b/arch/xtensa/platforms/s6105/Makefile @@ -0,0 +1,3 @@ +# Makefile for the Stretch S6105 eval board + +obj-y := setup.o device.o diff --git a/arch/xtensa/platforms/s6105/device.c b/arch/xtensa/platforms/s6105/device.c new file mode 100644 index 00000000..4f4fc971 --- /dev/null +++ b/arch/xtensa/platforms/s6105/device.c @@ -0,0 +1,161 @@ +/* + * s6105 platform devices + * + * Copyright (c) 2009 emlix GmbH + */ + +#include <linux/kernel.h> +#include <linux/gpio.h> +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/phy.h> +#include <linux/platform_device.h> +#include <linux/serial.h> +#include <linux/serial_8250.h> + +#include <variant/hardware.h> +#include <variant/dmac.h> + +#include <platform/gpio.h> + +#define GPIO3_INTNUM 3 +#define UART_INTNUM 4 +#define GMAC_INTNUM 5 + +static const signed char gpio3_irq_mappings[] = { + S6_INTC_GPIO(3), + -1 +}; + +static const signed char uart_irq_mappings[] = { + S6_INTC_UART(0), + S6_INTC_UART(1), + -1, +}; + +static const signed char gmac_irq_mappings[] = { + S6_INTC_GMAC_STAT, + S6_INTC_GMAC_ERR, + S6_INTC_DMA_HOSTTERMCNT(0), + S6_INTC_DMA_HOSTTERMCNT(1), + -1 +}; + +const signed char *platform_irq_mappings[NR_IRQS] = { + [GPIO3_INTNUM] = gpio3_irq_mappings, + [UART_INTNUM] = uart_irq_mappings, + [GMAC_INTNUM] = gmac_irq_mappings, +}; + +static struct plat_serial8250_port serial_platform_data[] = { + { + .membase = (void *)S6_REG_UART + 0x0000, + .mapbase = S6_REG_UART + 0x0000, + .irq = UART_INTNUM, + .uartclk = S6_SCLK, + .regshift = 2, + .iotype = SERIAL_IO_MEM, + .flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST, + }, + { + .membase = (void *)S6_REG_UART + 0x1000, + .mapbase = S6_REG_UART + 0x1000, + .irq = UART_INTNUM, + .uartclk = S6_SCLK, + .regshift = 2, + .iotype = SERIAL_IO_MEM, + .flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST, + }, + { }, +}; + +static struct resource s6_gmac_resource[] = { + { + .name = "mem", + .start = (resource_size_t)S6_REG_GMAC, + .end = (resource_size_t)S6_REG_GMAC + 0x10000 - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "dma", + .start = (resource_size_t) + DMA_CHNL(S6_REG_HIFDMA, S6_HIFDMA_GMACTX), + .end = (resource_size_t) + DMA_CHNL(S6_REG_HIFDMA, S6_HIFDMA_GMACTX) + 0x100 - 1, + .flags = IORESOURCE_DMA, + }, + { + .name = "dma", + .start = (resource_size_t) + DMA_CHNL(S6_REG_HIFDMA, S6_HIFDMA_GMACRX), + .end = (resource_size_t) + DMA_CHNL(S6_REG_HIFDMA, S6_HIFDMA_GMACRX) + 0x100 - 1, + .flags = IORESOURCE_DMA, + }, + { + .name = "io", + .start = (resource_size_t)S6_MEM_GMAC, + .end = (resource_size_t)S6_MEM_GMAC + 0x2000000 - 1, + .flags = IORESOURCE_IO, + }, + { + .name = "irq", + .start = (resource_size_t)GMAC_INTNUM, + .flags = IORESOURCE_IRQ, + }, + { + .name = "irq", + .start = (resource_size_t)PHY_POLL, + .flags = IORESOURCE_IRQ, + }, +}; + +static int __init prepare_phy_irq(int pin) +{ + int irq; + if (gpio_request(pin, "s6gmac_phy") < 0) + goto fail; + if (gpio_direction_input(pin) < 0) + goto free; + irq = gpio_to_irq(pin); + if (irq < 0) + goto free; + if (irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW) < 0) + goto free; + return irq; +free: + gpio_free(pin); +fail: + return PHY_POLL; +} + +static struct platform_device platform_devices[] = { + { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = serial_platform_data, + }, + }, + { + .name = "s6gmac", + .id = 0, + .resource = s6_gmac_resource, + .num_resources = ARRAY_SIZE(s6_gmac_resource), + }, + { + I2C_BOARD_INFO("m41t62", S6I2C_ADDR_M41T62), + }, +}; + +static int __init device_init(void) +{ + int i; + + s6_gmac_resource[5].start = prepare_phy_irq(GPIO_PHY_IRQ); + + for (i = 0; i < ARRAY_SIZE(platform_devices); i++) + platform_device_register(&platform_devices[i]); + return 0; +} +arch_initcall_sync(device_init); diff --git a/arch/xtensa/platforms/s6105/include/platform/gpio.h b/arch/xtensa/platforms/s6105/include/platform/gpio.h new file mode 100644 index 00000000..fa11aa4b --- /dev/null +++ b/arch/xtensa/platforms/s6105/include/platform/gpio.h @@ -0,0 +1,27 @@ +#ifndef __ASM_XTENSA_S6105_GPIO_H +#define __ASM_XTENSA_S6105_GPIO_H + +#define GPIO_BP_TEMP_ALARM 0 +#define GPIO_PB_RESET_IN 1 +#define GPIO_EXP_IRQ 2 +#define GPIO_TRIGGER_IRQ 3 +#define GPIO_RTC_IRQ 4 +#define GPIO_PHY_IRQ 5 +#define GPIO_IMAGER_RESET 6 +#define GPIO_SD_IRQ 7 +#define GPIO_MINI_BOOT_INH 8 +#define GPIO_BOARD_RESET 9 +#define GPIO_EXP_PRESENT 10 +#define GPIO_LED1_NGREEN 12 +#define GPIO_LED1_RED 13 +#define GPIO_LED0_NGREEN 14 +#define GPIO_LED0_NRED 15 +#define GPIO_SPI_CS0 16 +#define GPIO_SPI_CS1 17 +#define GPIO_SPI_CS3 19 +#define GPIO_SPI_CS4 20 +#define GPIO_SD_WP 21 +#define GPIO_BP_RESET 22 +#define GPIO_ALARM_OUT 23 + +#endif /* __ASM_XTENSA_S6105_GPIO_H */ diff --git a/arch/xtensa/platforms/s6105/include/platform/hardware.h b/arch/xtensa/platforms/s6105/include/platform/hardware.h new file mode 100644 index 00000000..d628efac --- /dev/null +++ b/arch/xtensa/platforms/s6105/include/platform/hardware.h @@ -0,0 +1,11 @@ +#ifndef __XTENSA_S6105_HARDWARE_H +#define __XTENSA_S6105_HARDWARE_H + +#define PLATFORM_DEFAULT_MEM_START 0x40000000 +#define PLATFORM_DEFAULT_MEM_SIZE 0x08000000 + +#define MAX_DMA_ADDRESS 0 + +#define KERNELOFFSET (PLATFORM_DEFAULT_MEM_START + 0x1000) + +#endif /* __XTENSA_S6105_HARDWARE_H */ diff --git a/arch/xtensa/platforms/s6105/include/platform/serial.h b/arch/xtensa/platforms/s6105/include/platform/serial.h new file mode 100644 index 00000000..c8a771e5 --- /dev/null +++ b/arch/xtensa/platforms/s6105/include/platform/serial.h @@ -0,0 +1,8 @@ +#ifndef __ASM_XTENSA_S6105_SERIAL_H +#define __ASM_XTENSA_S6105_SERIAL_H + +#include <variant/hardware.h> + +#define BASE_BAUD (S6_SCLK / 16) + +#endif /* __ASM_XTENSA_S6105_SERIAL_H */ diff --git a/arch/xtensa/platforms/s6105/setup.c b/arch/xtensa/platforms/s6105/setup.c new file mode 100644 index 00000000..86ce730f --- /dev/null +++ b/arch/xtensa/platforms/s6105/setup.c @@ -0,0 +1,73 @@ +/* + * s6105 control routines + * + * Copyright (c) 2009 emlix GmbH + */ +#include <linux/irq.h> +#include <linux/io.h> +#include <linux/gpio.h> + +#include <asm/bootparam.h> + +#include <variant/hardware.h> +#include <variant/gpio.h> + +#include <platform/gpio.h> + +void platform_halt(void) +{ + local_irq_disable(); + while (1) + ; +} + +void platform_power_off(void) +{ + platform_halt(); +} + +void platform_restart(void) +{ + platform_halt(); +} + +void __init platform_setup(char **cmdline) +{ + unsigned long reg; + + reg = readl(S6_REG_GREG1 + S6_GREG1_PLLSEL); + reg &= ~(S6_GREG1_PLLSEL_GMAC_MASK << S6_GREG1_PLLSEL_GMAC | + S6_GREG1_PLLSEL_GMII_MASK << S6_GREG1_PLLSEL_GMII); + reg |= S6_GREG1_PLLSEL_GMAC_125MHZ << S6_GREG1_PLLSEL_GMAC | + S6_GREG1_PLLSEL_GMII_125MHZ << S6_GREG1_PLLSEL_GMII; + writel(reg, S6_REG_GREG1 + S6_GREG1_PLLSEL); + + reg = readl(S6_REG_GREG1 + S6_GREG1_CLKGATE); + reg &= ~(1 << S6_GREG1_BLOCK_SB); + reg &= ~(1 << S6_GREG1_BLOCK_GMAC); + writel(reg, S6_REG_GREG1 + S6_GREG1_CLKGATE); + + reg = readl(S6_REG_GREG1 + S6_GREG1_BLOCKENA); + reg |= 1 << S6_GREG1_BLOCK_SB; + reg |= 1 << S6_GREG1_BLOCK_GMAC; + writel(reg, S6_REG_GREG1 + S6_GREG1_BLOCKENA); + + printk(KERN_NOTICE "S6105 on Stretch S6000 - " + "Copyright (C) 2009 emlix GmbH <info@emlix.com>\n"); +} + +void __init platform_init(bp_tag_t *first) +{ + s6_gpio_init(0); + gpio_request(GPIO_LED1_NGREEN, "led1_green"); + gpio_request(GPIO_LED1_RED, "led1_red"); + gpio_direction_output(GPIO_LED1_NGREEN, 1); +} + +void platform_heartbeat(void) +{ + static unsigned int c; + + if (!(++c & 0x4F)) + gpio_direction_output(GPIO_LED1_RED, !(c & 0x10)); +} diff --git a/arch/xtensa/platforms/xt2000/Makefile b/arch/xtensa/platforms/xt2000/Makefile new file mode 100644 index 00000000..54d018e4 --- /dev/null +++ b/arch/xtensa/platforms/xt2000/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the Tensilica XT2000 Emulation Board +# + +obj-y = setup.o diff --git a/arch/xtensa/platforms/xt2000/include/platform/hardware.h b/arch/xtensa/platforms/xt2000/include/platform/hardware.h new file mode 100644 index 00000000..886ef156 --- /dev/null +++ b/arch/xtensa/platforms/xt2000/include/platform/hardware.h @@ -0,0 +1,54 @@ +/* + * platform/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. + * + * Copyright (C) 2001 Tensilica Inc. + */ + +/* + * This file contains the hardware configuration of the XT2000 board. + */ + +#ifndef _XTENSA_XT2000_HARDWARE_H +#define _XTENSA_XT2000_HARDWARE_H + +#include <variant/core.h> + +/* + * Memory configuration. + */ + +#define PLATFORM_DEFAULT_MEM_START 0x00000000 +#define PLATFORM_DEFAULT_MEM_SIZE 0x08000000 + +/* + * Number of platform IRQs + */ +#define PLATFORM_NR_IRQS 3 +/* + * On-board components. + */ + +#define SONIC83934_INTNUM XCHAL_EXTINT3_NUM +#define SONIC83934_ADDR IOADDR(0x0d030000) + +/* + * V3-PCI + */ + +/* The XT2000 uses the V3 as a cascaded interrupt controller for the PCI bus */ + +#define IRQ_PCI_A (XCHAL_NUM_INTERRUPTS + 0) +#define IRQ_PCI_B (XCHAL_NUM_INTERRUPTS + 1) +#define IRQ_PCI_C (XCHAL_NUM_INTERRUPTS + 2) + +/* + * Various other components. + */ + +#define XT2000_LED_ADDR IOADDR(0x0d040000) + +#endif /* _XTENSA_XT2000_HARDWARE_H */ diff --git a/arch/xtensa/platforms/xt2000/include/platform/serial.h b/arch/xtensa/platforms/xt2000/include/platform/serial.h new file mode 100644 index 00000000..7226cf73 --- /dev/null +++ b/arch/xtensa/platforms/xt2000/include/platform/serial.h @@ -0,0 +1,28 @@ +/* + * platform/serial.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001 Tensilica Inc. + */ + +#ifndef _XTENSA_XT2000_SERIAL_H +#define _XTENSA_XT2000_SERIAL_H + +#include <variant/core.h> +#include <asm/io.h> + +/* National-Semi PC16552D DUART: */ + +#define DUART16552_1_INTNUM XCHAL_EXTINT4_NUM +#define DUART16552_2_INTNUM XCHAL_EXTINT5_NUM + +#define DUART16552_1_ADDR IOADDR(0x0d050020) /* channel 1 */ +#define DUART16552_2_ADDR IOADDR(0x0d050000) /* channel 2 */ + +#define DUART16552_XTAL_FREQ 18432000 /* crystal frequency in Hz */ +#define BASE_BAUD ( DUART16552_XTAL_FREQ / 16 ) + +#endif /* _XTENSA_XT2000_SERIAL_H */ diff --git a/arch/xtensa/platforms/xt2000/setup.c b/arch/xtensa/platforms/xt2000/setup.c new file mode 100644 index 00000000..9e83940a --- /dev/null +++ b/arch/xtensa/platforms/xt2000/setup.c @@ -0,0 +1,181 @@ +/* + * arch/xtensa/platforms/xt2000/setup.c + * + * Platform specific functions for the XT2000 board. + * + * Authors: Chris Zankel <chris@zankel.net> + * Joe Taylor <joe@tensilica.com> + * + * Copyright 2001 - 2004 Tensilica Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/reboot.h> +#include <linux/kdev_t.h> +#include <linux/types.h> +#include <linux/major.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/stringify.h> +#include <linux/platform_device.h> +#include <linux/serial.h> +#include <linux/serial_8250.h> + +#include <asm/processor.h> +#include <asm/platform.h> +#include <asm/bootparam.h> +#include <platform/hardware.h> +#include <platform/serial.h> + +/* Assumes s points to an 8-chr string. No checking for NULL. */ + +static void led_print (int f, char *s) +{ + unsigned long* led_addr = (unsigned long*) (XT2000_LED_ADDR + 0xE0) + f; + int i; + for (i = f; i < 8; i++) + if ((*led_addr++ = *s++) == 0) + break; +} + +void platform_halt(void) +{ + led_print (0, " HALT "); + local_irq_disable(); + while (1); +} + +void platform_power_off(void) +{ + led_print (0, "POWEROFF"); + local_irq_disable(); + while (1); +} + +void platform_restart(void) +{ + /* Flush and reset the mmu, simulate a processor reset, and + * jump to the reset vector. */ + + __asm__ __volatile__ ("movi a2, 15\n\t" + "wsr a2, " __stringify(ICOUNTLEVEL) "\n\t" + "movi a2, 0\n\t" + "wsr a2, " __stringify(ICOUNT) "\n\t" + "wsr a2, " __stringify(IBREAKENABLE) "\n\t" + "wsr a2, " __stringify(LCOUNT) "\n\t" + "movi a2, 0x1f\n\t" + "wsr a2, " __stringify(PS) "\n\t" + "isync\n\t" + "jx %0\n\t" + : + : "a" (XCHAL_RESET_VECTOR_VADDR) + : "a2" + ); + + /* control never gets here */ +} + +void __init platform_setup(char** cmdline) +{ + led_print (0, "LINUX "); +} + +/* early initialization */ + +extern sysmem_info_t __initdata sysmem; + +void platform_init(bp_tag_t* first) +{ + /* Set default memory block if not provided by the bootloader. */ + + if (sysmem.nr_banks == 0) { + sysmem.nr_banks = 1; + sysmem.bank[0].start = PLATFORM_DEFAULT_MEM_START; + sysmem.bank[0].end = PLATFORM_DEFAULT_MEM_START + + PLATFORM_DEFAULT_MEM_SIZE; + } +} + +/* Heartbeat. Let the LED blink. */ + +void platform_heartbeat(void) +{ + static int i=0, t = 0; + + if (--t < 0) + { + t = 59; + led_print(7, i ? ".": " "); + i ^= 1; + } +} + +//#define RS_TABLE_SIZE 2 +//#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST) + +#define _SERIAL_PORT(_base,_irq) \ +{ \ + .mapbase = (_base), \ + .membase = (void*)(_base), \ + .irq = (_irq), \ + .uartclk = DUART16552_XTAL_FREQ, \ + .iotype = UPIO_MEM, \ + .flags = UPF_BOOT_AUTOCONF, \ + .regshift = 2, \ +} + +static struct plat_serial8250_port xt2000_serial_data[] = { +#if XCHAL_HAVE_BE + _SERIAL_PORT(DUART16552_1_ADDR + 3, DUART16552_1_INTNUM), + _SERIAL_PORT(DUART16552_2_ADDR + 3, DUART16552_2_INTNUM), +#else + _SERIAL_PORT(DUART16552_1_ADDR, DUART16552_1_INTNUM), + _SERIAL_PORT(DUART16552_2_ADDR, DUART16552_2_INTNUM), +#endif + { } +}; + +static struct platform_device xt2000_serial8250_device = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = xt2000_serial_data, + }, +}; + +static struct resource xt2000_sonic_res[] = { + { + .start = SONIC83934_ADDR, + .end = SONIC83934_ADDR + 0xff, + .flags = IORESOURCE_MEM, + }, + { + .start = SONIC83934_INTNUM, + .end = SONIC83934_INTNUM, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device xt2000_sonic_device = { + .name = "xtsonic", + .num_resources = ARRAY_SIZE(xt2000_sonic_res), + .resource = xt2000_sonic_res, +}; + +static int __init xt2000_setup_devinit(void) +{ + platform_device_register(&xt2000_serial8250_device); + platform_device_register(&xt2000_sonic_device); + + return 0; +} + +device_initcall(xt2000_setup_devinit); diff --git a/arch/xtensa/variants/dc232b/include/variant/core.h b/arch/xtensa/variants/dc232b/include/variant/core.h new file mode 100644 index 00000000..525bd3d9 --- /dev/null +++ b/arch/xtensa/variants/dc232b/include/variant/core.h @@ -0,0 +1,424 @@ +/* + * Xtensa processor core configuration information. + * + * 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) 1999-2007 Tensilica Inc. + */ + +#ifndef _XTENSA_CORE_CONFIGURATION_H +#define _XTENSA_CORE_CONFIGURATION_H + + +/**************************************************************************** + Parameters Useful for Any Code, USER or PRIVILEGED + ****************************************************************************/ + +/* + * Note: Macros of the form XCHAL_HAVE_*** have a value of 1 if the option is + * configured, and a value of 0 otherwise. These macros are always defined. + */ + + +/*---------------------------------------------------------------------- + ISA + ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_BE 0 /* big-endian byte ordering */ +#define XCHAL_HAVE_WINDOWED 1 /* windowed registers option */ +#define XCHAL_NUM_AREGS 32 /* num of physical addr regs */ +#define XCHAL_NUM_AREGS_LOG2 5 /* log2(XCHAL_NUM_AREGS) */ +#define XCHAL_MAX_INSTRUCTION_SIZE 3 /* max instr bytes (3..8) */ +#define XCHAL_HAVE_DEBUG 1 /* debug option */ +#define XCHAL_HAVE_DENSITY 1 /* 16-bit instructions */ +#define XCHAL_HAVE_LOOPS 1 /* zero-overhead loops */ +#define XCHAL_HAVE_NSA 1 /* NSA/NSAU instructions */ +#define XCHAL_HAVE_MINMAX 1 /* MIN/MAX instructions */ +#define XCHAL_HAVE_SEXT 1 /* SEXT instruction */ +#define XCHAL_HAVE_CLAMPS 1 /* CLAMPS instruction */ +#define XCHAL_HAVE_MUL16 1 /* MUL16S/MUL16U instructions */ +#define XCHAL_HAVE_MUL32 1 /* MULL instruction */ +#define XCHAL_HAVE_MUL32_HIGH 0 /* MULUH/MULSH instructions */ +#define XCHAL_HAVE_DIV32 1 /* QUOS/QUOU/REMS/REMU instructions */ +#define XCHAL_HAVE_L32R 1 /* L32R instruction */ +#define XCHAL_HAVE_ABSOLUTE_LITERALS 1 /* non-PC-rel (extended) L32R */ +#define XCHAL_HAVE_CONST16 0 /* CONST16 instruction */ +#define XCHAL_HAVE_ADDX 1 /* ADDX#/SUBX# instructions */ +#define XCHAL_HAVE_WIDE_BRANCHES 0 /* B*.W18 or B*.W15 instr's */ +#define XCHAL_HAVE_PREDICTED_BRANCHES 0 /* B[EQ/EQZ/NE/NEZ]T instr's */ +#define XCHAL_HAVE_CALL4AND12 1 /* (obsolete option) */ +#define XCHAL_HAVE_ABS 1 /* ABS instruction */ +/*#define XCHAL_HAVE_POPC 0*/ /* POPC instruction */ +/*#define XCHAL_HAVE_CRC 0*/ /* CRC instruction */ +#define XCHAL_HAVE_RELEASE_SYNC 1 /* L32AI/S32RI instructions */ +#define XCHAL_HAVE_S32C1I 1 /* S32C1I instruction */ +#define XCHAL_HAVE_SPECULATION 0 /* speculation */ +#define XCHAL_HAVE_FULL_RESET 1 /* all regs/state reset */ +#define XCHAL_NUM_CONTEXTS 1 /* */ +#define XCHAL_NUM_MISC_REGS 2 /* num of scratch regs (0..4) */ +#define XCHAL_HAVE_TAP_MASTER 0 /* JTAG TAP control instr's */ +#define XCHAL_HAVE_PRID 1 /* processor ID register */ +#define XCHAL_HAVE_THREADPTR 1 /* THREADPTR register */ +#define XCHAL_HAVE_BOOLEANS 0 /* boolean registers */ +#define XCHAL_HAVE_CP 1 /* CPENABLE reg (coprocessor) */ +#define XCHAL_CP_MAXCFG 8 /* max allowed cp id plus one */ +#define XCHAL_HAVE_MAC16 1 /* MAC16 package */ +#define XCHAL_HAVE_VECTORFPU2005 0 /* vector floating-point pkg */ +#define XCHAL_HAVE_FP 0 /* floating point pkg */ +#define XCHAL_HAVE_VECTRA1 0 /* Vectra I pkg */ +#define XCHAL_HAVE_VECTRALX 0 /* Vectra LX pkg */ +#define XCHAL_HAVE_HIFI2 0 /* HiFi2 Audio Engine pkg */ + + +/*---------------------------------------------------------------------- + MISC + ----------------------------------------------------------------------*/ + +#define XCHAL_NUM_WRITEBUFFER_ENTRIES 8 /* size of write buffer */ +#define XCHAL_INST_FETCH_WIDTH 4 /* instr-fetch width in bytes */ +#define XCHAL_DATA_WIDTH 4 /* data width in bytes */ +/* In T1050, applies to selected core load and store instructions (see ISA): */ +#define XCHAL_UNALIGNED_LOAD_EXCEPTION 1 /* unaligned loads cause exc. */ +#define XCHAL_UNALIGNED_STORE_EXCEPTION 1 /* unaligned stores cause exc.*/ + +#define XCHAL_SW_VERSION 701001 /* sw version of this header */ + +#define XCHAL_CORE_ID "dc232b" /* alphanum core name + (CoreID) set in the Xtensa + Processor Generator */ + +#define XCHAL_CORE_DESCRIPTION "Diamond 232L Standard Core Rev.B (LE)" +#define XCHAL_BUILD_UNIQUE_ID 0x0000BEEF /* 22-bit sw build ID */ + +/* + * These definitions describe the hardware targeted by this software. + */ +#define XCHAL_HW_CONFIGID0 0xC56307FE /* ConfigID hi 32 bits*/ +#define XCHAL_HW_CONFIGID1 0x0D40BEEF /* ConfigID lo 32 bits*/ +#define XCHAL_HW_VERSION_NAME "LX2.1.1" /* full version name */ +#define XCHAL_HW_VERSION_MAJOR 2210 /* major ver# of targeted hw */ +#define XCHAL_HW_VERSION_MINOR 1 /* minor ver# of targeted hw */ +#define XCHAL_HW_VERSION 221001 /* major*100+minor */ +#define XCHAL_HW_REL_LX2 1 +#define XCHAL_HW_REL_LX2_1 1 +#define XCHAL_HW_REL_LX2_1_1 1 +#define XCHAL_HW_CONFIGID_RELIABLE 1 +/* If software targets a *range* of hardware versions, these are the bounds: */ +#define XCHAL_HW_MIN_VERSION_MAJOR 2210 /* major v of earliest tgt hw */ +#define XCHAL_HW_MIN_VERSION_MINOR 1 /* minor v of earliest tgt hw */ +#define XCHAL_HW_MIN_VERSION 221001 /* earliest targeted hw */ +#define XCHAL_HW_MAX_VERSION_MAJOR 2210 /* major v of latest tgt hw */ +#define XCHAL_HW_MAX_VERSION_MINOR 1 /* minor v of latest tgt hw */ +#define XCHAL_HW_MAX_VERSION 221001 /* latest targeted hw */ + + +/*---------------------------------------------------------------------- + CACHE + ----------------------------------------------------------------------*/ + +#define XCHAL_ICACHE_LINESIZE 32 /* I-cache line size in bytes */ +#define XCHAL_DCACHE_LINESIZE 32 /* D-cache line size in bytes */ +#define XCHAL_ICACHE_LINEWIDTH 5 /* log2(I line size in bytes) */ +#define XCHAL_DCACHE_LINEWIDTH 5 /* log2(D line size in bytes) */ + +#define XCHAL_ICACHE_SIZE 16384 /* I-cache size in bytes or 0 */ +#define XCHAL_DCACHE_SIZE 16384 /* D-cache size in bytes or 0 */ + +#define XCHAL_DCACHE_IS_WRITEBACK 1 /* writeback feature */ + + + + +/**************************************************************************** + Parameters Useful for PRIVILEGED (Supervisory or Non-Virtualized) Code + ****************************************************************************/ + + +#ifndef XTENSA_HAL_NON_PRIVILEGED_ONLY + +/*---------------------------------------------------------------------- + CACHE + ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_PIF 1 /* any outbound PIF present */ + +/* If present, cache size in bytes == (ways * 2^(linewidth + setwidth)). */ + +/* Number of cache sets in log2(lines per way): */ +#define XCHAL_ICACHE_SETWIDTH 7 +#define XCHAL_DCACHE_SETWIDTH 7 + +/* Cache set associativity (number of ways): */ +#define XCHAL_ICACHE_WAYS 4 +#define XCHAL_DCACHE_WAYS 4 + +/* Cache features: */ +#define XCHAL_ICACHE_LINE_LOCKABLE 1 +#define XCHAL_DCACHE_LINE_LOCKABLE 1 +#define XCHAL_ICACHE_ECC_PARITY 0 +#define XCHAL_DCACHE_ECC_PARITY 0 + +/* Number of encoded cache attr bits (see <xtensa/hal.h> for decoded bits): */ +#define XCHAL_CA_BITS 4 + + +/*---------------------------------------------------------------------- + INTERNAL I/D RAM/ROMs and XLMI + ----------------------------------------------------------------------*/ + +#define XCHAL_NUM_INSTROM 0 /* number of core instr. ROMs */ +#define XCHAL_NUM_INSTRAM 0 /* number of core instr. RAMs */ +#define XCHAL_NUM_DATAROM 0 /* number of core data ROMs */ +#define XCHAL_NUM_DATARAM 0 /* number of core data RAMs */ +#define XCHAL_NUM_URAM 0 /* number of core unified RAMs*/ +#define XCHAL_NUM_XLMI 0 /* number of core XLMI ports */ + + +/*---------------------------------------------------------------------- + INTERRUPTS and TIMERS + ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_INTERRUPTS 1 /* interrupt option */ +#define XCHAL_HAVE_HIGHPRI_INTERRUPTS 1 /* med/high-pri. interrupts */ +#define XCHAL_HAVE_NMI 1 /* non-maskable interrupt */ +#define XCHAL_HAVE_CCOUNT 1 /* CCOUNT reg. (timer option) */ +#define XCHAL_NUM_TIMERS 3 /* number of CCOMPAREn regs */ +#define XCHAL_NUM_INTERRUPTS 22 /* number of interrupts */ +#define XCHAL_NUM_INTERRUPTS_LOG2 5 /* ceil(log2(NUM_INTERRUPTS)) */ +#define XCHAL_NUM_EXTINTERRUPTS 17 /* num of external interrupts */ +#define XCHAL_NUM_INTLEVELS 6 /* number of interrupt levels + (not including level zero) */ +#define XCHAL_EXCM_LEVEL 3 /* level masked by PS.EXCM */ + /* (always 1 in XEA1; levels 2 .. EXCM_LEVEL are "medium priority") */ + +/* Masks of interrupts at each interrupt level: */ +#define XCHAL_INTLEVEL1_MASK 0x001F80FF +#define XCHAL_INTLEVEL2_MASK 0x00000100 +#define XCHAL_INTLEVEL3_MASK 0x00200E00 +#define XCHAL_INTLEVEL4_MASK 0x00001000 +#define XCHAL_INTLEVEL5_MASK 0x00002000 +#define XCHAL_INTLEVEL6_MASK 0x00000000 +#define XCHAL_INTLEVEL7_MASK 0x00004000 + +/* Masks of interrupts at each range 1..n of interrupt levels: */ +#define XCHAL_INTLEVEL1_ANDBELOW_MASK 0x001F80FF +#define XCHAL_INTLEVEL2_ANDBELOW_MASK 0x001F81FF +#define XCHAL_INTLEVEL3_ANDBELOW_MASK 0x003F8FFF +#define XCHAL_INTLEVEL4_ANDBELOW_MASK 0x003F9FFF +#define XCHAL_INTLEVEL5_ANDBELOW_MASK 0x003FBFFF +#define XCHAL_INTLEVEL6_ANDBELOW_MASK 0x003FBFFF +#define XCHAL_INTLEVEL7_ANDBELOW_MASK 0x003FFFFF + +/* Level of each interrupt: */ +#define XCHAL_INT0_LEVEL 1 +#define XCHAL_INT1_LEVEL 1 +#define XCHAL_INT2_LEVEL 1 +#define XCHAL_INT3_LEVEL 1 +#define XCHAL_INT4_LEVEL 1 +#define XCHAL_INT5_LEVEL 1 +#define XCHAL_INT6_LEVEL 1 +#define XCHAL_INT7_LEVEL 1 +#define XCHAL_INT8_LEVEL 2 +#define XCHAL_INT9_LEVEL 3 +#define XCHAL_INT10_LEVEL 3 +#define XCHAL_INT11_LEVEL 3 +#define XCHAL_INT12_LEVEL 4 +#define XCHAL_INT13_LEVEL 5 +#define XCHAL_INT14_LEVEL 7 +#define XCHAL_INT15_LEVEL 1 +#define XCHAL_INT16_LEVEL 1 +#define XCHAL_INT17_LEVEL 1 +#define XCHAL_INT18_LEVEL 1 +#define XCHAL_INT19_LEVEL 1 +#define XCHAL_INT20_LEVEL 1 +#define XCHAL_INT21_LEVEL 3 +#define XCHAL_DEBUGLEVEL 6 /* debug interrupt level */ +#define XCHAL_HAVE_DEBUG_EXTERN_INT 1 /* OCD external db interrupt */ +#define XCHAL_NMILEVEL 7 /* NMI "level" (for use with + EXCSAVE/EPS/EPC_n, RFI n) */ + +/* Type of each interrupt: */ +#define XCHAL_INT0_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT1_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT2_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT3_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT4_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT5_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT6_TYPE XTHAL_INTTYPE_TIMER +#define XCHAL_INT7_TYPE XTHAL_INTTYPE_SOFTWARE +#define XCHAL_INT8_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT9_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT10_TYPE XTHAL_INTTYPE_TIMER +#define XCHAL_INT11_TYPE XTHAL_INTTYPE_SOFTWARE +#define XCHAL_INT12_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT13_TYPE XTHAL_INTTYPE_TIMER +#define XCHAL_INT14_TYPE XTHAL_INTTYPE_NMI +#define XCHAL_INT15_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT16_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT17_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT18_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT19_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT20_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT21_TYPE XTHAL_INTTYPE_EXTERN_EDGE + +/* Masks of interrupts for each type of interrupt: */ +#define XCHAL_INTTYPE_MASK_UNCONFIGURED 0xFFC00000 +#define XCHAL_INTTYPE_MASK_SOFTWARE 0x00000880 +#define XCHAL_INTTYPE_MASK_EXTERN_EDGE 0x003F8000 +#define XCHAL_INTTYPE_MASK_EXTERN_LEVEL 0x0000133F +#define XCHAL_INTTYPE_MASK_TIMER 0x00002440 +#define XCHAL_INTTYPE_MASK_NMI 0x00004000 +#define XCHAL_INTTYPE_MASK_WRITE_ERROR 0x00000000 + +/* Interrupt numbers assigned to specific interrupt sources: */ +#define XCHAL_TIMER0_INTERRUPT 6 /* CCOMPARE0 */ +#define XCHAL_TIMER1_INTERRUPT 10 /* CCOMPARE1 */ +#define XCHAL_TIMER2_INTERRUPT 13 /* CCOMPARE2 */ +#define XCHAL_TIMER3_INTERRUPT XTHAL_TIMER_UNCONFIGURED +#define XCHAL_NMI_INTERRUPT 14 /* non-maskable interrupt */ + +/* Interrupt numbers for levels at which only one interrupt is configured: */ +#define XCHAL_INTLEVEL2_NUM 8 +#define XCHAL_INTLEVEL4_NUM 12 +#define XCHAL_INTLEVEL5_NUM 13 +#define XCHAL_INTLEVEL7_NUM 14 +/* (There are many interrupts each at level(s) 1, 3.) */ + + +/* + * External interrupt vectors/levels. + * These macros describe how Xtensa processor interrupt numbers + * (as numbered internally, eg. in INTERRUPT and INTENABLE registers) + * map to external BInterrupt<n> pins, for those interrupts + * configured as external (level-triggered, edge-triggered, or NMI). + * See the Xtensa processor databook for more details. + */ + +/* Core interrupt numbers mapped to each EXTERNAL interrupt number: */ +#define XCHAL_EXTINT0_NUM 0 /* (intlevel 1) */ +#define XCHAL_EXTINT1_NUM 1 /* (intlevel 1) */ +#define XCHAL_EXTINT2_NUM 2 /* (intlevel 1) */ +#define XCHAL_EXTINT3_NUM 3 /* (intlevel 1) */ +#define XCHAL_EXTINT4_NUM 4 /* (intlevel 1) */ +#define XCHAL_EXTINT5_NUM 5 /* (intlevel 1) */ +#define XCHAL_EXTINT6_NUM 8 /* (intlevel 2) */ +#define XCHAL_EXTINT7_NUM 9 /* (intlevel 3) */ +#define XCHAL_EXTINT8_NUM 12 /* (intlevel 4) */ +#define XCHAL_EXTINT9_NUM 14 /* (intlevel 7) */ +#define XCHAL_EXTINT10_NUM 15 /* (intlevel 1) */ +#define XCHAL_EXTINT11_NUM 16 /* (intlevel 1) */ +#define XCHAL_EXTINT12_NUM 17 /* (intlevel 1) */ +#define XCHAL_EXTINT13_NUM 18 /* (intlevel 1) */ +#define XCHAL_EXTINT14_NUM 19 /* (intlevel 1) */ +#define XCHAL_EXTINT15_NUM 20 /* (intlevel 1) */ +#define XCHAL_EXTINT16_NUM 21 /* (intlevel 3) */ + + +/*---------------------------------------------------------------------- + EXCEPTIONS and VECTORS + ----------------------------------------------------------------------*/ + +#define XCHAL_XEA_VERSION 2 /* Xtensa Exception Architecture + number: 1 == XEA1 (old) + 2 == XEA2 (new) + 0 == XEAX (extern) */ +#define XCHAL_HAVE_XEA1 0 /* Exception Architecture 1 */ +#define XCHAL_HAVE_XEA2 1 /* Exception Architecture 2 */ +#define XCHAL_HAVE_XEAX 0 /* External Exception Arch. */ +#define XCHAL_HAVE_EXCEPTIONS 1 /* exception option */ +#define XCHAL_HAVE_MEM_ECC_PARITY 0 /* local memory ECC/parity */ +#define XCHAL_HAVE_VECTOR_SELECT 1 /* relocatable vectors */ +#define XCHAL_HAVE_VECBASE 1 /* relocatable vectors */ +#define XCHAL_VECBASE_RESET_VADDR 0xD0000000 /* VECBASE reset value */ +#define XCHAL_VECBASE_RESET_PADDR 0x00000000 +#define XCHAL_RESET_VECBASE_OVERLAP 0 + +#define XCHAL_RESET_VECTOR0_VADDR 0xFE000000 +#define XCHAL_RESET_VECTOR0_PADDR 0xFE000000 +#define XCHAL_RESET_VECTOR1_VADDR 0xD8000500 +#define XCHAL_RESET_VECTOR1_PADDR 0x00000500 +#define XCHAL_RESET_VECTOR_VADDR 0xFE000000 +#define XCHAL_RESET_VECTOR_PADDR 0xFE000000 +#define XCHAL_USER_VECOFS 0x00000340 +#define XCHAL_USER_VECTOR_VADDR 0xD0000340 +#define XCHAL_USER_VECTOR_PADDR 0x00000340 +#define XCHAL_KERNEL_VECOFS 0x00000300 +#define XCHAL_KERNEL_VECTOR_VADDR 0xD0000300 +#define XCHAL_KERNEL_VECTOR_PADDR 0x00000300 +#define XCHAL_DOUBLEEXC_VECOFS 0x000003C0 +#define XCHAL_DOUBLEEXC_VECTOR_VADDR 0xD00003C0 +#define XCHAL_DOUBLEEXC_VECTOR_PADDR 0x000003C0 +#define XCHAL_WINDOW_OF4_VECOFS 0x00000000 +#define XCHAL_WINDOW_UF4_VECOFS 0x00000040 +#define XCHAL_WINDOW_OF8_VECOFS 0x00000080 +#define XCHAL_WINDOW_UF8_VECOFS 0x000000C0 +#define XCHAL_WINDOW_OF12_VECOFS 0x00000100 +#define XCHAL_WINDOW_UF12_VECOFS 0x00000140 +#define XCHAL_WINDOW_VECTORS_VADDR 0xD0000000 +#define XCHAL_WINDOW_VECTORS_PADDR 0x00000000 +#define XCHAL_INTLEVEL2_VECOFS 0x00000180 +#define XCHAL_INTLEVEL2_VECTOR_VADDR 0xD0000180 +#define XCHAL_INTLEVEL2_VECTOR_PADDR 0x00000180 +#define XCHAL_INTLEVEL3_VECOFS 0x000001C0 +#define XCHAL_INTLEVEL3_VECTOR_VADDR 0xD00001C0 +#define XCHAL_INTLEVEL3_VECTOR_PADDR 0x000001C0 +#define XCHAL_INTLEVEL4_VECOFS 0x00000200 +#define XCHAL_INTLEVEL4_VECTOR_VADDR 0xD0000200 +#define XCHAL_INTLEVEL4_VECTOR_PADDR 0x00000200 +#define XCHAL_INTLEVEL5_VECOFS 0x00000240 +#define XCHAL_INTLEVEL5_VECTOR_VADDR 0xD0000240 +#define XCHAL_INTLEVEL5_VECTOR_PADDR 0x00000240 +#define XCHAL_INTLEVEL6_VECOFS 0x00000280 +#define XCHAL_INTLEVEL6_VECTOR_VADDR 0xD0000280 +#define XCHAL_INTLEVEL6_VECTOR_PADDR 0x00000280 +#define XCHAL_DEBUG_VECOFS XCHAL_INTLEVEL6_VECOFS +#define XCHAL_DEBUG_VECTOR_VADDR XCHAL_INTLEVEL6_VECTOR_VADDR +#define XCHAL_DEBUG_VECTOR_PADDR XCHAL_INTLEVEL6_VECTOR_PADDR +#define XCHAL_NMI_VECOFS 0x000002C0 +#define XCHAL_NMI_VECTOR_VADDR 0xD00002C0 +#define XCHAL_NMI_VECTOR_PADDR 0x000002C0 +#define XCHAL_INTLEVEL7_VECOFS XCHAL_NMI_VECOFS +#define XCHAL_INTLEVEL7_VECTOR_VADDR XCHAL_NMI_VECTOR_VADDR +#define XCHAL_INTLEVEL7_VECTOR_PADDR XCHAL_NMI_VECTOR_PADDR + + +/*---------------------------------------------------------------------- + DEBUG + ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_OCD 1 /* OnChipDebug option */ +#define XCHAL_NUM_IBREAK 2 /* number of IBREAKn regs */ +#define XCHAL_NUM_DBREAK 2 /* number of DBREAKn regs */ +#define XCHAL_HAVE_OCD_DIR_ARRAY 1 /* faster OCD option */ + + +/*---------------------------------------------------------------------- + MMU + ----------------------------------------------------------------------*/ + +/* See core-matmap.h header file for more details. */ + +#define XCHAL_HAVE_TLBS 1 /* inverse of HAVE_CACHEATTR */ +#define XCHAL_HAVE_SPANNING_WAY 0 /* one way maps I+D 4GB vaddr */ +#define XCHAL_HAVE_IDENTITY_MAP 0 /* vaddr == paddr always */ +#define XCHAL_HAVE_CACHEATTR 0 /* CACHEATTR register present */ +#define XCHAL_HAVE_MIMIC_CACHEATTR 0 /* region protection */ +#define XCHAL_HAVE_XLT_CACHEATTR 0 /* region prot. w/translation */ +#define XCHAL_HAVE_PTP_MMU 1 /* full MMU (with page table + [autorefill] and protection) + usable for an MMU-based OS */ +/* If none of the above last 4 are set, it's a custom TLB configuration. */ +#define XCHAL_ITLB_ARF_ENTRIES_LOG2 2 /* log2(autorefill way size) */ +#define XCHAL_DTLB_ARF_ENTRIES_LOG2 2 /* log2(autorefill way size) */ + +#define XCHAL_MMU_ASID_BITS 8 /* number of bits in ASIDs */ +#define XCHAL_MMU_RINGS 4 /* number of rings (1..4) */ +#define XCHAL_MMU_RING_BITS 2 /* num of bits in RING field */ + +#endif /* !XTENSA_HAL_NON_PRIVILEGED_ONLY */ + + +#endif /* _XTENSA_CORE_CONFIGURATION_H */ + diff --git a/arch/xtensa/variants/dc232b/include/variant/tie-asm.h b/arch/xtensa/variants/dc232b/include/variant/tie-asm.h new file mode 100644 index 00000000..ed4f53f5 --- /dev/null +++ b/arch/xtensa/variants/dc232b/include/variant/tie-asm.h @@ -0,0 +1,122 @@ +/* + * This header file contains assembly-language definitions (assembly + * macros, etc.) for this specific Xtensa processor's TIE extensions + * and options. It is customized to this Xtensa processor configuration. + * + * 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) 1999-2007 Tensilica Inc. + */ + +#ifndef _XTENSA_CORE_TIE_ASM_H +#define _XTENSA_CORE_TIE_ASM_H + +/* Selection parameter values for save-area save/restore macros: */ +/* Option vs. TIE: */ +#define XTHAL_SAS_TIE 0x0001 /* custom extension or coprocessor */ +#define XTHAL_SAS_OPT 0x0002 /* optional (and not a coprocessor) */ +/* Whether used automatically by compiler: */ +#define XTHAL_SAS_NOCC 0x0004 /* not used by compiler w/o special opts/code */ +#define XTHAL_SAS_CC 0x0008 /* used by compiler without special opts/code */ +/* ABI handling across function calls: */ +#define XTHAL_SAS_CALR 0x0010 /* caller-saved */ +#define XTHAL_SAS_CALE 0x0020 /* callee-saved */ +#define XTHAL_SAS_GLOB 0x0040 /* global across function calls (in thread) */ +/* Misc */ +#define XTHAL_SAS_ALL 0xFFFF /* include all default NCP contents */ + + + +/* Macro to save all non-coprocessor (extra) custom TIE and optional state + * (not including zero-overhead loop registers). + * Save area ptr (clobbered): ptr (1 byte aligned) + * Scratch regs (clobbered): at1..at4 (only first XCHAL_NCP_NUM_ATMPS needed) + */ + .macro xchal_ncp_store ptr at1 at2 at3 at4 continue=0 ofs=-1 select=XTHAL_SAS_ALL + xchal_sa_start \continue, \ofs + .ifeq (XTHAL_SAS_OPT | XTHAL_SAS_CC | XTHAL_SAS_CALR) & ~\select + xchal_sa_align \ptr, 0, 1024-8, 4, 4 + rsr \at1, ACCLO // MAC16 accumulator + rsr \at2, ACCHI + s32i \at1, \ptr, .Lxchal_ofs_ + 0 + s32i \at2, \ptr, .Lxchal_ofs_ + 4 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 8 + .endif + .ifeq (XTHAL_SAS_OPT | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~\select + xchal_sa_align \ptr, 0, 1024-16, 4, 4 + rsr \at1, M0 // MAC16 registers + rsr \at2, M1 + s32i \at1, \ptr, .Lxchal_ofs_ + 0 + s32i \at2, \ptr, .Lxchal_ofs_ + 4 + rsr \at1, M2 + rsr \at2, M3 + s32i \at1, \ptr, .Lxchal_ofs_ + 8 + s32i \at2, \ptr, .Lxchal_ofs_ + 12 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 16 + .endif + .ifeq (XTHAL_SAS_OPT | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~\select + xchal_sa_align \ptr, 0, 1024-4, 4, 4 + rsr \at1, SCOMPARE1 // conditional store option + s32i \at1, \ptr, .Lxchal_ofs_ + 0 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 4 + .endif + .ifeq (XTHAL_SAS_OPT | XTHAL_SAS_CC | XTHAL_SAS_GLOB) & ~\select + xchal_sa_align \ptr, 0, 1024-4, 4, 4 + rur \at1, THREADPTR // threadptr option + s32i \at1, \ptr, .Lxchal_ofs_ + 0 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 4 + .endif + .endm // xchal_ncp_store + +/* Macro to save all non-coprocessor (extra) custom TIE and optional state + * (not including zero-overhead loop registers). + * Save area ptr (clobbered): ptr (1 byte aligned) + * Scratch regs (clobbered): at1..at4 (only first XCHAL_NCP_NUM_ATMPS needed) + */ + .macro xchal_ncp_load ptr at1 at2 at3 at4 continue=0 ofs=-1 select=XTHAL_SAS_ALL + xchal_sa_start \continue, \ofs + .ifeq (XTHAL_SAS_OPT | XTHAL_SAS_CC | XTHAL_SAS_CALR) & ~\select + xchal_sa_align \ptr, 0, 1024-8, 4, 4 + l32i \at1, \ptr, .Lxchal_ofs_ + 0 + l32i \at2, \ptr, .Lxchal_ofs_ + 4 + wsr \at1, ACCLO // MAC16 accumulator + wsr \at2, ACCHI + .set .Lxchal_ofs_, .Lxchal_ofs_ + 8 + .endif + .ifeq (XTHAL_SAS_OPT | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~\select + xchal_sa_align \ptr, 0, 1024-16, 4, 4 + l32i \at1, \ptr, .Lxchal_ofs_ + 0 + l32i \at2, \ptr, .Lxchal_ofs_ + 4 + wsr \at1, M0 // MAC16 registers + wsr \at2, M1 + l32i \at1, \ptr, .Lxchal_ofs_ + 8 + l32i \at2, \ptr, .Lxchal_ofs_ + 12 + wsr \at1, M2 + wsr \at2, M3 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 16 + .endif + .ifeq (XTHAL_SAS_OPT | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~\select + xchal_sa_align \ptr, 0, 1024-4, 4, 4 + l32i \at1, \ptr, .Lxchal_ofs_ + 0 + wsr \at1, SCOMPARE1 // conditional store option + .set .Lxchal_ofs_, .Lxchal_ofs_ + 4 + .endif + .ifeq (XTHAL_SAS_OPT | XTHAL_SAS_CC | XTHAL_SAS_GLOB) & ~\select + xchal_sa_align \ptr, 0, 1024-4, 4, 4 + l32i \at1, \ptr, .Lxchal_ofs_ + 0 + wur \at1, THREADPTR // threadptr option + .set .Lxchal_ofs_, .Lxchal_ofs_ + 4 + .endif + .endm // xchal_ncp_load + + + +#define XCHAL_NCP_NUM_ATMPS 2 + + +#define XCHAL_SA_NUM_ATMPS 2 + +#endif /*_XTENSA_CORE_TIE_ASM_H*/ + diff --git a/arch/xtensa/variants/dc232b/include/variant/tie.h b/arch/xtensa/variants/dc232b/include/variant/tie.h new file mode 100644 index 00000000..018e81af --- /dev/null +++ b/arch/xtensa/variants/dc232b/include/variant/tie.h @@ -0,0 +1,131 @@ +/* + * This header file describes this specific Xtensa processor's TIE extensions + * that extend basic Xtensa core functionality. It is customized to this + * Xtensa processor configuration. + * + * 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) 1999-2007 Tensilica Inc. + */ + +#ifndef _XTENSA_CORE_TIE_H +#define _XTENSA_CORE_TIE_H + +#define XCHAL_CP_NUM 1 /* number of coprocessors */ +#define XCHAL_CP_MAX 8 /* max CP ID + 1 (0 if none) */ +#define XCHAL_CP_MASK 0x80 /* bitmask of all CPs by ID */ +#define XCHAL_CP_PORT_MASK 0x80 /* bitmask of only port CPs */ + +/* Basic parameters of each coprocessor: */ +#define XCHAL_CP7_NAME "XTIOP" +#define XCHAL_CP7_IDENT XTIOP +#define XCHAL_CP7_SA_SIZE 0 /* size of state save area */ +#define XCHAL_CP7_SA_ALIGN 1 /* min alignment of save area */ +#define XCHAL_CP_ID_XTIOP 7 /* coprocessor ID (0..7) */ + +/* Filler info for unassigned coprocessors, to simplify arrays etc: */ +#define XCHAL_CP0_SA_SIZE 0 +#define XCHAL_CP0_SA_ALIGN 1 +#define XCHAL_CP1_SA_SIZE 0 +#define XCHAL_CP1_SA_ALIGN 1 +#define XCHAL_CP2_SA_SIZE 0 +#define XCHAL_CP2_SA_ALIGN 1 +#define XCHAL_CP3_SA_SIZE 0 +#define XCHAL_CP3_SA_ALIGN 1 +#define XCHAL_CP4_SA_SIZE 0 +#define XCHAL_CP4_SA_ALIGN 1 +#define XCHAL_CP5_SA_SIZE 0 +#define XCHAL_CP5_SA_ALIGN 1 +#define XCHAL_CP6_SA_SIZE 0 +#define XCHAL_CP6_SA_ALIGN 1 + +/* Save area for non-coprocessor optional and custom (TIE) state: */ +#define XCHAL_NCP_SA_SIZE 32 +#define XCHAL_NCP_SA_ALIGN 4 + +/* Total save area for optional and custom state (NCP + CPn): */ +#define XCHAL_TOTAL_SA_SIZE 32 /* with 16-byte align padding */ +#define XCHAL_TOTAL_SA_ALIGN 4 /* actual minimum alignment */ + +/* + * Detailed contents of save areas. + * NOTE: caller must define the XCHAL_SA_REG macro (not defined here) + * before expanding the XCHAL_xxx_SA_LIST() macros. + * + * XCHAL_SA_REG(s,ccused,abikind,kind,opt,name,galign,align,asize, + * dbnum,base,regnum,bitsz,gapsz,reset,x...) + * + * s = passed from XCHAL_*_LIST(s), eg. to select how to expand + * ccused = set if used by compiler without special options or code + * abikind = 0 (caller-saved), 1 (callee-saved), or 2 (thread-global) + * kind = 0 (special reg), 1 (TIE user reg), or 2 (TIE regfile reg) + * opt = 0 (custom TIE extension or coprocessor), or 1 (optional reg) + * name = lowercase reg name (no quotes) + * galign = group byte alignment (power of 2) (galign >= align) + * align = register byte alignment (power of 2) + * asize = allocated size in bytes (asize*8 == bitsz + gapsz + padsz) + * (not including any pad bytes required to galign this or next reg) + * dbnum = unique target number f/debug (see <xtensa-libdb-macros.h>) + * base = reg shortname w/o index (or sr=special, ur=TIE user reg) + * regnum = reg index in regfile, or special/TIE-user reg number + * bitsz = number of significant bits (regfile width, or ur/sr mask bits) + * gapsz = intervening bits, if bitsz bits not stored contiguously + * (padsz = pad bits at end [TIE regfile] or at msbits [ur,sr] of asize) + * reset = register reset value (or 0 if undefined at reset) + * x = reserved for future use (0 until then) + * + * To filter out certain registers, e.g. to expand only the non-global + * registers used by the compiler, you can do something like this: + * + * #define XCHAL_SA_REG(s,ccused,p...) SELCC##ccused(p) + * #define SELCC0(p...) + * #define SELCC1(abikind,p...) SELAK##abikind(p) + * #define SELAK0(p...) REG(p) + * #define SELAK1(p...) REG(p) + * #define SELAK2(p...) + * #define REG(kind,tie,name,galn,aln,asz,csz,dbnum,base,rnum,bsz,rst,x...) \ + * ...what you want to expand... + */ + +#define XCHAL_NCP_SA_NUM 8 +#define XCHAL_NCP_SA_LIST(s) \ + XCHAL_SA_REG(s,1,0,0,1, acclo, 4, 4, 4,0x0210, sr,16 , 32,0,0,0) \ + XCHAL_SA_REG(s,1,0,0,1, acchi, 4, 4, 4,0x0211, sr,17 , 8,0,0,0) \ + XCHAL_SA_REG(s,0,0,0,1, m0, 4, 4, 4,0x0220, sr,32 , 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,0,1, m1, 4, 4, 4,0x0221, sr,33 , 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,0,1, m2, 4, 4, 4,0x0222, sr,34 , 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,0,1, m3, 4, 4, 4,0x0223, sr,35 , 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,0,1, scompare1, 4, 4, 4,0x020C, sr,12 , 32,0,0,0) \ + XCHAL_SA_REG(s,1,2,1,1, threadptr, 4, 4, 4,0x03E7, ur,231, 32,0,0,0) + +#define XCHAL_CP0_SA_NUM 0 +#define XCHAL_CP0_SA_LIST(s) /* empty */ + +#define XCHAL_CP1_SA_NUM 0 +#define XCHAL_CP1_SA_LIST(s) /* empty */ + +#define XCHAL_CP2_SA_NUM 0 +#define XCHAL_CP2_SA_LIST(s) /* empty */ + +#define XCHAL_CP3_SA_NUM 0 +#define XCHAL_CP3_SA_LIST(s) /* empty */ + +#define XCHAL_CP4_SA_NUM 0 +#define XCHAL_CP4_SA_LIST(s) /* empty */ + +#define XCHAL_CP5_SA_NUM 0 +#define XCHAL_CP5_SA_LIST(s) /* empty */ + +#define XCHAL_CP6_SA_NUM 0 +#define XCHAL_CP6_SA_LIST(s) /* empty */ + +#define XCHAL_CP7_SA_NUM 0 +#define XCHAL_CP7_SA_LIST(s) /* empty */ + +/* Byte length of instruction from its first nibble (op0 field), per FLIX. */ +#define XCHAL_OP0_FORMAT_LENGTHS 3,3,3,3,3,3,3,3,2,2,2,2,2,2,3,3 + +#endif /*_XTENSA_CORE_TIE_H*/ + diff --git a/arch/xtensa/variants/fsf/include/variant/core.h b/arch/xtensa/variants/fsf/include/variant/core.h new file mode 100644 index 00000000..2f337605 --- /dev/null +++ b/arch/xtensa/variants/fsf/include/variant/core.h @@ -0,0 +1,359 @@ +/* + * Xtensa processor core configuration information. + * + * 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) 1999-2006 Tensilica Inc. + */ + +#ifndef _XTENSA_CORE_H +#define _XTENSA_CORE_H + + +/**************************************************************************** + Parameters Useful for Any Code, USER or PRIVILEGED + ****************************************************************************/ + +/* + * Note: Macros of the form XCHAL_HAVE_*** have a value of 1 if the option is + * configured, and a value of 0 otherwise. These macros are always defined. + */ + + +/*---------------------------------------------------------------------- + ISA + ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_BE 1 /* big-endian byte ordering */ +#define XCHAL_HAVE_WINDOWED 1 /* windowed registers option */ +#define XCHAL_NUM_AREGS 64 /* num of physical addr regs */ +#define XCHAL_NUM_AREGS_LOG2 6 /* log2(XCHAL_NUM_AREGS) */ +#define XCHAL_MAX_INSTRUCTION_SIZE 3 /* max instr bytes (3..8) */ +#define XCHAL_HAVE_DEBUG 1 /* debug option */ +#define XCHAL_HAVE_DENSITY 1 /* 16-bit instructions */ +#define XCHAL_HAVE_LOOPS 1 /* zero-overhead loops */ +#define XCHAL_HAVE_NSA 1 /* NSA/NSAU instructions */ +#define XCHAL_HAVE_MINMAX 0 /* MIN/MAX instructions */ +#define XCHAL_HAVE_SEXT 0 /* SEXT instruction */ +#define XCHAL_HAVE_CLAMPS 0 /* CLAMPS instruction */ +#define XCHAL_HAVE_MUL16 0 /* MUL16S/MUL16U instructions */ +#define XCHAL_HAVE_MUL32 0 /* MULL instruction */ +#define XCHAL_HAVE_MUL32_HIGH 0 /* MULUH/MULSH instructions */ +#define XCHAL_HAVE_L32R 1 /* L32R instruction */ +#define XCHAL_HAVE_ABSOLUTE_LITERALS 1 /* non-PC-rel (extended) L32R */ +#define XCHAL_HAVE_CONST16 0 /* CONST16 instruction */ +#define XCHAL_HAVE_ADDX 1 /* ADDX#/SUBX# instructions */ +#define XCHAL_HAVE_WIDE_BRANCHES 0 /* B*.W18 or B*.W15 instr's */ +#define XCHAL_HAVE_PREDICTED_BRANCHES 0 /* B[EQ/EQZ/NE/NEZ]T instr's */ +#define XCHAL_HAVE_CALL4AND12 1 /* (obsolete option) */ +#define XCHAL_HAVE_ABS 1 /* ABS instruction */ +/*#define XCHAL_HAVE_POPC 0*/ /* POPC instruction */ +/*#define XCHAL_HAVE_CRC 0*/ /* CRC instruction */ +#define XCHAL_HAVE_RELEASE_SYNC 0 /* L32AI/S32RI instructions */ +#define XCHAL_HAVE_S32C1I 0 /* S32C1I instruction */ +#define XCHAL_HAVE_SPECULATION 0 /* speculation */ +#define XCHAL_HAVE_FULL_RESET 1 /* all regs/state reset */ +#define XCHAL_NUM_CONTEXTS 1 /* */ +#define XCHAL_NUM_MISC_REGS 2 /* num of scratch regs (0..4) */ +#define XCHAL_HAVE_TAP_MASTER 0 /* JTAG TAP control instr's */ +#define XCHAL_HAVE_PRID 1 /* processor ID register */ +#define XCHAL_HAVE_THREADPTR 1 /* THREADPTR register */ +#define XCHAL_HAVE_BOOLEANS 0 /* boolean registers */ +#define XCHAL_HAVE_CP 0 /* CPENABLE reg (coprocessor) */ +#define XCHAL_CP_MAXCFG 0 /* max allowed cp id plus one */ +#define XCHAL_HAVE_MAC16 0 /* MAC16 package */ +#define XCHAL_HAVE_VECTORFPU2005 0 /* vector floating-point pkg */ +#define XCHAL_HAVE_FP 0 /* floating point pkg */ +#define XCHAL_HAVE_VECTRA1 0 /* Vectra I pkg */ +#define XCHAL_HAVE_VECTRALX 0 /* Vectra LX pkg */ +#define XCHAL_HAVE_HIFI2 0 /* HiFi2 Audio Engine pkg */ + + +/*---------------------------------------------------------------------- + MISC + ----------------------------------------------------------------------*/ + +#define XCHAL_NUM_WRITEBUFFER_ENTRIES 4 /* size of write buffer */ +#define XCHAL_INST_FETCH_WIDTH 4 /* instr-fetch width in bytes */ +#define XCHAL_DATA_WIDTH 4 /* data width in bytes */ +/* In T1050, applies to selected core load and store instructions (see ISA): */ +#define XCHAL_UNALIGNED_LOAD_EXCEPTION 1 /* unaligned loads cause exc. */ +#define XCHAL_UNALIGNED_STORE_EXCEPTION 1 /* unaligned stores cause exc.*/ + +#define XCHAL_CORE_ID "fsf" /* alphanum core name + (CoreID) set in the Xtensa + Processor Generator */ + +#define XCHAL_BUILD_UNIQUE_ID 0x00006700 /* 22-bit sw build ID */ + +/* + * These definitions describe the hardware targeted by this software. + */ +#define XCHAL_HW_CONFIGID0 0xC103C3FF /* ConfigID hi 32 bits*/ +#define XCHAL_HW_CONFIGID1 0x0C006700 /* ConfigID lo 32 bits*/ +#define XCHAL_HW_VERSION_NAME "LX2.0.0" /* full version name */ +#define XCHAL_HW_VERSION_MAJOR 2200 /* major ver# of targeted hw */ +#define XCHAL_HW_VERSION_MINOR 0 /* minor ver# of targeted hw */ +#define XTHAL_HW_REL_LX2 1 +#define XTHAL_HW_REL_LX2_0 1 +#define XTHAL_HW_REL_LX2_0_0 1 +#define XCHAL_HW_CONFIGID_RELIABLE 1 +/* If software targets a *range* of hardware versions, these are the bounds: */ +#define XCHAL_HW_MIN_VERSION_MAJOR 2200 /* major v of earliest tgt hw */ +#define XCHAL_HW_MIN_VERSION_MINOR 0 /* minor v of earliest tgt hw */ +#define XCHAL_HW_MAX_VERSION_MAJOR 2200 /* major v of latest tgt hw */ +#define XCHAL_HW_MAX_VERSION_MINOR 0 /* minor v of latest tgt hw */ + + +/*---------------------------------------------------------------------- + CACHE + ----------------------------------------------------------------------*/ + +#define XCHAL_ICACHE_LINESIZE 16 /* I-cache line size in bytes */ +#define XCHAL_DCACHE_LINESIZE 16 /* D-cache line size in bytes */ +#define XCHAL_ICACHE_LINEWIDTH 4 /* log2(I line size in bytes) */ +#define XCHAL_DCACHE_LINEWIDTH 4 /* log2(D line size in bytes) */ + +#define XCHAL_ICACHE_SIZE 8192 /* I-cache size in bytes or 0 */ +#define XCHAL_DCACHE_SIZE 8192 /* D-cache size in bytes or 0 */ + +#define XCHAL_DCACHE_IS_WRITEBACK 0 /* writeback feature */ + + + + +/**************************************************************************** + Parameters Useful for PRIVILEGED (Supervisory or Non-Virtualized) Code + ****************************************************************************/ + + +#ifndef XTENSA_HAL_NON_PRIVILEGED_ONLY + +/*---------------------------------------------------------------------- + CACHE + ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_PIF 1 /* any outbound PIF present */ + +/* If present, cache size in bytes == (ways * 2^(linewidth + setwidth)). */ + +/* Number of cache sets in log2(lines per way): */ +#define XCHAL_ICACHE_SETWIDTH 8 +#define XCHAL_DCACHE_SETWIDTH 8 + +/* Cache set associativity (number of ways): */ +#define XCHAL_ICACHE_WAYS 2 +#define XCHAL_DCACHE_WAYS 2 + +/* Cache features: */ +#define XCHAL_ICACHE_LINE_LOCKABLE 0 +#define XCHAL_DCACHE_LINE_LOCKABLE 0 +#define XCHAL_ICACHE_ECC_PARITY 0 +#define XCHAL_DCACHE_ECC_PARITY 0 + +/* Number of encoded cache attr bits (see <xtensa/hal.h> for decoded bits): */ +#define XCHAL_CA_BITS 4 + + +/*---------------------------------------------------------------------- + INTERNAL I/D RAM/ROMs and XLMI + ----------------------------------------------------------------------*/ + +#define XCHAL_NUM_INSTROM 0 /* number of core instr. ROMs */ +#define XCHAL_NUM_INSTRAM 0 /* number of core instr. RAMs */ +#define XCHAL_NUM_DATAROM 0 /* number of core data ROMs */ +#define XCHAL_NUM_DATARAM 0 /* number of core data RAMs */ +#define XCHAL_NUM_URAM 0 /* number of core unified RAMs*/ +#define XCHAL_NUM_XLMI 0 /* number of core XLMI ports */ + + +/*---------------------------------------------------------------------- + INTERRUPTS and TIMERS + ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_INTERRUPTS 1 /* interrupt option */ +#define XCHAL_HAVE_HIGHPRI_INTERRUPTS 1 /* med/high-pri. interrupts */ +#define XCHAL_HAVE_NMI 0 /* non-maskable interrupt */ +#define XCHAL_HAVE_CCOUNT 1 /* CCOUNT reg. (timer option) */ +#define XCHAL_NUM_TIMERS 3 /* number of CCOMPAREn regs */ +#define XCHAL_NUM_INTERRUPTS 17 /* number of interrupts */ +#define XCHAL_NUM_INTERRUPTS_LOG2 5 /* ceil(log2(NUM_INTERRUPTS)) */ +#define XCHAL_NUM_EXTINTERRUPTS 10 /* num of external interrupts */ +#define XCHAL_NUM_INTLEVELS 4 /* number of interrupt levels + (not including level zero) */ +#define XCHAL_EXCM_LEVEL 1 /* level masked by PS.EXCM */ + /* (always 1 in XEA1; levels 2 .. EXCM_LEVEL are "medium priority") */ + +/* Masks of interrupts at each interrupt level: */ +#define XCHAL_INTLEVEL1_MASK 0x000064F9 +#define XCHAL_INTLEVEL2_MASK 0x00008902 +#define XCHAL_INTLEVEL3_MASK 0x00011204 +#define XCHAL_INTLEVEL4_MASK 0x00000000 +#define XCHAL_INTLEVEL5_MASK 0x00000000 +#define XCHAL_INTLEVEL6_MASK 0x00000000 +#define XCHAL_INTLEVEL7_MASK 0x00000000 + +/* Masks of interrupts at each range 1..n of interrupt levels: */ +#define XCHAL_INTLEVEL1_ANDBELOW_MASK 0x000064F9 +#define XCHAL_INTLEVEL2_ANDBELOW_MASK 0x0000EDFB +#define XCHAL_INTLEVEL3_ANDBELOW_MASK 0x0001FFFF +#define XCHAL_INTLEVEL4_ANDBELOW_MASK 0x0001FFFF +#define XCHAL_INTLEVEL5_ANDBELOW_MASK 0x0001FFFF +#define XCHAL_INTLEVEL6_ANDBELOW_MASK 0x0001FFFF +#define XCHAL_INTLEVEL7_ANDBELOW_MASK 0x0001FFFF + +/* Level of each interrupt: */ +#define XCHAL_INT0_LEVEL 1 +#define XCHAL_INT1_LEVEL 2 +#define XCHAL_INT2_LEVEL 3 +#define XCHAL_INT3_LEVEL 1 +#define XCHAL_INT4_LEVEL 1 +#define XCHAL_INT5_LEVEL 1 +#define XCHAL_INT6_LEVEL 1 +#define XCHAL_INT7_LEVEL 1 +#define XCHAL_INT8_LEVEL 2 +#define XCHAL_INT9_LEVEL 3 +#define XCHAL_INT10_LEVEL 1 +#define XCHAL_INT11_LEVEL 2 +#define XCHAL_INT12_LEVEL 3 +#define XCHAL_INT13_LEVEL 1 +#define XCHAL_INT14_LEVEL 1 +#define XCHAL_INT15_LEVEL 2 +#define XCHAL_INT16_LEVEL 3 +#define XCHAL_DEBUGLEVEL 4 /* debug interrupt level */ +#define XCHAL_HAVE_DEBUG_EXTERN_INT 0 /* OCD external db interrupt */ + +/* Type of each interrupt: */ +#define XCHAL_INT0_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT1_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT2_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT3_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT4_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT5_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT6_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT7_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT8_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT9_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT10_TYPE XTHAL_INTTYPE_TIMER +#define XCHAL_INT11_TYPE XTHAL_INTTYPE_TIMER +#define XCHAL_INT12_TYPE XTHAL_INTTYPE_TIMER +#define XCHAL_INT13_TYPE XTHAL_INTTYPE_SOFTWARE +#define XCHAL_INT14_TYPE XTHAL_INTTYPE_SOFTWARE +#define XCHAL_INT15_TYPE XTHAL_INTTYPE_SOFTWARE +#define XCHAL_INT16_TYPE XTHAL_INTTYPE_SOFTWARE + +/* Masks of interrupts for each type of interrupt: */ +#define XCHAL_INTTYPE_MASK_UNCONFIGURED 0xFFFE0000 +#define XCHAL_INTTYPE_MASK_SOFTWARE 0x0001E000 +#define XCHAL_INTTYPE_MASK_EXTERN_EDGE 0x00000380 +#define XCHAL_INTTYPE_MASK_EXTERN_LEVEL 0x0000007F +#define XCHAL_INTTYPE_MASK_TIMER 0x00001C00 +#define XCHAL_INTTYPE_MASK_NMI 0x00000000 +#define XCHAL_INTTYPE_MASK_WRITE_ERROR 0x00000000 + +/* Interrupt numbers assigned to specific interrupt sources: */ +#define XCHAL_TIMER0_INTERRUPT 10 /* CCOMPARE0 */ +#define XCHAL_TIMER1_INTERRUPT 11 /* CCOMPARE1 */ +#define XCHAL_TIMER2_INTERRUPT 12 /* CCOMPARE2 */ +#define XCHAL_TIMER3_INTERRUPT XTHAL_TIMER_UNCONFIGURED + +/* Interrupt numbers for levels at which only one interrupt is configured: */ +/* (There are many interrupts each at level(s) 1, 2, 3.) */ + + +/* + * External interrupt vectors/levels. + * These macros describe how Xtensa processor interrupt numbers + * (as numbered internally, eg. in INTERRUPT and INTENABLE registers) + * map to external BInterrupt<n> pins, for those interrupts + * configured as external (level-triggered, edge-triggered, or NMI). + * See the Xtensa processor databook for more details. + */ + +/* Core interrupt numbers mapped to each EXTERNAL interrupt number: */ +#define XCHAL_EXTINT0_NUM 0 /* (intlevel 1) */ +#define XCHAL_EXTINT1_NUM 1 /* (intlevel 2) */ +#define XCHAL_EXTINT2_NUM 2 /* (intlevel 3) */ +#define XCHAL_EXTINT3_NUM 3 /* (intlevel 1) */ +#define XCHAL_EXTINT4_NUM 4 /* (intlevel 1) */ +#define XCHAL_EXTINT5_NUM 5 /* (intlevel 1) */ +#define XCHAL_EXTINT6_NUM 6 /* (intlevel 1) */ +#define XCHAL_EXTINT7_NUM 7 /* (intlevel 1) */ +#define XCHAL_EXTINT8_NUM 8 /* (intlevel 2) */ +#define XCHAL_EXTINT9_NUM 9 /* (intlevel 3) */ + + +/*---------------------------------------------------------------------- + EXCEPTIONS and VECTORS + ----------------------------------------------------------------------*/ + +#define XCHAL_XEA_VERSION 2 /* Xtensa Exception Architecture + number: 1 == XEA1 (old) + 2 == XEA2 (new) + 0 == XEAX (extern) */ +#define XCHAL_HAVE_XEA1 0 /* Exception Architecture 1 */ +#define XCHAL_HAVE_XEA2 1 /* Exception Architecture 2 */ +#define XCHAL_HAVE_XEAX 0 /* External Exception Arch. */ +#define XCHAL_HAVE_EXCEPTIONS 1 /* exception option */ +#define XCHAL_HAVE_MEM_ECC_PARITY 0 /* local memory ECC/parity */ + +#define XCHAL_RESET_VECTOR_VADDR 0xFE000020 +#define XCHAL_RESET_VECTOR_PADDR 0xFE000020 +#define XCHAL_USER_VECTOR_VADDR 0xD0000220 +#define XCHAL_USER_VECTOR_PADDR 0x00000220 +#define XCHAL_KERNEL_VECTOR_VADDR 0xD0000200 +#define XCHAL_KERNEL_VECTOR_PADDR 0x00000200 +#define XCHAL_DOUBLEEXC_VECTOR_VADDR 0xD0000290 +#define XCHAL_DOUBLEEXC_VECTOR_PADDR 0x00000290 +#define XCHAL_WINDOW_VECTORS_VADDR 0xD0000000 +#define XCHAL_WINDOW_VECTORS_PADDR 0x00000000 +#define XCHAL_INTLEVEL2_VECTOR_VADDR 0xD0000240 +#define XCHAL_INTLEVEL2_VECTOR_PADDR 0x00000240 +#define XCHAL_INTLEVEL3_VECTOR_VADDR 0xD0000250 +#define XCHAL_INTLEVEL3_VECTOR_PADDR 0x00000250 +#define XCHAL_INTLEVEL4_VECTOR_VADDR 0xFE000520 +#define XCHAL_INTLEVEL4_VECTOR_PADDR 0xFE000520 +#define XCHAL_DEBUG_VECTOR_VADDR XCHAL_INTLEVEL4_VECTOR_VADDR +#define XCHAL_DEBUG_VECTOR_PADDR XCHAL_INTLEVEL4_VECTOR_PADDR + + +/*---------------------------------------------------------------------- + DEBUG + ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_OCD 1 /* OnChipDebug option */ +#define XCHAL_NUM_IBREAK 2 /* number of IBREAKn regs */ +#define XCHAL_NUM_DBREAK 2 /* number of DBREAKn regs */ +#define XCHAL_HAVE_OCD_DIR_ARRAY 1 /* faster OCD option */ + + +/*---------------------------------------------------------------------- + MMU + ----------------------------------------------------------------------*/ + +/* See <xtensa/config/core-matmap.h> header file for more details. */ + +#define XCHAL_HAVE_TLBS 1 /* inverse of HAVE_CACHEATTR */ +#define XCHAL_HAVE_SPANNING_WAY 0 /* one way maps I+D 4GB vaddr */ +#define XCHAL_HAVE_IDENTITY_MAP 0 /* vaddr == paddr always */ +#define XCHAL_HAVE_CACHEATTR 0 /* CACHEATTR register present */ +#define XCHAL_HAVE_MIMIC_CACHEATTR 0 /* region protection */ +#define XCHAL_HAVE_XLT_CACHEATTR 0 /* region prot. w/translation */ +#define XCHAL_HAVE_PTP_MMU 1 /* full MMU (with page table + [autorefill] and protection) + usable for an MMU-based OS */ +/* If none of the above last 4 are set, it's a custom TLB configuration. */ +#define XCHAL_ITLB_ARF_ENTRIES_LOG2 2 /* log2(autorefill way size) */ +#define XCHAL_DTLB_ARF_ENTRIES_LOG2 2 /* log2(autorefill way size) */ + +#define XCHAL_MMU_ASID_BITS 8 /* number of bits in ASIDs */ +#define XCHAL_MMU_RINGS 4 /* number of rings (1..4) */ +#define XCHAL_MMU_RING_BITS 2 /* num of bits in RING field */ + +#endif /* !XTENSA_HAL_NON_PRIVILEGED_ONLY */ + + +#endif /* _XTENSA_CORE_CONFIGURATION_H */ + diff --git a/arch/xtensa/variants/fsf/include/variant/tie-asm.h b/arch/xtensa/variants/fsf/include/variant/tie-asm.h new file mode 100644 index 00000000..68a73bf4 --- /dev/null +++ b/arch/xtensa/variants/fsf/include/variant/tie-asm.h @@ -0,0 +1,70 @@ +/* + * This header file contains assembly-language definitions (assembly + * macros, etc.) for this specific Xtensa processor's TIE extensions + * and options. It is customized to this Xtensa processor configuration. + * + * 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) 1999-2008 Tensilica Inc. + */ + +#ifndef _XTENSA_CORE_TIE_ASM_H +#define _XTENSA_CORE_TIE_ASM_H + +/* Selection parameter values for save-area save/restore macros: */ +/* Option vs. TIE: */ +#define XTHAL_SAS_TIE 0x0001 /* custom extension or coprocessor */ +#define XTHAL_SAS_OPT 0x0002 /* optional (and not a coprocessor) */ +/* Whether used automatically by compiler: */ +#define XTHAL_SAS_NOCC 0x0004 /* not used by compiler w/o special opts/code */ +#define XTHAL_SAS_CC 0x0008 /* used by compiler without special opts/code */ +/* ABI handling across function calls: */ +#define XTHAL_SAS_CALR 0x0010 /* caller-saved */ +#define XTHAL_SAS_CALE 0x0020 /* callee-saved */ +#define XTHAL_SAS_GLOB 0x0040 /* global across function calls (in thread) */ +/* Misc */ +#define XTHAL_SAS_ALL 0xFFFF /* include all default NCP contents */ + + + +/* Macro to save all non-coprocessor (extra) custom TIE and optional state + * (not including zero-overhead loop registers). + * Save area ptr (clobbered): ptr (1 byte aligned) + * Scratch regs (clobbered): at1..at4 (only first XCHAL_NCP_NUM_ATMPS needed) + */ + .macro xchal_ncp_store ptr at1 at2 at3 at4 continue=0 ofs=-1 select=XTHAL_SAS_ALL + xchal_sa_start \continue, \ofs + .ifeq (XTHAL_SAS_OPT | XTHAL_SAS_CC | XTHAL_SAS_GLOB) & ~\select + xchal_sa_align \ptr, 0, 1024-4, 4, 4 + rur \at1, THREADPTR // threadptr option + s32i \at1, \ptr, .Lxchal_ofs_ + 0 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 4 + .endif + .endm // xchal_ncp_store + +/* Macro to save all non-coprocessor (extra) custom TIE and optional state + * (not including zero-overhead loop registers). + * Save area ptr (clobbered): ptr (1 byte aligned) + * Scratch regs (clobbered): at1..at4 (only first XCHAL_NCP_NUM_ATMPS needed) + */ + .macro xchal_ncp_load ptr at1 at2 at3 at4 continue=0 ofs=-1 select=XTHAL_SAS_ALL + xchal_sa_start \continue, \ofs + .ifeq (XTHAL_SAS_OPT | XTHAL_SAS_CC | XTHAL_SAS_GLOB) & ~\select + xchal_sa_align \ptr, 0, 1024-4, 4, 4 + l32i \at1, \ptr, .Lxchal_ofs_ + 0 + wur \at1, THREADPTR // threadptr option + .set .Lxchal_ofs_, .Lxchal_ofs_ + 4 + .endif + .endm // xchal_ncp_load + + + +#define XCHAL_NCP_NUM_ATMPS 1 + + +#define XCHAL_SA_NUM_ATMPS 1 + +#endif /*_XTENSA_CORE_TIE_ASM_H*/ + diff --git a/arch/xtensa/variants/fsf/include/variant/tie.h b/arch/xtensa/variants/fsf/include/variant/tie.h new file mode 100644 index 00000000..bf402011 --- /dev/null +++ b/arch/xtensa/variants/fsf/include/variant/tie.h @@ -0,0 +1,77 @@ +/* + * This header file describes this specific Xtensa processor's TIE extensions + * that extend basic Xtensa core functionality. It is customized to this + * Xtensa processor configuration. + * + * 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) 1999-2007 Tensilica Inc. + */ + +#ifndef _XTENSA_CORE_TIE_H +#define _XTENSA_CORE_TIE_H + +#define XCHAL_CP_NUM 0 /* number of coprocessors */ +#define XCHAL_CP_MAX 0 /* max CP ID + 1 (0 if none) */ +#define XCHAL_CP_MASK 0x00 /* bitmask of all CPs by ID */ +#define XCHAL_CP_PORT_MASK 0x00 /* bitmask of only port CPs */ + +/* Basic parameters of each coprocessor: */ +#define XCHAL_CP7_NAME "XTIOP" +#define XCHAL_CP7_IDENT XTIOP +#define XCHAL_CP7_SA_SIZE 0 /* size of state save area */ +#define XCHAL_CP7_SA_ALIGN 1 /* min alignment of save area */ +#define XCHAL_CP_ID_XTIOP 7 /* coprocessor ID (0..7) */ + +/* Filler info for unassigned coprocessors, to simplify arrays etc: */ +#define XCHAL_NCP_SA_SIZE 0 +#define XCHAL_NCP_SA_ALIGN 1 +#define XCHAL_CP0_SA_SIZE 0 +#define XCHAL_CP0_SA_ALIGN 1 +#define XCHAL_CP1_SA_SIZE 0 +#define XCHAL_CP1_SA_ALIGN 1 +#define XCHAL_CP2_SA_SIZE 0 +#define XCHAL_CP2_SA_ALIGN 1 +#define XCHAL_CP3_SA_SIZE 0 +#define XCHAL_CP3_SA_ALIGN 1 +#define XCHAL_CP4_SA_SIZE 0 +#define XCHAL_CP4_SA_ALIGN 1 +#define XCHAL_CP5_SA_SIZE 0 +#define XCHAL_CP5_SA_ALIGN 1 +#define XCHAL_CP6_SA_SIZE 0 +#define XCHAL_CP6_SA_ALIGN 1 + +/* Save area for non-coprocessor optional and custom (TIE) state: */ +#define XCHAL_NCP_SA_SIZE 0 +#define XCHAL_NCP_SA_ALIGN 1 + +/* Total save area for optional and custom state (NCP + CPn): */ +#define XCHAL_TOTAL_SA_SIZE 0 /* with 16-byte align padding */ +#define XCHAL_TOTAL_SA_ALIGN 1 /* actual minimum alignment */ + +#define XCHAL_NCP_SA_NUM 0 +#define XCHAL_NCP_SA_LIST(s) +#define XCHAL_CP0_SA_NUM 0 +#define XCHAL_CP0_SA_LIST(s) +#define XCHAL_CP1_SA_NUM 0 +#define XCHAL_CP1_SA_LIST(s) +#define XCHAL_CP2_SA_NUM 0 +#define XCHAL_CP2_SA_LIST(s) +#define XCHAL_CP3_SA_NUM 0 +#define XCHAL_CP3_SA_LIST(s) +#define XCHAL_CP4_SA_NUM 0 +#define XCHAL_CP4_SA_LIST(s) +#define XCHAL_CP5_SA_NUM 0 +#define XCHAL_CP5_SA_LIST(s) +#define XCHAL_CP6_SA_NUM 0 +#define XCHAL_CP6_SA_LIST(s) +#define XCHAL_CP7_SA_NUM 0 +#define XCHAL_CP7_SA_LIST(s) + +/* Byte length of instruction from its first nibble (op0 field), per FLIX. */ +#define XCHAL_OP0_FORMAT_LENGTHS 3,3,3,3,3,3,3,3,2,2,2,2,2,2,3,3 + +#endif /*_XTENSA_CORE_TIE_H*/ + diff --git a/arch/xtensa/variants/s6000/Makefile b/arch/xtensa/variants/s6000/Makefile new file mode 100644 index 00000000..3e7ef0a0 --- /dev/null +++ b/arch/xtensa/variants/s6000/Makefile @@ -0,0 +1,4 @@ +# s6000 Makefile + +obj-y += irq.o gpio.o dmac.o +obj-$(CONFIG_XTENSA_CALIBRATE_CCOUNT) += delay.o diff --git a/arch/xtensa/variants/s6000/delay.c b/arch/xtensa/variants/s6000/delay.c new file mode 100644 index 00000000..54b2b573 --- /dev/null +++ b/arch/xtensa/variants/s6000/delay.c @@ -0,0 +1,27 @@ +#include <asm/delay.h> +#include <asm/timex.h> +#include <asm/io.h> +#include <variant/hardware.h> + +#define LOOPS 10 +void platform_calibrate_ccount(void) +{ + u32 uninitialized_var(a); + u32 uninitialized_var(u); + u32 b; + u32 tstamp = S6_REG_GREG1 + S6_GREG1_GLOBAL_TIMER; + int i = LOOPS+1; + do { + u32 t = u; + asm volatile( + "1: l32i %0, %2, 0 ;" + " beq %0, %1, 1b ;" + : "=&a"(u) : "a"(t), "a"(tstamp)); + b = xtensa_get_ccount(); + if (i == LOOPS) + a = b; + } while (--i >= 0); + b -= a; + nsec_per_ccount = (LOOPS * 10000) / b; + ccount_per_jiffy = b * (100000UL / (LOOPS * HZ)); +} diff --git a/arch/xtensa/variants/s6000/dmac.c b/arch/xtensa/variants/s6000/dmac.c new file mode 100644 index 00000000..dc7f7c57 --- /dev/null +++ b/arch/xtensa/variants/s6000/dmac.c @@ -0,0 +1,173 @@ +/* + * Authors: Oskar Schirmer <os@emlix.com> + * Daniel Gloeckner <dg@emlix.com> + * (c) 2008 emlix GmbH http://www.emlix.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/kernel.h> +#include <linux/io.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/spinlock.h> +#include <asm/cacheflush.h> +#include <variant/dmac.h> + +/* DMA engine lookup */ + +struct s6dmac_ctrl s6dmac_ctrl[S6_DMAC_NB]; + + +/* DMA control, per engine */ + +void s6dmac_put_fifo_cache(u32 dmac, int chan, u32 src, u32 dst, u32 size) +{ + if (xtensa_need_flush_dma_source(src)) { + u32 base = src; + u32 span = size; + u32 chunk = readl(DMA_CHNL(dmac, chan) + S6_DMA_CMONCHUNK); + if (chunk && (size > chunk)) { + s32 skip = + readl(DMA_CHNL(dmac, chan) + S6_DMA_SRCSKIP); + u32 gaps = (size+chunk-1)/chunk - 1; + if (skip >= 0) { + span += gaps * skip; + } else if (-skip > chunk) { + s32 decr = gaps * (chunk + skip); + base += decr; + span = chunk - decr; + } else { + span = max(span + gaps * skip, + (chunk + skip) * gaps - skip); + } + } + flush_dcache_unaligned(base, span); + } + if (xtensa_need_invalidate_dma_destination(dst)) { + u32 base = dst; + u32 span = size; + u32 chunk = readl(DMA_CHNL(dmac, chan) + S6_DMA_CMONCHUNK); + if (chunk && (size > chunk)) { + s32 skip = + readl(DMA_CHNL(dmac, chan) + S6_DMA_DSTSKIP); + u32 gaps = (size+chunk-1)/chunk - 1; + if (skip >= 0) { + span += gaps * skip; + } else if (-skip > chunk) { + s32 decr = gaps * (chunk + skip); + base += decr; + span = chunk - decr; + } else { + span = max(span + gaps * skip, + (chunk + skip) * gaps - skip); + } + } + invalidate_dcache_unaligned(base, span); + } + s6dmac_put_fifo(dmac, chan, src, dst, size); +} + +void s6dmac_disable_error_irqs(u32 dmac, u32 mask) +{ + unsigned long flags; + spinlock_t *spinl = &s6dmac_ctrl[_dmac_addr_index(dmac)].lock; + spin_lock_irqsave(spinl, flags); + _s6dmac_disable_error_irqs(dmac, mask); + spin_unlock_irqrestore(spinl, flags); +} + +u32 s6dmac_int_sources(u32 dmac, u32 channel) +{ + u32 mask, ret, tmp; + mask = 1 << channel; + + tmp = readl(dmac + S6_DMA_TERMCNTIRQSTAT); + tmp &= mask; + writel(tmp, dmac + S6_DMA_TERMCNTIRQCLR); + ret = tmp >> channel; + + tmp = readl(dmac + S6_DMA_PENDCNTIRQSTAT); + tmp &= mask; + writel(tmp, dmac + S6_DMA_PENDCNTIRQCLR); + ret |= (tmp >> channel) << 1; + + tmp = readl(dmac + S6_DMA_LOWWMRKIRQSTAT); + tmp &= mask; + writel(tmp, dmac + S6_DMA_LOWWMRKIRQCLR); + ret |= (tmp >> channel) << 2; + + tmp = readl(dmac + S6_DMA_INTRAW0); + tmp &= (mask << S6_DMA_INT0_OVER) | (mask << S6_DMA_INT0_UNDER); + writel(tmp, dmac + S6_DMA_INTCLEAR0); + + if (tmp & (mask << S6_DMA_INT0_UNDER)) + ret |= 1 << 3; + if (tmp & (mask << S6_DMA_INT0_OVER)) + ret |= 1 << 4; + + tmp = readl(dmac + S6_DMA_MASTERERRINFO); + mask <<= S6_DMA_INT1_CHANNEL; + if (((tmp >> S6_DMA_MASTERERR_CHAN(0)) & S6_DMA_MASTERERR_CHAN_MASK) + == channel) + mask |= 1 << S6_DMA_INT1_MASTER; + if (((tmp >> S6_DMA_MASTERERR_CHAN(1)) & S6_DMA_MASTERERR_CHAN_MASK) + == channel) + mask |= 1 << (S6_DMA_INT1_MASTER + 1); + if (((tmp >> S6_DMA_MASTERERR_CHAN(2)) & S6_DMA_MASTERERR_CHAN_MASK) + == channel) + mask |= 1 << (S6_DMA_INT1_MASTER + 2); + + tmp = readl(dmac + S6_DMA_INTRAW1) & mask; + writel(tmp, dmac + S6_DMA_INTCLEAR1); + ret |= ((tmp >> channel) & 1) << 5; + ret |= ((tmp >> S6_DMA_INT1_MASTER) & S6_DMA_INT1_MASTER_MASK) << 6; + + return ret; +} + +void s6dmac_release_chan(u32 dmac, int chan) +{ + if (chan >= 0) + s6dmac_disable_chan(dmac, chan); +} + + +/* global init */ + +static inline void __init dmac_init(u32 dmac, u8 chan_nb) +{ + s6dmac_ctrl[S6_DMAC_INDEX(dmac)].dmac = dmac; + spin_lock_init(&s6dmac_ctrl[S6_DMAC_INDEX(dmac)].lock); + s6dmac_ctrl[S6_DMAC_INDEX(dmac)].chan_nb = chan_nb; + writel(S6_DMA_INT1_MASTER_MASK << S6_DMA_INT1_MASTER, + dmac + S6_DMA_INTCLEAR1); +} + +static inline void __init dmac_master(u32 dmac, + u32 m0start, u32 m0end, u32 m1start, u32 m1end) +{ + writel(m0start, dmac + S6_DMA_MASTER0START); + writel(m0end - 1, dmac + S6_DMA_MASTER0END); + writel(m1start, dmac + S6_DMA_MASTER1START); + writel(m1end - 1, dmac + S6_DMA_MASTER1END); +} + +static void __init s6_dmac_init(void) +{ + dmac_init(S6_REG_LMSDMA, S6_LMSDMA_NB); + dmac_master(S6_REG_LMSDMA, + S6_MEM_DDR, S6_MEM_PCIE_APER, S6_MEM_EFI, S6_MEM_GMAC); + dmac_init(S6_REG_NIDMA, S6_NIDMA_NB); + dmac_init(S6_REG_DPDMA, S6_DPDMA_NB); + dmac_master(S6_REG_DPDMA, + S6_MEM_DDR, S6_MEM_PCIE_APER, S6_REG_DP, S6_REG_DPDMA); + dmac_init(S6_REG_HIFDMA, S6_HIFDMA_NB); + dmac_master(S6_REG_HIFDMA, + S6_MEM_GMAC, S6_MEM_PCIE_CFG, S6_MEM_PCIE_APER, S6_MEM_AUX); +} + +arch_initcall(s6_dmac_init); diff --git a/arch/xtensa/variants/s6000/gpio.c b/arch/xtensa/variants/s6000/gpio.c new file mode 100644 index 00000000..7af0757e --- /dev/null +++ b/arch/xtensa/variants/s6000/gpio.c @@ -0,0 +1,230 @@ +/* + * s6000 gpio driver + * + * Copyright (c) 2009 emlix GmbH + * Authors: Oskar Schirmer <os@emlix.com> + * Johannes Weiner <jw@emlix.com> + * Daniel Gloeckner <dg@emlix.com> + */ +#include <linux/bitops.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/gpio.h> + +#include <variant/hardware.h> + +#define IRQ_BASE XTENSA_NR_IRQS + +#define S6_GPIO_DATA 0x000 +#define S6_GPIO_IS 0x404 +#define S6_GPIO_IBE 0x408 +#define S6_GPIO_IEV 0x40C +#define S6_GPIO_IE 0x410 +#define S6_GPIO_RIS 0x414 +#define S6_GPIO_MIS 0x418 +#define S6_GPIO_IC 0x41C +#define S6_GPIO_AFSEL 0x420 +#define S6_GPIO_DIR 0x800 +#define S6_GPIO_BANK(nr) ((nr) * 0x1000) +#define S6_GPIO_MASK(nr) (4 << (nr)) +#define S6_GPIO_OFFSET(nr) \ + (S6_GPIO_BANK((nr) >> 3) + S6_GPIO_MASK((nr) & 7)) + +static int direction_input(struct gpio_chip *chip, unsigned int off) +{ + writeb(0, S6_REG_GPIO + S6_GPIO_DIR + S6_GPIO_OFFSET(off)); + return 0; +} + +static int get(struct gpio_chip *chip, unsigned int off) +{ + return readb(S6_REG_GPIO + S6_GPIO_DATA + S6_GPIO_OFFSET(off)); +} + +static int direction_output(struct gpio_chip *chip, unsigned int off, int val) +{ + unsigned rel = S6_GPIO_OFFSET(off); + writeb(~0, S6_REG_GPIO + S6_GPIO_DIR + rel); + writeb(val ? ~0 : 0, S6_REG_GPIO + S6_GPIO_DATA + rel); + return 0; +} + +static void set(struct gpio_chip *chip, unsigned int off, int val) +{ + writeb(val ? ~0 : 0, S6_REG_GPIO + S6_GPIO_DATA + S6_GPIO_OFFSET(off)); +} + +static int to_irq(struct gpio_chip *chip, unsigned offset) +{ + if (offset < 8) + return offset + IRQ_BASE; + return -EINVAL; +} + +static struct gpio_chip gpiochip = { + .owner = THIS_MODULE, + .direction_input = direction_input, + .get = get, + .direction_output = direction_output, + .set = set, + .to_irq = to_irq, + .base = 0, + .ngpio = 24, + .can_sleep = 0, /* no blocking io needed */ + .exported = 0, /* no exporting to userspace */ +}; + +int s6_gpio_init(u32 afsel) +{ + writeb(afsel, S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_AFSEL); + writeb(afsel >> 8, S6_REG_GPIO + S6_GPIO_BANK(1) + S6_GPIO_AFSEL); + writeb(afsel >> 16, S6_REG_GPIO + S6_GPIO_BANK(2) + S6_GPIO_AFSEL); + return gpiochip_add(&gpiochip); +} + +static void ack(struct irq_data *d) +{ + writeb(1 << (d->irq - IRQ_BASE), S6_REG_GPIO + S6_GPIO_IC); +} + +static void mask(struct irq_data *d) +{ + u8 r = readb(S6_REG_GPIO + S6_GPIO_IE); + r &= ~(1 << (d->irq - IRQ_BASE)); + writeb(r, S6_REG_GPIO + S6_GPIO_IE); +} + +static void unmask(struct irq_data *d) +{ + u8 m = readb(S6_REG_GPIO + S6_GPIO_IE); + m |= 1 << (d->irq - IRQ_BASE); + writeb(m, S6_REG_GPIO + S6_GPIO_IE); +} + +static int set_type(struct irq_data *d, unsigned int type) +{ + const u8 m = 1 << (d->irq - IRQ_BASE); + irq_flow_handler_t handler; + u8 reg; + + if (type == IRQ_TYPE_PROBE) { + if ((readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_AFSEL) & m) + || (readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IE) & m) + || readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_DIR + + S6_GPIO_MASK(irq - IRQ_BASE))) + return 0; + type = IRQ_TYPE_EDGE_BOTH; + } + + reg = readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IS); + if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) { + reg |= m; + handler = handle_level_irq; + } else { + reg &= ~m; + handler = handle_edge_irq; + } + writeb(reg, S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IS); + __irq_set_handler_locked(irq, handler); + + reg = readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IEV); + if (type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_EDGE_RISING)) + reg |= m; + else + reg &= ~m; + writeb(reg, S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IEV); + + reg = readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IBE); + if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) + reg |= m; + else + reg &= ~m; + writeb(reg, S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IBE); + return 0; +} + +static struct irq_chip gpioirqs = { + .name = "GPIO", + .irq_ack = ack, + .irq_mask = mask, + .irq_unmask = unmask, + .irq_set_type = set_type, +}; + +static u8 demux_masks[4]; + +static void demux_irqs(unsigned int irq, struct irq_desc *desc) +{ + struct irq_chip *chip = irq_desc_get_chip(desc); + u8 *mask = irq_desc_get_handler_data(desc); + u8 pending; + int cirq; + + chip->irq_mask(&desc->irq_data); + chip->irq_ack(&desc->irq_data)); + pending = readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_MIS) & *mask; + cirq = IRQ_BASE - 1; + while (pending) { + int n = ffs(pending); + cirq += n; + pending >>= n; + generic_handle_irq(cirq); + } + chip->irq_unmask(&desc->irq_data)); +} + +extern const signed char *platform_irq_mappings[XTENSA_NR_IRQS]; + +void __init variant_init_irq(void) +{ + int irq, n; + writeb(0, S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IE); + for (irq = n = 0; irq < XTENSA_NR_IRQS; irq++) { + const signed char *mapping = platform_irq_mappings[irq]; + int alone = 1; + u8 mask; + if (!mapping) + continue; + for(mask = 0; *mapping != -1; mapping++) + switch (*mapping) { + case S6_INTC_GPIO(0): + mask |= 1 << 0; + break; + case S6_INTC_GPIO(1): + mask |= 1 << 1; + break; + case S6_INTC_GPIO(2): + mask |= 1 << 2; + break; + case S6_INTC_GPIO(3): + mask |= 0x1f << 3; + break; + default: + alone = 0; + } + if (mask) { + int cirq, i; + if (!alone) { + printk(KERN_ERR "chained irq chips can't share" + " parent irq %i\n", irq); + continue; + } + demux_masks[n] = mask; + cirq = IRQ_BASE - 1; + do { + i = ffs(mask); + cirq += i; + mask >>= i; + irq_set_chip(cirq, &gpioirqs); + irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW); + } while (mask); + irq_set_handler_data(irq, demux_masks + n); + irq_set_chained_handler(irq, demux_irqs); + if (++n == ARRAY_SIZE(demux_masks)) + break; + } + } +} diff --git a/arch/xtensa/variants/s6000/include/variant/core.h b/arch/xtensa/variants/s6000/include/variant/core.h new file mode 100644 index 00000000..af007953 --- /dev/null +++ b/arch/xtensa/variants/s6000/include/variant/core.h @@ -0,0 +1,431 @@ +/* + * Xtensa processor core configuration information. + * + * 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) 1999-2008 Tensilica Inc. + */ + +#ifndef _XTENSA_CORE_CONFIGURATION_H +#define _XTENSA_CORE_CONFIGURATION_H + + +/**************************************************************************** + Parameters Useful for Any Code, USER or PRIVILEGED + ****************************************************************************/ + +/* + * Note: Macros of the form XCHAL_HAVE_*** have a value of 1 if the option is + * configured, and a value of 0 otherwise. These macros are always defined. + */ + + +/*---------------------------------------------------------------------- + ISA + ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_BE 0 /* big-endian byte ordering */ +#define XCHAL_HAVE_WINDOWED 1 /* windowed registers option */ +#define XCHAL_NUM_AREGS 64 /* num of physical addr regs */ +#define XCHAL_NUM_AREGS_LOG2 6 /* log2(XCHAL_NUM_AREGS) */ +#define XCHAL_MAX_INSTRUCTION_SIZE 8 /* max instr bytes (3..8) */ +#define XCHAL_HAVE_DEBUG 1 /* debug option */ +#define XCHAL_HAVE_DENSITY 1 /* 16-bit instructions */ +#define XCHAL_HAVE_LOOPS 1 /* zero-overhead loops */ +#define XCHAL_HAVE_NSA 1 /* NSA/NSAU instructions */ +#define XCHAL_HAVE_MINMAX 1 /* MIN/MAX instructions */ +#define XCHAL_HAVE_SEXT 1 /* SEXT instruction */ +#define XCHAL_HAVE_CLAMPS 1 /* CLAMPS instruction */ +#define XCHAL_HAVE_MUL16 1 /* MUL16S/MUL16U instructions */ +#define XCHAL_HAVE_MUL32 1 /* MULL instruction */ +#define XCHAL_HAVE_MUL32_HIGH 1 /* MULUH/MULSH instructions */ +#define XCHAL_HAVE_DIV32 0 /* QUOS/QUOU/REMS/REMU instructions */ +#define XCHAL_HAVE_L32R 1 /* L32R instruction */ +#define XCHAL_HAVE_ABSOLUTE_LITERALS 1 /* non-PC-rel (extended) L32R */ +#define XCHAL_HAVE_CONST16 0 /* CONST16 instruction */ +#define XCHAL_HAVE_ADDX 1 /* ADDX#/SUBX# instructions */ +#define XCHAL_HAVE_WIDE_BRANCHES 0 /* B*.W18 or B*.W15 instr's */ +#define XCHAL_HAVE_PREDICTED_BRANCHES 0 /* B[EQ/EQZ/NE/NEZ]T instr's */ +#define XCHAL_HAVE_CALL4AND12 1 /* (obsolete option) */ +#define XCHAL_HAVE_ABS 1 /* ABS instruction */ +/*#define XCHAL_HAVE_POPC 0*/ /* POPC instruction */ +/*#define XCHAL_HAVE_CRC 0*/ /* CRC instruction */ +#define XCHAL_HAVE_RELEASE_SYNC 0 /* L32AI/S32RI instructions */ +#define XCHAL_HAVE_S32C1I 0 /* S32C1I instruction */ +#define XCHAL_HAVE_SPECULATION 0 /* speculation */ +#define XCHAL_HAVE_FULL_RESET 0 /* all regs/state reset */ +#define XCHAL_NUM_CONTEXTS 1 /* */ +#define XCHAL_NUM_MISC_REGS 4 /* num of scratch regs (0..4) */ +#define XCHAL_HAVE_TAP_MASTER 0 /* JTAG TAP control instr's */ +#define XCHAL_HAVE_PRID 0 /* processor ID register */ +#define XCHAL_HAVE_THREADPTR 0 /* THREADPTR register */ +#define XCHAL_HAVE_BOOLEANS 1 /* boolean registers */ +#define XCHAL_HAVE_CP 1 /* CPENABLE reg (coprocessor) */ +#define XCHAL_CP_MAXCFG 8 /* max allowed cp id plus one */ +#define XCHAL_HAVE_MAC16 0 /* MAC16 package */ +#define XCHAL_HAVE_VECTORFPU2005 0 /* vector floating-point pkg */ +#define XCHAL_HAVE_FP 1 /* floating point pkg */ +#define XCHAL_HAVE_VECTRA1 0 /* Vectra I pkg */ +#define XCHAL_HAVE_VECTRALX 0 /* Vectra LX pkg */ +#define XCHAL_HAVE_HIFI2 0 /* HiFi2 Audio Engine pkg */ + + +/*---------------------------------------------------------------------- + MISC + ----------------------------------------------------------------------*/ + +#define XCHAL_NUM_WRITEBUFFER_ENTRIES 8 /* size of write buffer */ +#define XCHAL_INST_FETCH_WIDTH 8 /* instr-fetch width in bytes */ +#define XCHAL_DATA_WIDTH 16 /* data width in bytes */ +/* In T1050, applies to selected core load and store instructions (see ISA): */ +#define XCHAL_UNALIGNED_LOAD_EXCEPTION 1 /* unaligned loads cause exc. */ +#define XCHAL_UNALIGNED_STORE_EXCEPTION 1 /* unaligned stores cause exc.*/ + +#define XCHAL_SW_VERSION 701001 /* sw version of this header */ + +#define XCHAL_CORE_ID "stretch_bali" /* alphanum core name + (CoreID) set in the Xtensa + Processor Generator */ + +#define XCHAL_BUILD_UNIQUE_ID 0x000104B9 /* 22-bit sw build ID */ + +/* + * These definitions describe the hardware targeted by this software. + */ +#define XCHAL_HW_CONFIGID0 0xC2F3F9FE /* ConfigID hi 32 bits*/ +#define XCHAL_HW_CONFIGID1 0x054104B9 /* ConfigID lo 32 bits*/ +#define XCHAL_HW_VERSION_NAME "LX1.0.2" /* full version name */ +#define XCHAL_HW_VERSION_MAJOR 2100 /* major ver# of targeted hw */ +#define XCHAL_HW_VERSION_MINOR 2 /* minor ver# of targeted hw */ +#define XCHAL_HW_VERSION 210002 /* major*100+minor */ +#define XCHAL_HW_REL_LX1 1 +#define XCHAL_HW_REL_LX1_0 1 +#define XCHAL_HW_REL_LX1_0_2 1 +#define XCHAL_HW_CONFIGID_RELIABLE 1 +/* If software targets a *range* of hardware versions, these are the bounds: */ +#define XCHAL_HW_MIN_VERSION_MAJOR 2100 /* major v of earliest tgt hw */ +#define XCHAL_HW_MIN_VERSION_MINOR 2 /* minor v of earliest tgt hw */ +#define XCHAL_HW_MIN_VERSION 210002 /* earliest targeted hw */ +#define XCHAL_HW_MAX_VERSION_MAJOR 2100 /* major v of latest tgt hw */ +#define XCHAL_HW_MAX_VERSION_MINOR 2 /* minor v of latest tgt hw */ +#define XCHAL_HW_MAX_VERSION 210002 /* latest targeted hw */ + + +/*---------------------------------------------------------------------- + CACHE + ----------------------------------------------------------------------*/ + +#define XCHAL_ICACHE_LINESIZE 16 /* I-cache line size in bytes */ +#define XCHAL_DCACHE_LINESIZE 16 /* D-cache line size in bytes */ +#define XCHAL_ICACHE_LINEWIDTH 4 /* log2(I line size in bytes) */ +#define XCHAL_DCACHE_LINEWIDTH 4 /* log2(D line size in bytes) */ + +#define XCHAL_ICACHE_SIZE 32768 /* I-cache size in bytes or 0 */ +#define XCHAL_DCACHE_SIZE 32768 /* D-cache size in bytes or 0 */ + +#define XCHAL_DCACHE_IS_WRITEBACK 1 /* writeback feature */ + + + + +/**************************************************************************** + Parameters Useful for PRIVILEGED (Supervisory or Non-Virtualized) Code + ****************************************************************************/ + + +#ifndef XTENSA_HAL_NON_PRIVILEGED_ONLY + +/*---------------------------------------------------------------------- + CACHE + ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_PIF 1 /* any outbound PIF present */ + +/* If present, cache size in bytes == (ways * 2^(linewidth + setwidth)). */ + +/* Number of cache sets in log2(lines per way): */ +#define XCHAL_ICACHE_SETWIDTH 9 +#define XCHAL_DCACHE_SETWIDTH 10 + +/* Cache set associativity (number of ways): */ +#define XCHAL_ICACHE_WAYS 4 +#define XCHAL_DCACHE_WAYS 2 + +/* Cache features: */ +#define XCHAL_ICACHE_LINE_LOCKABLE 1 +#define XCHAL_DCACHE_LINE_LOCKABLE 0 +#define XCHAL_ICACHE_ECC_PARITY 0 +#define XCHAL_DCACHE_ECC_PARITY 0 + +/* Number of encoded cache attr bits (see <xtensa/hal.h> for decoded bits): */ +#define XCHAL_CA_BITS 4 + + +/*---------------------------------------------------------------------- + INTERNAL I/D RAM/ROMs and XLMI + ----------------------------------------------------------------------*/ + +#define XCHAL_NUM_INSTROM 0 /* number of core instr. ROMs */ +#define XCHAL_NUM_INSTRAM 0 /* number of core instr. RAMs */ +#define XCHAL_NUM_DATAROM 0 /* number of core data ROMs */ +#define XCHAL_NUM_DATARAM 1 /* number of core data RAMs */ +#define XCHAL_NUM_URAM 0 /* number of core unified RAMs*/ +#define XCHAL_NUM_XLMI 1 /* number of core XLMI ports */ + +/* Data RAM 0: */ +#define XCHAL_DATARAM0_VADDR 0x3FFF0000 +#define XCHAL_DATARAM0_PADDR 0x3FFF0000 +#define XCHAL_DATARAM0_SIZE 65536 +#define XCHAL_DATARAM0_ECC_PARITY 0 + +/* XLMI Port 0: */ +#define XCHAL_XLMI0_VADDR 0x37F80000 +#define XCHAL_XLMI0_PADDR 0x37F80000 +#define XCHAL_XLMI0_SIZE 262144 +#define XCHAL_XLMI0_ECC_PARITY 0 + + +/*---------------------------------------------------------------------- + INTERRUPTS and TIMERS + ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_INTERRUPTS 1 /* interrupt option */ +#define XCHAL_HAVE_HIGHPRI_INTERRUPTS 1 /* med/high-pri. interrupts */ +#define XCHAL_HAVE_NMI 1 /* non-maskable interrupt */ +#define XCHAL_HAVE_CCOUNT 1 /* CCOUNT reg. (timer option) */ +#define XCHAL_NUM_TIMERS 3 /* number of CCOMPAREn regs */ +#define XCHAL_NUM_INTERRUPTS 27 /* number of interrupts */ +#define XCHAL_NUM_INTERRUPTS_LOG2 5 /* ceil(log2(NUM_INTERRUPTS)) */ +#define XCHAL_NUM_EXTINTERRUPTS 20 /* num of external interrupts */ +#define XCHAL_NUM_INTLEVELS 4 /* number of interrupt levels + (not including level zero) */ +#define XCHAL_EXCM_LEVEL 1 /* level masked by PS.EXCM */ + /* (always 1 in XEA1; levels 2 .. EXCM_LEVEL are "medium priority") */ + +/* Masks of interrupts at each interrupt level: */ +#define XCHAL_INTLEVEL1_MASK 0x01F07FFF +#define XCHAL_INTLEVEL2_MASK 0x02018000 +#define XCHAL_INTLEVEL3_MASK 0x04060000 +#define XCHAL_INTLEVEL4_MASK 0x00000000 +#define XCHAL_INTLEVEL5_MASK 0x00080000 +#define XCHAL_INTLEVEL6_MASK 0x00000000 +#define XCHAL_INTLEVEL7_MASK 0x00000000 + +/* Masks of interrupts at each range 1..n of interrupt levels: */ +#define XCHAL_INTLEVEL1_ANDBELOW_MASK 0x01F07FFF +#define XCHAL_INTLEVEL2_ANDBELOW_MASK 0x03F1FFFF +#define XCHAL_INTLEVEL3_ANDBELOW_MASK 0x07F7FFFF +#define XCHAL_INTLEVEL4_ANDBELOW_MASK 0x07F7FFFF +#define XCHAL_INTLEVEL5_ANDBELOW_MASK 0x07FFFFFF +#define XCHAL_INTLEVEL6_ANDBELOW_MASK 0x07FFFFFF +#define XCHAL_INTLEVEL7_ANDBELOW_MASK 0x07FFFFFF + +/* Level of each interrupt: */ +#define XCHAL_INT0_LEVEL 1 +#define XCHAL_INT1_LEVEL 1 +#define XCHAL_INT2_LEVEL 1 +#define XCHAL_INT3_LEVEL 1 +#define XCHAL_INT4_LEVEL 1 +#define XCHAL_INT5_LEVEL 1 +#define XCHAL_INT6_LEVEL 1 +#define XCHAL_INT7_LEVEL 1 +#define XCHAL_INT8_LEVEL 1 +#define XCHAL_INT9_LEVEL 1 +#define XCHAL_INT10_LEVEL 1 +#define XCHAL_INT11_LEVEL 1 +#define XCHAL_INT12_LEVEL 1 +#define XCHAL_INT13_LEVEL 1 +#define XCHAL_INT14_LEVEL 1 +#define XCHAL_INT15_LEVEL 2 +#define XCHAL_INT16_LEVEL 2 +#define XCHAL_INT17_LEVEL 3 +#define XCHAL_INT18_LEVEL 3 +#define XCHAL_INT19_LEVEL 5 +#define XCHAL_INT20_LEVEL 1 +#define XCHAL_INT21_LEVEL 1 +#define XCHAL_INT22_LEVEL 1 +#define XCHAL_INT23_LEVEL 1 +#define XCHAL_INT24_LEVEL 1 +#define XCHAL_INT25_LEVEL 2 +#define XCHAL_INT26_LEVEL 3 +#define XCHAL_DEBUGLEVEL 4 /* debug interrupt level */ +#define XCHAL_HAVE_DEBUG_EXTERN_INT 1 /* OCD external db interrupt */ +#define XCHAL_NMILEVEL 5 /* NMI "level" (for use with + EXCSAVE/EPS/EPC_n, RFI n) */ + +/* Type of each interrupt: */ +#define XCHAL_INT0_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT1_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT2_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT3_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT4_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT5_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT6_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT7_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT8_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT9_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT10_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT11_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT12_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT13_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT14_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT15_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT16_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT17_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT18_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT19_TYPE XTHAL_INTTYPE_NMI +#define XCHAL_INT20_TYPE XTHAL_INTTYPE_SOFTWARE +#define XCHAL_INT21_TYPE XTHAL_INTTYPE_SOFTWARE +#define XCHAL_INT22_TYPE XTHAL_INTTYPE_SOFTWARE +#define XCHAL_INT23_TYPE XTHAL_INTTYPE_SOFTWARE +#define XCHAL_INT24_TYPE XTHAL_INTTYPE_TIMER +#define XCHAL_INT25_TYPE XTHAL_INTTYPE_TIMER +#define XCHAL_INT26_TYPE XTHAL_INTTYPE_TIMER + +/* Masks of interrupts for each type of interrupt: */ +#define XCHAL_INTTYPE_MASK_UNCONFIGURED 0xF8000000 +#define XCHAL_INTTYPE_MASK_SOFTWARE 0x00F00000 +#define XCHAL_INTTYPE_MASK_EXTERN_EDGE 0x00000000 +#define XCHAL_INTTYPE_MASK_EXTERN_LEVEL 0x0007FFFF +#define XCHAL_INTTYPE_MASK_TIMER 0x07000000 +#define XCHAL_INTTYPE_MASK_NMI 0x00080000 +#define XCHAL_INTTYPE_MASK_WRITE_ERROR 0x00000000 + +/* Interrupt numbers assigned to specific interrupt sources: */ +#define XCHAL_TIMER0_INTERRUPT 24 /* CCOMPARE0 */ +#define XCHAL_TIMER1_INTERRUPT 25 /* CCOMPARE1 */ +#define XCHAL_TIMER2_INTERRUPT 26 /* CCOMPARE2 */ +#define XCHAL_TIMER3_INTERRUPT XTHAL_TIMER_UNCONFIGURED +#define XCHAL_NMI_INTERRUPT 19 /* non-maskable interrupt */ + +/* Interrupt numbers for levels at which only one interrupt is configured: */ +#define XCHAL_INTLEVEL5_NUM 19 +/* (There are many interrupts each at level(s) 1, 2, 3.) */ + + +/* + * External interrupt vectors/levels. + * These macros describe how Xtensa processor interrupt numbers + * (as numbered internally, eg. in INTERRUPT and INTENABLE registers) + * map to external BInterrupt<n> pins, for those interrupts + * configured as external (level-triggered, edge-triggered, or NMI). + * See the Xtensa processor databook for more details. + */ + +/* Core interrupt numbers mapped to each EXTERNAL interrupt number: */ +#define XCHAL_EXTINT0_NUM 0 /* (intlevel 1) */ +#define XCHAL_EXTINT1_NUM 1 /* (intlevel 1) */ +#define XCHAL_EXTINT2_NUM 2 /* (intlevel 1) */ +#define XCHAL_EXTINT3_NUM 3 /* (intlevel 1) */ +#define XCHAL_EXTINT4_NUM 4 /* (intlevel 1) */ +#define XCHAL_EXTINT5_NUM 5 /* (intlevel 1) */ +#define XCHAL_EXTINT6_NUM 6 /* (intlevel 1) */ +#define XCHAL_EXTINT7_NUM 7 /* (intlevel 1) */ +#define XCHAL_EXTINT8_NUM 8 /* (intlevel 1) */ +#define XCHAL_EXTINT9_NUM 9 /* (intlevel 1) */ +#define XCHAL_EXTINT10_NUM 10 /* (intlevel 1) */ +#define XCHAL_EXTINT11_NUM 11 /* (intlevel 1) */ +#define XCHAL_EXTINT12_NUM 12 /* (intlevel 1) */ +#define XCHAL_EXTINT13_NUM 13 /* (intlevel 1) */ +#define XCHAL_EXTINT14_NUM 14 /* (intlevel 1) */ +#define XCHAL_EXTINT15_NUM 15 /* (intlevel 2) */ +#define XCHAL_EXTINT16_NUM 16 /* (intlevel 2) */ +#define XCHAL_EXTINT17_NUM 17 /* (intlevel 3) */ +#define XCHAL_EXTINT18_NUM 18 /* (intlevel 3) */ +#define XCHAL_EXTINT19_NUM 19 /* (intlevel 5) */ + + +/*---------------------------------------------------------------------- + EXCEPTIONS and VECTORS + ----------------------------------------------------------------------*/ + +#define XCHAL_XEA_VERSION 2 /* Xtensa Exception Architecture + number: 1 == XEA1 (old) + 2 == XEA2 (new) + 0 == XEAX (extern) */ +#define XCHAL_HAVE_XEA1 0 /* Exception Architecture 1 */ +#define XCHAL_HAVE_XEA2 1 /* Exception Architecture 2 */ +#define XCHAL_HAVE_XEAX 0 /* External Exception Arch. */ +#define XCHAL_HAVE_EXCEPTIONS 1 /* exception option */ +#define XCHAL_HAVE_MEM_ECC_PARITY 0 /* local memory ECC/parity */ +#define XCHAL_HAVE_VECTOR_SELECT 0 /* relocatable vectors */ +#define XCHAL_HAVE_VECBASE 0 /* relocatable vectors */ + +#define XCHAL_RESET_VECOFS 0x00000000 +#define XCHAL_RESET_VECTOR_VADDR 0x3FFE03D0 +#define XCHAL_RESET_VECTOR_PADDR 0x3FFE03D0 +#define XCHAL_USER_VECOFS 0x00000000 +#define XCHAL_USER_VECTOR_VADDR 0x40000220 +#define XCHAL_USER_VECTOR_PADDR 0x40000220 +#define XCHAL_KERNEL_VECOFS 0x00000000 +#define XCHAL_KERNEL_VECTOR_VADDR 0x40000200 +#define XCHAL_KERNEL_VECTOR_PADDR 0x40000200 +#define XCHAL_DOUBLEEXC_VECOFS 0x00000000 +#define XCHAL_DOUBLEEXC_VECTOR_VADDR 0x400002A0 +#define XCHAL_DOUBLEEXC_VECTOR_PADDR 0x400002A0 +#define XCHAL_WINDOW_OF4_VECOFS 0x00000000 +#define XCHAL_WINDOW_UF4_VECOFS 0x00000040 +#define XCHAL_WINDOW_OF8_VECOFS 0x00000080 +#define XCHAL_WINDOW_UF8_VECOFS 0x000000C0 +#define XCHAL_WINDOW_OF12_VECOFS 0x00000100 +#define XCHAL_WINDOW_UF12_VECOFS 0x00000140 +#define XCHAL_WINDOW_VECTORS_VADDR 0x40000000 +#define XCHAL_WINDOW_VECTORS_PADDR 0x40000000 +#define XCHAL_INTLEVEL2_VECOFS 0x00000000 +#define XCHAL_INTLEVEL2_VECTOR_VADDR 0x40000240 +#define XCHAL_INTLEVEL2_VECTOR_PADDR 0x40000240 +#define XCHAL_INTLEVEL3_VECOFS 0x00000000 +#define XCHAL_INTLEVEL3_VECTOR_VADDR 0x40000260 +#define XCHAL_INTLEVEL3_VECTOR_PADDR 0x40000260 +#define XCHAL_INTLEVEL4_VECOFS 0x00000000 +#define XCHAL_INTLEVEL4_VECTOR_VADDR 0x40000390 +#define XCHAL_INTLEVEL4_VECTOR_PADDR 0x40000390 +#define XCHAL_DEBUG_VECOFS XCHAL_INTLEVEL4_VECOFS +#define XCHAL_DEBUG_VECTOR_VADDR XCHAL_INTLEVEL4_VECTOR_VADDR +#define XCHAL_DEBUG_VECTOR_PADDR XCHAL_INTLEVEL4_VECTOR_PADDR +#define XCHAL_NMI_VECOFS 0x00000000 +#define XCHAL_NMI_VECTOR_VADDR 0x400003B0 +#define XCHAL_NMI_VECTOR_PADDR 0x400003B0 +#define XCHAL_INTLEVEL5_VECOFS XCHAL_NMI_VECOFS +#define XCHAL_INTLEVEL5_VECTOR_VADDR XCHAL_NMI_VECTOR_VADDR +#define XCHAL_INTLEVEL5_VECTOR_PADDR XCHAL_NMI_VECTOR_PADDR + + +/*---------------------------------------------------------------------- + DEBUG + ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_OCD 1 /* OnChipDebug option */ +#define XCHAL_NUM_IBREAK 2 /* number of IBREAKn regs */ +#define XCHAL_NUM_DBREAK 2 /* number of DBREAKn regs */ +#define XCHAL_HAVE_OCD_DIR_ARRAY 1 /* faster OCD option */ + + +/*---------------------------------------------------------------------- + MMU + ----------------------------------------------------------------------*/ + +/* See core-matmap.h header file for more details. */ + +#define XCHAL_HAVE_TLBS 1 /* inverse of HAVE_CACHEATTR */ +#define XCHAL_HAVE_SPANNING_WAY 1 /* one way maps I+D 4GB vaddr */ +#define XCHAL_HAVE_IDENTITY_MAP 1 /* vaddr == paddr always */ +#define XCHAL_HAVE_CACHEATTR 0 /* CACHEATTR register present */ +#define XCHAL_HAVE_MIMIC_CACHEATTR 1 /* region protection */ +#define XCHAL_HAVE_XLT_CACHEATTR 0 /* region prot. w/translation */ +#define XCHAL_HAVE_PTP_MMU 0 /* full MMU (with page table + [autorefill] and protection) + usable for an MMU-based OS */ +/* If none of the above last 4 are set, it's a custom TLB configuration. */ + +#define XCHAL_MMU_ASID_BITS 0 /* number of bits in ASIDs */ +#define XCHAL_MMU_RINGS 1 /* number of rings (1..4) */ +#define XCHAL_MMU_RING_BITS 0 /* num of bits in RING field */ + +#endif /* !XTENSA_HAL_NON_PRIVILEGED_ONLY */ + + +#endif /* _XTENSA_CORE_CONFIGURATION_H */ + diff --git a/arch/xtensa/variants/s6000/include/variant/dmac.h b/arch/xtensa/variants/s6000/include/variant/dmac.h new file mode 100644 index 00000000..e81735b2 --- /dev/null +++ b/arch/xtensa/variants/s6000/include/variant/dmac.h @@ -0,0 +1,387 @@ +/* + * include/asm-xtensa/variant-s6000/dmac.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2006 Tensilica Inc. + * Copyright (C) 2008 Emlix GmbH <info@emlix.com> + * Authors: Fabian Godehardt <fg@emlix.com> + * Oskar Schirmer <os@emlix.com> + * Daniel Gloeckner <dg@emlix.com> + */ + +#ifndef __ASM_XTENSA_S6000_DMAC_H +#define __ASM_XTENSA_S6000_DMAC_H +#include <linux/io.h> +#include <variant/hardware.h> + +/* DMA global */ + +#define S6_DMA_INTSTAT0 0x000 +#define S6_DMA_INTSTAT1 0x004 +#define S6_DMA_INTENABLE0 0x008 +#define S6_DMA_INTENABLE1 0x00C +#define S6_DMA_INTRAW0 0x010 +#define S6_DMA_INTRAW1 0x014 +#define S6_DMA_INTCLEAR0 0x018 +#define S6_DMA_INTCLEAR1 0x01C +#define S6_DMA_INTSET0 0x020 +#define S6_DMA_INTSET1 0x024 +#define S6_DMA_INT0_UNDER 0 +#define S6_DMA_INT0_OVER 16 +#define S6_DMA_INT1_CHANNEL 0 +#define S6_DMA_INT1_MASTER 16 +#define S6_DMA_INT1_MASTER_MASK 7 +#define S6_DMA_TERMCNTIRQSTAT 0x028 +#define S6_DMA_TERMCNTIRQCLR 0x02C +#define S6_DMA_TERMCNTIRQSET 0x030 +#define S6_DMA_PENDCNTIRQSTAT 0x034 +#define S6_DMA_PENDCNTIRQCLR 0x038 +#define S6_DMA_PENDCNTIRQSET 0x03C +#define S6_DMA_LOWWMRKIRQSTAT 0x040 +#define S6_DMA_LOWWMRKIRQCLR 0x044 +#define S6_DMA_LOWWMRKIRQSET 0x048 +#define S6_DMA_MASTERERRINFO 0x04C +#define S6_DMA_MASTERERR_CHAN(n) (4*(n)) +#define S6_DMA_MASTERERR_CHAN_MASK 0xF +#define S6_DMA_DESCRFIFO0 0x050 +#define S6_DMA_DESCRFIFO1 0x054 +#define S6_DMA_DESCRFIFO2 0x058 +#define S6_DMA_DESCRFIFO2_AUTODISABLE 24 +#define S6_DMA_DESCRFIFO3 0x05C +#define S6_DMA_MASTER0START 0x060 +#define S6_DMA_MASTER0END 0x064 +#define S6_DMA_MASTER1START 0x068 +#define S6_DMA_MASTER1END 0x06C +#define S6_DMA_NEXTFREE 0x070 +#define S6_DMA_NEXTFREE_CHAN 0 +#define S6_DMA_NEXTFREE_CHAN_MASK 0x1F +#define S6_DMA_NEXTFREE_ENA 16 +#define S6_DMA_NEXTFREE_ENA_MASK ((1 << 16) - 1) +#define S6_DMA_DPORTCTRLGRP(p) ((p) * 4 + 0x074) +#define S6_DMA_DPORTCTRLGRP_FRAMEREP 0 +#define S6_DMA_DPORTCTRLGRP_NRCHANS 1 +#define S6_DMA_DPORTCTRLGRP_NRCHANS_1 0 +#define S6_DMA_DPORTCTRLGRP_NRCHANS_3 1 +#define S6_DMA_DPORTCTRLGRP_NRCHANS_4 2 +#define S6_DMA_DPORTCTRLGRP_NRCHANS_2 3 +#define S6_DMA_DPORTCTRLGRP_ENA 31 + + +/* DMA per channel */ + +#define DMA_CHNL(dmac, n) ((dmac) + 0x1000 + (n) * 0x100) +#define DMA_INDEX_CHNL(addr) (((addr) >> 8) & 0xF) +#define DMA_MASK_DMAC(addr) ((addr) & 0xFFFF0000) +#define S6_DMA_CHNCTRL 0x000 +#define S6_DMA_CHNCTRL_ENABLE 0 +#define S6_DMA_CHNCTRL_PAUSE 1 +#define S6_DMA_CHNCTRL_PRIO 2 +#define S6_DMA_CHNCTRL_PRIO_MASK 3 +#define S6_DMA_CHNCTRL_PERIPHXFER 4 +#define S6_DMA_CHNCTRL_PERIPHENA 5 +#define S6_DMA_CHNCTRL_SRCINC 6 +#define S6_DMA_CHNCTRL_DSTINC 7 +#define S6_DMA_CHNCTRL_BURSTLOG 8 +#define S6_DMA_CHNCTRL_BURSTLOG_MASK 7 +#define S6_DMA_CHNCTRL_DESCFIFODEPTH 12 +#define S6_DMA_CHNCTRL_DESCFIFODEPTH_MASK 0x1F +#define S6_DMA_CHNCTRL_DESCFIFOFULL 17 +#define S6_DMA_CHNCTRL_BWCONSEL 18 +#define S6_DMA_CHNCTRL_BWCONENA 19 +#define S6_DMA_CHNCTRL_PENDGCNTSTAT 20 +#define S6_DMA_CHNCTRL_PENDGCNTSTAT_MASK 0x3F +#define S6_DMA_CHNCTRL_LOWWMARK 26 +#define S6_DMA_CHNCTRL_LOWWMARK_MASK 0xF +#define S6_DMA_CHNCTRL_TSTAMP 30 +#define S6_DMA_TERMCNTNB 0x004 +#define S6_DMA_TERMCNTNB_MASK 0xFFFF +#define S6_DMA_TERMCNTTMO 0x008 +#define S6_DMA_TERMCNTSTAT 0x00C +#define S6_DMA_TERMCNTSTAT_MASK 0xFF +#define S6_DMA_CMONCHUNK 0x010 +#define S6_DMA_SRCSKIP 0x014 +#define S6_DMA_DSTSKIP 0x018 +#define S6_DMA_CUR_SRC 0x024 +#define S6_DMA_CUR_DST 0x028 +#define S6_DMA_TIMESTAMP 0x030 + +/* DMA channel lists */ + +#define S6_DPDMA_CHAN(stream, channel) (4 * (stream) + (channel)) +#define S6_DPDMA_NB 16 + +#define S6_HIFDMA_GMACTX 0 +#define S6_HIFDMA_GMACRX 1 +#define S6_HIFDMA_I2S0 2 +#define S6_HIFDMA_I2S1 3 +#define S6_HIFDMA_EGIB 4 +#define S6_HIFDMA_PCITX 5 +#define S6_HIFDMA_PCIRX 6 +#define S6_HIFDMA_NB 7 + +#define S6_NIDMA_NB 4 + +#define S6_LMSDMA_NB 12 + +/* controller access */ + +#define S6_DMAC_NB 4 +#define S6_DMAC_INDEX(dmac) (((unsigned)(dmac) >> 18) % S6_DMAC_NB) + +struct s6dmac_ctrl { + u32 dmac; + spinlock_t lock; + u8 chan_nb; +}; + +extern struct s6dmac_ctrl s6dmac_ctrl[S6_DMAC_NB]; + + +/* DMA control, per channel */ + +static inline int s6dmac_fifo_full(u32 dmac, int chan) +{ + return (readl(DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL) + & (1 << S6_DMA_CHNCTRL_DESCFIFOFULL)) && 1; +} + +static inline int s6dmac_termcnt_irq(u32 dmac, int chan) +{ + u32 m = 1 << chan; + int r = (readl(dmac + S6_DMA_TERMCNTIRQSTAT) & m) && 1; + if (r) + writel(m, dmac + S6_DMA_TERMCNTIRQCLR); + return r; +} + +static inline int s6dmac_pendcnt_irq(u32 dmac, int chan) +{ + u32 m = 1 << chan; + int r = (readl(dmac + S6_DMA_PENDCNTIRQSTAT) & m) && 1; + if (r) + writel(m, dmac + S6_DMA_PENDCNTIRQCLR); + return r; +} + +static inline int s6dmac_lowwmark_irq(u32 dmac, int chan) +{ + int r = (readl(dmac + S6_DMA_LOWWMRKIRQSTAT) & (1 << chan)) ? 1 : 0; + if (r) + writel(1 << chan, dmac + S6_DMA_LOWWMRKIRQCLR); + return r; +} + +static inline u32 s6dmac_pending_count(u32 dmac, int chan) +{ + return (readl(DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL) + >> S6_DMA_CHNCTRL_PENDGCNTSTAT) + & S6_DMA_CHNCTRL_PENDGCNTSTAT_MASK; +} + +static inline void s6dmac_set_terminal_count(u32 dmac, int chan, u32 n) +{ + n &= S6_DMA_TERMCNTNB_MASK; + n |= readl(DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTNB) + & ~S6_DMA_TERMCNTNB_MASK; + writel(n, DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTNB); +} + +static inline u32 s6dmac_get_terminal_count(u32 dmac, int chan) +{ + return (readl(DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTNB)) + & S6_DMA_TERMCNTNB_MASK; +} + +static inline u32 s6dmac_timestamp(u32 dmac, int chan) +{ + return readl(DMA_CHNL(dmac, chan) + S6_DMA_TIMESTAMP); +} + +static inline u32 s6dmac_cur_src(u32 dmac, int chan) +{ + return readl(DMA_CHNL(dmac, chan) + S6_DMA_CUR_SRC); +} + +static inline u32 s6dmac_cur_dst(u32 dmac, int chan) +{ + return readl(DMA_CHNL(dmac, chan) + S6_DMA_CUR_DST); +} + +static inline void s6dmac_disable_chan(u32 dmac, int chan) +{ + u32 ctrl; + writel(readl(DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL) + & ~(1 << S6_DMA_CHNCTRL_ENABLE), + DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL); + do + ctrl = readl(DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL); + while (ctrl & (1 << S6_DMA_CHNCTRL_ENABLE)); +} + +static inline void s6dmac_set_stride_skip(u32 dmac, int chan, + int comchunk, /* 0: disable scatter/gather */ + int srcskip, int dstskip) +{ + writel(comchunk, DMA_CHNL(dmac, chan) + S6_DMA_CMONCHUNK); + writel(srcskip, DMA_CHNL(dmac, chan) + S6_DMA_SRCSKIP); + writel(dstskip, DMA_CHNL(dmac, chan) + S6_DMA_DSTSKIP); +} + +static inline void s6dmac_enable_chan(u32 dmac, int chan, + int prio, /* 0 (highest) .. 3 (lowest) */ + int periphxfer, /* <0: disable p.req.line, 0..1: mode */ + int srcinc, int dstinc, /* 0: dont increment src/dst address */ + int comchunk, /* 0: disable scatter/gather */ + int srcskip, int dstskip, + int burstsize, /* 4 for I2S, 7 for everything else */ + int bandwidthconserve, /* <0: disable, 0..1: select */ + int lowwmark, /* 0..15 */ + int timestamp, /* 0: disable timestamp */ + int enable) /* 0: disable for now */ +{ + writel(1, DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTNB); + writel(0, DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTTMO); + writel(lowwmark << S6_DMA_CHNCTRL_LOWWMARK, + DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL); + s6dmac_set_stride_skip(dmac, chan, comchunk, srcskip, dstskip); + writel(((enable ? 1 : 0) << S6_DMA_CHNCTRL_ENABLE) | + (prio << S6_DMA_CHNCTRL_PRIO) | + (((periphxfer > 0) ? 1 : 0) << S6_DMA_CHNCTRL_PERIPHXFER) | + (((periphxfer < 0) ? 0 : 1) << S6_DMA_CHNCTRL_PERIPHENA) | + ((srcinc ? 1 : 0) << S6_DMA_CHNCTRL_SRCINC) | + ((dstinc ? 1 : 0) << S6_DMA_CHNCTRL_DSTINC) | + (burstsize << S6_DMA_CHNCTRL_BURSTLOG) | + (((bandwidthconserve > 0) ? 1 : 0) << S6_DMA_CHNCTRL_BWCONSEL) | + (((bandwidthconserve < 0) ? 0 : 1) << S6_DMA_CHNCTRL_BWCONENA) | + (lowwmark << S6_DMA_CHNCTRL_LOWWMARK) | + ((timestamp ? 1 : 0) << S6_DMA_CHNCTRL_TSTAMP), + DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL); +} + + +/* DMA control, per engine */ + +static inline unsigned _dmac_addr_index(u32 dmac) +{ + unsigned i = S6_DMAC_INDEX(dmac); + if (s6dmac_ctrl[i].dmac != dmac) + BUG(); + return i; +} + +static inline void _s6dmac_disable_error_irqs(u32 dmac, u32 mask) +{ + writel(mask, dmac + S6_DMA_TERMCNTIRQCLR); + writel(mask, dmac + S6_DMA_PENDCNTIRQCLR); + writel(mask, dmac + S6_DMA_LOWWMRKIRQCLR); + writel(readl(dmac + S6_DMA_INTENABLE0) + & ~((mask << S6_DMA_INT0_UNDER) | (mask << S6_DMA_INT0_OVER)), + dmac + S6_DMA_INTENABLE0); + writel(readl(dmac + S6_DMA_INTENABLE1) & ~(mask << S6_DMA_INT1_CHANNEL), + dmac + S6_DMA_INTENABLE1); + writel((mask << S6_DMA_INT0_UNDER) | (mask << S6_DMA_INT0_OVER), + dmac + S6_DMA_INTCLEAR0); + writel(mask << S6_DMA_INT1_CHANNEL, dmac + S6_DMA_INTCLEAR1); +} + +/* + * request channel from specified engine + * with chan<0, accept any channel + * further parameters see s6dmac_enable_chan + * returns < 0 upon error, channel nb otherwise + */ +static inline int s6dmac_request_chan(u32 dmac, int chan, + int prio, + int periphxfer, + int srcinc, int dstinc, + int comchunk, + int srcskip, int dstskip, + int burstsize, + int bandwidthconserve, + int lowwmark, + int timestamp, + int enable) +{ + int r = chan; + unsigned long flags; + spinlock_t *spinl = &s6dmac_ctrl[_dmac_addr_index(dmac)].lock; + spin_lock_irqsave(spinl, flags); + if (r < 0) { + r = (readl(dmac + S6_DMA_NEXTFREE) >> S6_DMA_NEXTFREE_CHAN) + & S6_DMA_NEXTFREE_CHAN_MASK; + } + if (r >= s6dmac_ctrl[_dmac_addr_index(dmac)].chan_nb) { + if (chan < 0) + r = -EBUSY; + else + r = -ENXIO; + } else if (((readl(dmac + S6_DMA_NEXTFREE) >> S6_DMA_NEXTFREE_ENA) + >> r) & 1) { + r = -EBUSY; + } else { + s6dmac_enable_chan(dmac, r, prio, periphxfer, + srcinc, dstinc, comchunk, srcskip, dstskip, burstsize, + bandwidthconserve, lowwmark, timestamp, enable); + } + spin_unlock_irqrestore(spinl, flags); + return r; +} + +static inline void s6dmac_put_fifo(u32 dmac, int chan, + u32 src, u32 dst, u32 size) +{ + unsigned long flags; + spinlock_t *spinl = &s6dmac_ctrl[_dmac_addr_index(dmac)].lock; + spin_lock_irqsave(spinl, flags); + writel(src, dmac + S6_DMA_DESCRFIFO0); + writel(dst, dmac + S6_DMA_DESCRFIFO1); + writel(size, dmac + S6_DMA_DESCRFIFO2); + writel(chan, dmac + S6_DMA_DESCRFIFO3); + spin_unlock_irqrestore(spinl, flags); +} + +static inline u32 s6dmac_channel_enabled(u32 dmac, int chan) +{ + return readl(DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL) & + (1 << S6_DMA_CHNCTRL_ENABLE); +} + +/* + * group 1-4 data port channels + * with port=0..3, nrch=1-4 channels, + * frrep=0/1 (dis- or enable frame repeat) + */ +static inline void s6dmac_dp_setup_group(u32 dmac, int port, + int nrch, int frrep) +{ + static const u8 mask[4] = {0, 3, 1, 2}; + BUG_ON(dmac != S6_REG_DPDMA); + if ((port < 0) || (port > 3) || (nrch < 1) || (nrch > 4)) + return; + writel((mask[nrch - 1] << S6_DMA_DPORTCTRLGRP_NRCHANS) + | ((frrep ? 1 : 0) << S6_DMA_DPORTCTRLGRP_FRAMEREP), + dmac + S6_DMA_DPORTCTRLGRP(port)); +} + +static inline void s6dmac_dp_switch_group(u32 dmac, int port, int enable) +{ + u32 tmp; + BUG_ON(dmac != S6_REG_DPDMA); + tmp = readl(dmac + S6_DMA_DPORTCTRLGRP(port)); + if (enable) + tmp |= (1 << S6_DMA_DPORTCTRLGRP_ENA); + else + tmp &= ~(1 << S6_DMA_DPORTCTRLGRP_ENA); + writel(tmp, dmac + S6_DMA_DPORTCTRLGRP(port)); +} + +extern void s6dmac_put_fifo_cache(u32 dmac, int chan, + u32 src, u32 dst, u32 size); +extern void s6dmac_disable_error_irqs(u32 dmac, u32 mask); +extern u32 s6dmac_int_sources(u32 dmac, u32 channel); +extern void s6dmac_release_chan(u32 dmac, int chan); + +#endif /* __ASM_XTENSA_S6000_DMAC_H */ diff --git a/arch/xtensa/variants/s6000/include/variant/gpio.h b/arch/xtensa/variants/s6000/include/variant/gpio.h new file mode 100644 index 00000000..8484ab0d --- /dev/null +++ b/arch/xtensa/variants/s6000/include/variant/gpio.h @@ -0,0 +1,6 @@ +#ifndef _XTENSA_VARIANT_S6000_GPIO_H +#define _XTENSA_VARIANT_S6000_GPIO_H + +extern int s6_gpio_init(u32 afsel); + +#endif /* _XTENSA_VARIANT_S6000_GPIO_H */ diff --git a/arch/xtensa/variants/s6000/include/variant/hardware.h b/arch/xtensa/variants/s6000/include/variant/hardware.h new file mode 100644 index 00000000..5d9ba098 --- /dev/null +++ b/arch/xtensa/variants/s6000/include/variant/hardware.h @@ -0,0 +1,259 @@ +#ifndef __XTENSA_S6000_HARDWARE_H +#define __XTENSA_S6000_HARDWARE_H + +#define S6_SCLK 1843200 + +#define S6_MEM_REG 0x20000000 +#define S6_MEM_EFI 0x33F00000 +#define S6_MEM_PCIE_DATARAM1 0x34000000 +#define S6_MEM_XLMI 0x37F80000 +#define S6_MEM_PIF_DATARAM1 0x37FFC000 +#define S6_MEM_GMAC 0x38000000 +#define S6_MEM_I2S 0x3A000000 +#define S6_MEM_EGIB 0x3C000000 +#define S6_MEM_PCIE_CFG 0x3E000000 +#define S6_MEM_PIF_DATARAM 0x3FFE0000 +#define S6_MEM_XLMI_DATARAM 0x3FFF0000 +#define S6_MEM_DDR 0x40000000 +#define S6_MEM_PCIE_APER 0xC0000000 +#define S6_MEM_AUX 0xF0000000 + +/* Device addresses */ + +#define S6_REG_SCB S6_MEM_REG +#define S6_REG_NB (S6_REG_SCB + 0x10000) +#define S6_REG_LMSDMA (S6_REG_SCB + 0x20000) +#define S6_REG_NI (S6_REG_SCB + 0x30000) +#define S6_REG_NIDMA (S6_REG_SCB + 0x40000) +#define S6_REG_NS (S6_REG_SCB + 0x50000) +#define S6_REG_DDR (S6_REG_SCB + 0x60000) +#define S6_REG_GREG1 (S6_REG_SCB + 0x70000) +#define S6_REG_DP (S6_REG_SCB + 0x80000) +#define S6_REG_DPDMA (S6_REG_SCB + 0x90000) +#define S6_REG_EGIB (S6_REG_SCB + 0xA0000) +#define S6_REG_PCIE (S6_REG_SCB + 0xB0000) +#define S6_REG_I2S (S6_REG_SCB + 0xC0000) +#define S6_REG_GMAC (S6_REG_SCB + 0xD0000) +#define S6_REG_HIFDMA (S6_REG_SCB + 0xE0000) +#define S6_REG_GREG2 (S6_REG_SCB + 0xF0000) + +#define S6_REG_APB S6_REG_SCB +#define S6_REG_UART (S6_REG_APB + 0x0000) +#define S6_REG_INTC (S6_REG_APB + 0x2000) +#define S6_REG_SPI (S6_REG_APB + 0x3000) +#define S6_REG_I2C (S6_REG_APB + 0x4000) +#define S6_REG_GPIO (S6_REG_APB + 0x8000) + +/* Global register block */ + +#define S6_GREG1_PLL_LOCKCLEAR 0x000 +#define S6_GREG1_PLL_LOCK_SYS 0 +#define S6_GREG1_PLL_LOCK_IO 1 +#define S6_GREG1_PLL_LOCK_AIM 2 +#define S6_GREG1_PLL_LOCK_DP0 3 +#define S6_GREG1_PLL_LOCK_DP2 4 +#define S6_GREG1_PLL_LOCK_DDR 5 +#define S6_GREG1_PLL_LOCKSTAT 0x004 +#define S6_GREG1_PLL_LOCKSTAT_CURLOCK 0 +#define S6_GREG1_PLL_LOCKSTAT_EVERUNLCK 8 +#define S6_GREG1_PLLSEL 0x010 +#define S6_GREG1_PLLSEL_AIM 0 +#define S6_GREG1_PLLSEL_AIM_DDR2 0 +#define S6_GREG1_PLLSEL_AIM_300MHZ 1 +#define S6_GREG1_PLLSEL_AIM_240MHZ 2 +#define S6_GREG1_PLLSEL_AIM_200MHZ 3 +#define S6_GREG1_PLLSEL_AIM_150MHZ 4 +#define S6_GREG1_PLLSEL_AIM_120MHZ 5 +#define S6_GREG1_PLLSEL_AIM_40MHZ 6 +#define S6_GREG1_PLLSEL_AIM_PLLAIMREF 7 +#define S6_GREG1_PLLSEL_AIM_MASK 7 +#define S6_GREG1_PLLSEL_DDR 8 +#define S6_GREG1_PLLSEL_DDR_HS 0 +#define S6_GREG1_PLLSEL_DDR_333MHZ 1 +#define S6_GREG1_PLLSEL_DDR_250MHZ 2 +#define S6_GREG1_PLLSEL_DDR_200MHZ 3 +#define S6_GREG1_PLLSEL_DDR_167MHZ 4 +#define S6_GREG1_PLLSEL_DDR_100MHZ 5 +#define S6_GREG1_PLLSEL_DDR_33MHZ 6 +#define S6_GREG1_PLLSEL_DDR_PLLIOREF 7 +#define S6_GREG1_PLLSEL_DDR_MASK 7 +#define S6_GREG1_PLLSEL_GMAC 16 +#define S6_GREG1_PLLSEL_GMAC_125MHZ 0 +#define S6_GREG1_PLLSEL_GMAC_25MHZ 1 +#define S6_GREG1_PLLSEL_GMAC_2500KHZ 2 +#define S6_GREG1_PLLSEL_GMAC_EXTERN 3 +#define S6_GREG1_PLLSEL_GMAC_MASK 3 +#define S6_GREG1_PLLSEL_GMII 18 +#define S6_GREG1_PLLSEL_GMII_111MHZ 0 +#define S6_GREG1_PLLSEL_GMII_IOREF 1 +#define S6_GREG1_PLLSEL_GMII_NONE 2 +#define S6_GREG1_PLLSEL_GMII_125MHZ 3 +#define S6_GREG1_PLLSEL_GMII_MASK 3 +#define S6_GREG1_SYSUNLOCKCNT 0x020 +#define S6_GREG1_IOUNLOCKCNT 0x024 +#define S6_GREG1_AIMUNLOCKCNT 0x028 +#define S6_GREG1_DP0UNLOCKCNT 0x02C +#define S6_GREG1_DP2UNLOCKCNT 0x030 +#define S6_GREG1_DDRUNLOCKCNT 0x034 +#define S6_GREG1_CLKBAL0 0x040 +#define S6_GREG1_CLKBAL0_LSGB 0 +#define S6_GREG1_CLKBAL0_LSPX 8 +#define S6_GREG1_CLKBAL0_MEMDO 16 +#define S6_GREG1_CLKBAL0_HSXT1 24 +#define S6_GREG1_CLKBAL1 0x044 +#define S6_GREG1_CLKBAL1_HSISEF 0 +#define S6_GREG1_CLKBAL1_HSNI 8 +#define S6_GREG1_CLKBAL1_HSNS 16 +#define S6_GREG1_CLKBAL1_HSISEFCFG 24 +#define S6_GREG1_CLKBAL2 0x048 +#define S6_GREG1_CLKBAL2_LSNB 0 +#define S6_GREG1_CLKBAL2_LSSB 8 +#define S6_GREG1_CLKBAL2_LSREST 24 +#define S6_GREG1_CLKBAL3 0x04C +#define S6_GREG1_CLKBAL3_ISEFXAD 0 +#define S6_GREG1_CLKBAL3_ISEFLMS 8 +#define S6_GREG1_CLKBAL3_ISEFISEF 16 +#define S6_GREG1_CLKBAL3_DDRDD 24 +#define S6_GREG1_CLKBAL4 0x050 +#define S6_GREG1_CLKBAL4_DDRDP 0 +#define S6_GREG1_CLKBAL4_DDRDO 8 +#define S6_GREG1_CLKBAL4_DDRNB 16 +#define S6_GREG1_CLKBAL4_DDRLMS 24 +#define S6_GREG1_BLOCKENA 0x100 +#define S6_GREG1_BLOCK_DDR 0 +#define S6_GREG1_BLOCK_DP 1 +#define S6_GREG1_BLOCK_NSNI 2 +#define S6_GREG1_BLOCK_PCIE 3 +#define S6_GREG1_BLOCK_GMAC 4 +#define S6_GREG1_BLOCK_I2S 5 +#define S6_GREG1_BLOCK_EGIB 6 +#define S6_GREG1_BLOCK_SB 7 +#define S6_GREG1_BLOCK_XT1 8 +#define S6_GREG1_CLKGATE 0x104 +#define S6_GREG1_BGATE_AIMNORTH 9 +#define S6_GREG1_BGATE_AIMEAST 10 +#define S6_GREG1_BGATE_AIMWEST 11 +#define S6_GREG1_BGATE_AIMSOUTH 12 +#define S6_GREG1_CHIPRES 0x108 +#define S6_GREG1_CHIPRES_SOFTRES 0 +#define S6_GREG1_CHIPRES_LOSTLOCK 1 +#define S6_GREG1_RESETCAUSE 0x10C +#define S6_GREG1_RESETCAUSE_RESETN 0 +#define S6_GREG1_RESETCAUSE_GLOBAL 1 +#define S6_GREG1_RESETCAUSE_WDOGTIMER 2 +#define S6_GREG1_RESETCAUSE_SWCHIP 3 +#define S6_GREG1_RESETCAUSE_PLLSYSLOSS 4 +#define S6_GREG1_RESETCAUSE_PCIE 5 +#define S6_GREG1_RESETCAUSE_CREATEDGLOB 6 +#define S6_GREG1_REFCLOCKCNT 0x110 +#define S6_GREG1_RESETTIMER 0x114 +#define S6_GREG1_NMITIMER 0x118 +#define S6_GREG1_GLOBAL_TIMER 0x11C +#define S6_GREG1_TIMER0 0x180 +#define S6_GREG1_TIMER1 0x184 +#define S6_GREG1_UARTCLOCKSEL 0x204 +#define S6_GREG1_CHIPVERSPACKG 0x208 +#define S6_GREG1_CHIPVERSPACKG_CHIPVID 0 +#define S6_GREG1_CHIPVERSPACKG_PACKSEL 8 +#define S6_GREG1_ONDIETERMCTRL 0x20C +#define S6_GREG1_ONDIETERMCTRL_WEST 0 +#define S6_GREG1_ONDIETERMCTRL_NORTH 2 +#define S6_GREG1_ONDIETERMCTRL_EAST 4 +#define S6_GREG1_ONDIETERMCTRL_SOUTH 6 +#define S6_GREG1_ONDIETERMCTRL_NONE 0 +#define S6_GREG1_ONDIETERMCTRL_75OHM 2 +#define S6_GREG1_ONDIETERMCTRL_MASK 3 +#define S6_GREG1_BOOT_CFG0 0x210 +#define S6_GREG1_BOOT_CFG0_AIMSTRONG 1 +#define S6_GREG1_BOOT_CFG0_MINIBOOTDL 2 +#define S6_GREG1_BOOT_CFG0_OCDGPIO8SET 5 +#define S6_GREG1_BOOT_CFG0_OCDGPIOENA 6 +#define S6_GREG1_BOOT_CFG0_DOWNSTREAM 7 +#define S6_GREG1_BOOT_CFG0_PLLSYSDIV 8 +#define S6_GREG1_BOOT_CFG0_PLLSYSDIV_300MHZ 1 +#define S6_GREG1_BOOT_CFG0_PLLSYSDIV_240MHZ 2 +#define S6_GREG1_BOOT_CFG0_PLLSYSDIV_200MHZ 3 +#define S6_GREG1_BOOT_CFG0_PLLSYSDIV_150MHZ 4 +#define S6_GREG1_BOOT_CFG0_PLLSYSDIV_120MHZ 5 +#define S6_GREG1_BOOT_CFG0_PLLSYSDIV_40MHZ 6 +#define S6_GREG1_BOOT_CFG0_PLLSYSDIV_MASK 7 +#define S6_GREG1_BOOT_CFG0_BALHSLMS 12 +#define S6_GREG1_BOOT_CFG0_BALHSNB 18 +#define S6_GREG1_BOOT_CFG0_BALHSXAD 24 +#define S6_GREG1_BOOT_CFG1 0x214 +#define S6_GREG1_BOOT_CFG1_PCIE1LANE 1 +#define S6_GREG1_BOOT_CFG1_MPLLPRESCALE 2 +#define S6_GREG1_BOOT_CFG1_MPLLNCY 4 +#define S6_GREG1_BOOT_CFG1_MPLLNCY5 9 +#define S6_GREG1_BOOT_CFG1_BALHSREST 14 +#define S6_GREG1_BOOT_CFG1_BALHSPSMEMS 20 +#define S6_GREG1_BOOT_CFG1_BALLSGI 26 +#define S6_GREG1_BOOT_CFG2 0x218 +#define S6_GREG1_BOOT_CFG2_PEID 0 +#define S6_GREG1_BOOT_CFG3 0x21C +#define S6_GREG1_DRAMBUSYHOLDOF 0x220 +#define S6_GREG1_DRAMBUSYHOLDOF_XT0 0 +#define S6_GREG1_DRAMBUSYHOLDOF_XT1 4 +#define S6_GREG1_DRAMBUSYHOLDOF_XT_MASK 7 +#define S6_GREG1_PCIEBAR1SIZE 0x224 +#define S6_GREG1_PCIEBAR2SIZE 0x228 +#define S6_GREG1_PCIEVENDOR 0x22C +#define S6_GREG1_PCIEDEVICE 0x230 +#define S6_GREG1_PCIEREV 0x234 +#define S6_GREG1_PCIECLASS 0x238 +#define S6_GREG1_XT1DCACHEMISS 0x240 +#define S6_GREG1_XT1ICACHEMISS 0x244 +#define S6_GREG1_HWSEMAPHORE(n) (0x400 + 4 * (n)) +#define S6_GREG1_HWSEMAPHORE_NB 16 + +/* peripheral interrupt numbers */ + +#define S6_INTC_GPIO(n) (n) /* 0..3 */ +#define S6_INTC_I2C 4 +#define S6_INTC_SPI 5 +#define S6_INTC_NB_ERR 6 +#define S6_INTC_DMA_LMSERR 7 +#define S6_INTC_DMA_LMSLOWWMRK(n) (8 + (n)) /* 0..11 */ +#define S6_INTC_DMA_LMSPENDCNT(n) (20 + (n)) /* 0..11 */ +#define S6_INTC_DMA HOSTLOWWMRK(n) (32 + (n)) /* 0..6 */ +#define S6_INTC_DMA_HOSTPENDCNT(n) (39 + (n)) /* 0..6 */ +#define S6_INTC_DMA_HOSTERR 46 +#define S6_INTC_UART(n) (47 + (n)) /* 0..1 */ +#define S6_INTC_XAD 49 +#define S6_INTC_NI_ERR 50 +#define S6_INTC_NI_INFIFOFULL 51 +#define S6_INTC_DMA_NIERR 52 +#define S6_INTC_DMA_NILOWWMRK(n) (53 + (n)) /* 0..3 */ +#define S6_INTC_DMA_NIPENDCNT(n) (57 + (n)) /* 0..3 */ +#define S6_INTC_DDR 61 +#define S6_INTC_NS_ERR 62 +#define S6_INTC_EFI_CFGERR 63 +#define S6_INTC_EFI_ISEFTEST 64 +#define S6_INTC_EFI_WRITEERR 65 +#define S6_INTC_NMI_TIMER 66 +#define S6_INTC_PLLLOCK_SYS 67 +#define S6_INTC_PLLLOCK_IO 68 +#define S6_INTC_PLLLOCK_AIM 69 +#define S6_INTC_PLLLOCK_DP0 70 +#define S6_INTC_PLLLOCK_DP2 71 +#define S6_INTC_I2S_ERR 72 +#define S6_INTC_GMAC_STAT 73 +#define S6_INTC_GMAC_ERR 74 +#define S6_INTC_GIB_ERR 75 +#define S6_INTC_PCIE_ERR 76 +#define S6_INTC_PCIE_MSI(n) (77 + (n)) /* 0..3 */ +#define S6_INTC_PCIE_INTA 81 +#define S6_INTC_PCIE_INTB 82 +#define S6_INTC_PCIE_INTC 83 +#define S6_INTC_PCIE_INTD 84 +#define S6_INTC_SW(n) (85 + (n)) /* 0..9 */ +#define S6_INTC_SW_ENABLE(n) (85 + 256 + (n)) +#define S6_INTC_DMA_DP_ERR 95 +#define S6_INTC_DMA_DPLOWWMRK(n) (96 + (n)) /* 0..3 */ +#define S6_INTC_DMA_DPPENDCNT(n) (100 + (n)) /* 0..3 */ +#define S6_INTC_DMA_DPTERMCNT(n) (104 + (n)) /* 0..3 */ +#define S6_INTC_TIMER0 108 +#define S6_INTC_TIMER1 109 +#define S6_INTC_DMA_HOSTTERMCNT(n) (110 + (n)) /* 0..6 */ + +#endif /* __XTENSA_S6000_HARDWARE_H */ diff --git a/arch/xtensa/variants/s6000/include/variant/irq.h b/arch/xtensa/variants/s6000/include/variant/irq.h new file mode 100644 index 00000000..97d6fc48 --- /dev/null +++ b/arch/xtensa/variants/s6000/include/variant/irq.h @@ -0,0 +1,9 @@ +#ifndef _XTENSA_S6000_IRQ_H +#define _XTENSA_S6000_IRQ_H + +#define NO_IRQ (-1) +#define VARIANT_NR_IRQS 8 /* GPIO interrupts */ + +extern void variant_irq_enable(unsigned int irq); + +#endif /* __XTENSA_S6000_IRQ_H */ diff --git a/arch/xtensa/variants/s6000/include/variant/tie-asm.h b/arch/xtensa/variants/s6000/include/variant/tie-asm.h new file mode 100644 index 00000000..f02d0a3a --- /dev/null +++ b/arch/xtensa/variants/s6000/include/variant/tie-asm.h @@ -0,0 +1,304 @@ +/* + * This header file contains assembly-language definitions (assembly + * macros, etc.) for this specific Xtensa processor's TIE extensions + * and options. It is customized to this Xtensa processor configuration. + * + * 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) 1999-2008 Tensilica Inc. + */ + +#ifndef _XTENSA_CORE_TIE_ASM_H +#define _XTENSA_CORE_TIE_ASM_H + +/* Selection parameter values for save-area save/restore macros: */ +/* Option vs. TIE: */ +#define XTHAL_SAS_TIE 0x0001 /* custom extension or coprocessor */ +#define XTHAL_SAS_OPT 0x0002 /* optional (and not a coprocessor) */ +/* Whether used automatically by compiler: */ +#define XTHAL_SAS_NOCC 0x0004 /* not used by compiler w/o special opts/code */ +#define XTHAL_SAS_CC 0x0008 /* used by compiler without special opts/code */ +/* ABI handling across function calls: */ +#define XTHAL_SAS_CALR 0x0010 /* caller-saved */ +#define XTHAL_SAS_CALE 0x0020 /* callee-saved */ +#define XTHAL_SAS_GLOB 0x0040 /* global across function calls (in thread) */ +/* Misc */ +#define XTHAL_SAS_ALL 0xFFFF /* include all default NCP contents */ + + + +/* Macro to save all non-coprocessor (extra) custom TIE and optional state + * (not including zero-overhead loop registers). + * Save area ptr (clobbered): ptr (16 byte aligned) + * Scratch regs (clobbered): at1..at4 (only first XCHAL_NCP_NUM_ATMPS needed) + */ + .macro xchal_ncp_store ptr at1 at2 at3 at4 continue=0 ofs=-1 select=XTHAL_SAS_ALL + xchal_sa_start \continue, \ofs + .ifeq (XTHAL_SAS_OPT | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~\select + xchal_sa_align \ptr, 0, 1024-4, 4, 4 + rsr \at1, BR // boolean option + s32i \at1, \ptr, .Lxchal_ofs_ + 0 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 4 + .endif + .endm // xchal_ncp_store + +/* Macro to save all non-coprocessor (extra) custom TIE and optional state + * (not including zero-overhead loop registers). + * Save area ptr (clobbered): ptr (16 byte aligned) + * Scratch regs (clobbered): at1..at4 (only first XCHAL_NCP_NUM_ATMPS needed) + */ + .macro xchal_ncp_load ptr at1 at2 at3 at4 continue=0 ofs=-1 select=XTHAL_SAS_ALL + xchal_sa_start \continue, \ofs + .ifeq (XTHAL_SAS_OPT | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~\select + xchal_sa_align \ptr, 0, 1024-4, 4, 4 + l32i \at1, \ptr, .Lxchal_ofs_ + 0 + wsr \at1, BR // boolean option + .set .Lxchal_ofs_, .Lxchal_ofs_ + 4 + .endif + .endm // xchal_ncp_load + + + +#define XCHAL_NCP_NUM_ATMPS 1 + + + +/* Macro to save the state of TIE coprocessor FPU. + * Save area ptr (clobbered): ptr (16 byte aligned) + * Scratch regs (clobbered): at1..at4 (only first XCHAL_CP0_NUM_ATMPS needed) + */ +#define xchal_cp_FPU_store xchal_cp0_store +/* #define xchal_cp_FPU_store_a2 xchal_cp0_store a2 a3 a4 a5 a6 */ + .macro xchal_cp0_store ptr at1 at2 at3 at4 continue=0 ofs=-1 select=XTHAL_SAS_ALL + xchal_sa_start \continue, \ofs + .ifeq (XTHAL_SAS_TIE | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~\select + xchal_sa_align \ptr, 0, 0, 1, 16 + rur232 \at1 // FCR + s32i \at1, \ptr, 0 + rur233 \at1 // FSR + s32i \at1, \ptr, 4 + SSI f0, \ptr, 8 + SSI f1, \ptr, 12 + SSI f2, \ptr, 16 + SSI f3, \ptr, 20 + SSI f4, \ptr, 24 + SSI f5, \ptr, 28 + SSI f6, \ptr, 32 + SSI f7, \ptr, 36 + SSI f8, \ptr, 40 + SSI f9, \ptr, 44 + SSI f10, \ptr, 48 + SSI f11, \ptr, 52 + SSI f12, \ptr, 56 + SSI f13, \ptr, 60 + SSI f14, \ptr, 64 + SSI f15, \ptr, 68 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 72 + .endif + .endm // xchal_cp0_store + +/* Macro to restore the state of TIE coprocessor FPU. + * Save area ptr (clobbered): ptr (16 byte aligned) + * Scratch regs (clobbered): at1..at4 (only first XCHAL_CP0_NUM_ATMPS needed) + */ +#define xchal_cp_FPU_load xchal_cp0_load +/* #define xchal_cp_FPU_load_a2 xchal_cp0_load a2 a3 a4 a5 a6 */ + .macro xchal_cp0_load ptr at1 at2 at3 at4 continue=0 ofs=-1 select=XTHAL_SAS_ALL + xchal_sa_start \continue, \ofs + .ifeq (XTHAL_SAS_TIE | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~\select + xchal_sa_align \ptr, 0, 0, 1, 16 + l32i \at1, \ptr, 0 + wur232 \at1 // FCR + l32i \at1, \ptr, 4 + wur233 \at1 // FSR + LSI f0, \ptr, 8 + LSI f1, \ptr, 12 + LSI f2, \ptr, 16 + LSI f3, \ptr, 20 + LSI f4, \ptr, 24 + LSI f5, \ptr, 28 + LSI f6, \ptr, 32 + LSI f7, \ptr, 36 + LSI f8, \ptr, 40 + LSI f9, \ptr, 44 + LSI f10, \ptr, 48 + LSI f11, \ptr, 52 + LSI f12, \ptr, 56 + LSI f13, \ptr, 60 + LSI f14, \ptr, 64 + LSI f15, \ptr, 68 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 72 + .endif + .endm // xchal_cp0_load + +#define XCHAL_CP0_NUM_ATMPS 1 + +/* Macro to save the state of TIE coprocessor XAD. + * Save area ptr (clobbered): ptr (16 byte aligned) + * Scratch regs (clobbered): at1..at4 (only first XCHAL_CP6_NUM_ATMPS needed) + */ +#define xchal_cp_XAD_store xchal_cp6_store +/* #define xchal_cp_XAD_store_a2 xchal_cp6_store a2 a3 a4 a5 a6 */ + .macro xchal_cp6_store ptr at1 at2 at3 at4 continue=0 ofs=-1 select=XTHAL_SAS_ALL + xchal_sa_start \continue, \ofs + .ifeq (XTHAL_SAS_TIE | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~\select + xchal_sa_align \ptr, 0, 0, 1, 16 + rur0 \at1 // LDCBHI + s32i \at1, \ptr, 0 + rur1 \at1 // LDCBLO + s32i \at1, \ptr, 4 + rur2 \at1 // STCBHI + s32i \at1, \ptr, 8 + rur3 \at1 // STCBLO + s32i \at1, \ptr, 12 + rur8 \at1 // LDBRBASE + s32i \at1, \ptr, 16 + rur9 \at1 // LDBROFF + s32i \at1, \ptr, 20 + rur10 \at1 // LDBRINC + s32i \at1, \ptr, 24 + rur11 \at1 // STBRBASE + s32i \at1, \ptr, 28 + rur12 \at1 // STBROFF + s32i \at1, \ptr, 32 + rur13 \at1 // STBRINC + s32i \at1, \ptr, 36 + rur24 \at1 // SCRATCH0 + s32i \at1, \ptr, 40 + rur25 \at1 // SCRATCH1 + s32i \at1, \ptr, 44 + rur26 \at1 // SCRATCH2 + s32i \at1, \ptr, 48 + rur27 \at1 // SCRATCH3 + s32i \at1, \ptr, 52 + WRAS128I wra0, \ptr, 64 + WRAS128I wra1, \ptr, 80 + WRAS128I wra2, \ptr, 96 + WRAS128I wra3, \ptr, 112 + WRAS128I wra4, \ptr, 128 + WRAS128I wra5, \ptr, 144 + WRAS128I wra6, \ptr, 160 + WRAS128I wra7, \ptr, 176 + WRAS128I wra8, \ptr, 192 + WRAS128I wra9, \ptr, 208 + WRAS128I wra10, \ptr, 224 + WRAS128I wra11, \ptr, 240 + WRAS128I wra12, \ptr, 256 + WRAS128I wra13, \ptr, 272 + WRAS128I wra14, \ptr, 288 + WRAS128I wra15, \ptr, 304 + WRBS128I wrb0, \ptr, 320 + WRBS128I wrb1, \ptr, 336 + WRBS128I wrb2, \ptr, 352 + WRBS128I wrb3, \ptr, 368 + WRBS128I wrb4, \ptr, 384 + WRBS128I wrb5, \ptr, 400 + WRBS128I wrb6, \ptr, 416 + WRBS128I wrb7, \ptr, 432 + WRBS128I wrb8, \ptr, 448 + WRBS128I wrb9, \ptr, 464 + WRBS128I wrb10, \ptr, 480 + WRBS128I wrb11, \ptr, 496 + WRBS128I wrb12, \ptr, 512 + WRBS128I wrb13, \ptr, 528 + WRBS128I wrb14, \ptr, 544 + WRBS128I wrb15, \ptr, 560 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 576 + .endif + .endm // xchal_cp6_store + +/* Macro to restore the state of TIE coprocessor XAD. + * Save area ptr (clobbered): ptr (16 byte aligned) + * Scratch regs (clobbered): at1..at4 (only first XCHAL_CP6_NUM_ATMPS needed) + */ +#define xchal_cp_XAD_load xchal_cp6_load +/* #define xchal_cp_XAD_load_a2 xchal_cp6_load a2 a3 a4 a5 a6 */ + .macro xchal_cp6_load ptr at1 at2 at3 at4 continue=0 ofs=-1 select=XTHAL_SAS_ALL + xchal_sa_start \continue, \ofs + .ifeq (XTHAL_SAS_TIE | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~\select + xchal_sa_align \ptr, 0, 0, 1, 16 + l32i \at1, \ptr, 0 + wur0 \at1 // LDCBHI + l32i \at1, \ptr, 4 + wur1 \at1 // LDCBLO + l32i \at1, \ptr, 8 + wur2 \at1 // STCBHI + l32i \at1, \ptr, 12 + wur3 \at1 // STCBLO + l32i \at1, \ptr, 16 + wur8 \at1 // LDBRBASE + l32i \at1, \ptr, 20 + wur9 \at1 // LDBROFF + l32i \at1, \ptr, 24 + wur10 \at1 // LDBRINC + l32i \at1, \ptr, 28 + wur11 \at1 // STBRBASE + l32i \at1, \ptr, 32 + wur12 \at1 // STBROFF + l32i \at1, \ptr, 36 + wur13 \at1 // STBRINC + l32i \at1, \ptr, 40 + wur24 \at1 // SCRATCH0 + l32i \at1, \ptr, 44 + wur25 \at1 // SCRATCH1 + l32i \at1, \ptr, 48 + wur26 \at1 // SCRATCH2 + l32i \at1, \ptr, 52 + wur27 \at1 // SCRATCH3 + WRBL128I wrb0, \ptr, 320 + WRBL128I wrb1, \ptr, 336 + WRBL128I wrb2, \ptr, 352 + WRBL128I wrb3, \ptr, 368 + WRBL128I wrb4, \ptr, 384 + WRBL128I wrb5, \ptr, 400 + WRBL128I wrb6, \ptr, 416 + WRBL128I wrb7, \ptr, 432 + WRBL128I wrb8, \ptr, 448 + WRBL128I wrb9, \ptr, 464 + WRBL128I wrb10, \ptr, 480 + WRBL128I wrb11, \ptr, 496 + WRBL128I wrb12, \ptr, 512 + WRBL128I wrb13, \ptr, 528 + WRBL128I wrb14, \ptr, 544 + WRBL128I wrb15, \ptr, 560 + WRAL128I wra0, \ptr, 64 + WRAL128I wra1, \ptr, 80 + WRAL128I wra2, \ptr, 96 + WRAL128I wra3, \ptr, 112 + WRAL128I wra4, \ptr, 128 + WRAL128I wra5, \ptr, 144 + WRAL128I wra6, \ptr, 160 + WRAL128I wra7, \ptr, 176 + WRAL128I wra8, \ptr, 192 + WRAL128I wra9, \ptr, 208 + WRAL128I wra10, \ptr, 224 + WRAL128I wra11, \ptr, 240 + WRAL128I wra12, \ptr, 256 + WRAL128I wra13, \ptr, 272 + WRAL128I wra14, \ptr, 288 + WRAL128I wra15, \ptr, 304 + .set .Lxchal_ofs_, .Lxchal_ofs_ + 576 + .endif + .endm // xchal_cp6_load + +#define XCHAL_CP6_NUM_ATMPS 1 +#define XCHAL_SA_NUM_ATMPS 1 + + /* Empty macros for unconfigured coprocessors: */ + .macro xchal_cp1_store p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp1_load p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp2_store p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp2_load p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp3_store p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp3_load p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp4_store p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp4_load p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp5_store p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp5_load p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp7_store p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp7_load p a b c d continue=0 ofs=-1 select=-1 ; .endm + +#endif /*_XTENSA_CORE_TIE_ASM_H*/ + diff --git a/arch/xtensa/variants/s6000/include/variant/tie.h b/arch/xtensa/variants/s6000/include/variant/tie.h new file mode 100644 index 00000000..be7ea843 --- /dev/null +++ b/arch/xtensa/variants/s6000/include/variant/tie.h @@ -0,0 +1,191 @@ +/* + * This header file describes this specific Xtensa processor's TIE extensions + * that extend basic Xtensa core functionality. It is customized to this + * Xtensa processor configuration. + * + * 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) 1999-2008 Tensilica Inc. + */ + +#ifndef _XTENSA_CORE_TIE_H +#define _XTENSA_CORE_TIE_H + +#define XCHAL_CP_NUM 2 /* number of coprocessors */ +#define XCHAL_CP_MAX 7 /* max CP ID + 1 (0 if none) */ +#define XCHAL_CP_MASK 0x41 /* bitmask of all CPs by ID */ +#define XCHAL_CP_PORT_MASK 0x00 /* bitmask of only port CPs */ + +/* Basic parameters of each coprocessor: */ +#define XCHAL_CP0_NAME "FPU" +#define XCHAL_CP0_IDENT FPU +#define XCHAL_CP0_SA_SIZE 72 /* size of state save area */ +#define XCHAL_CP0_SA_ALIGN 4 /* min alignment of save area */ +#define XCHAL_CP_ID_FPU 0 /* coprocessor ID (0..7) */ +#define XCHAL_CP6_NAME "XAD" +#define XCHAL_CP6_IDENT XAD +#define XCHAL_CP6_SA_SIZE 576 /* size of state save area */ +#define XCHAL_CP6_SA_ALIGN 16 /* min alignment of save area */ +#define XCHAL_CP_ID_XAD 6 /* coprocessor ID (0..7) */ + +/* Filler info for unassigned coprocessors, to simplify arrays etc: */ +#define XCHAL_CP1_SA_SIZE 0 +#define XCHAL_CP1_SA_ALIGN 1 +#define XCHAL_CP2_SA_SIZE 0 +#define XCHAL_CP2_SA_ALIGN 1 +#define XCHAL_CP3_SA_SIZE 0 +#define XCHAL_CP3_SA_ALIGN 1 +#define XCHAL_CP4_SA_SIZE 0 +#define XCHAL_CP4_SA_ALIGN 1 +#define XCHAL_CP5_SA_SIZE 0 +#define XCHAL_CP5_SA_ALIGN 1 +#define XCHAL_CP7_SA_SIZE 0 +#define XCHAL_CP7_SA_ALIGN 1 + +/* Save area for non-coprocessor optional and custom (TIE) state: */ +#define XCHAL_NCP_SA_SIZE 4 +#define XCHAL_NCP_SA_ALIGN 4 + +/* Total save area for optional and custom state (NCP + CPn): */ +#define XCHAL_TOTAL_SA_SIZE 672 /* with 16-byte align padding */ +#define XCHAL_TOTAL_SA_ALIGN 16 /* actual minimum alignment */ + +/* + * Detailed contents of save areas. + * NOTE: caller must define the XCHAL_SA_REG macro (not defined here) + * before expanding the XCHAL_xxx_SA_LIST() macros. + * + * XCHAL_SA_REG(s,ccused,abikind,kind,opt,name,galign,align,asize, + * dbnum,base,regnum,bitsz,gapsz,reset,x...) + * + * s = passed from XCHAL_*_LIST(s), eg. to select how to expand + * ccused = set if used by compiler without special options or code + * abikind = 0 (caller-saved), 1 (callee-saved), or 2 (thread-global) + * kind = 0 (special reg), 1 (TIE user reg), or 2 (TIE regfile reg) + * opt = 0 (custom TIE extension or coprocessor), or 1 (optional reg) + * name = lowercase reg name (no quotes) + * galign = group byte alignment (power of 2) (galign >= align) + * align = register byte alignment (power of 2) + * asize = allocated size in bytes (asize*8 == bitsz + gapsz + padsz) + * (not including any pad bytes required to galign this or next reg) + * dbnum = unique target number f/debug (see <xtensa-libdb-macros.h>) + * base = reg shortname w/o index (or sr=special, ur=TIE user reg) + * regnum = reg index in regfile, or special/TIE-user reg number + * bitsz = number of significant bits (regfile width, or ur/sr mask bits) + * gapsz = intervening bits, if bitsz bits not stored contiguously + * (padsz = pad bits at end [TIE regfile] or at msbits [ur,sr] of asize) + * reset = register reset value (or 0 if undefined at reset) + * x = reserved for future use (0 until then) + * + * To filter out certain registers, e.g. to expand only the non-global + * registers used by the compiler, you can do something like this: + * + * #define XCHAL_SA_REG(s,ccused,p...) SELCC##ccused(p) + * #define SELCC0(p...) + * #define SELCC1(abikind,p...) SELAK##abikind(p) + * #define SELAK0(p...) REG(p) + * #define SELAK1(p...) REG(p) + * #define SELAK2(p...) + * #define REG(kind,tie,name,galn,aln,asz,csz,dbnum,base,rnum,bsz,rst,x...) \ + * ...what you want to expand... + */ + +#define XCHAL_NCP_SA_NUM 1 +#define XCHAL_NCP_SA_LIST(s) \ + XCHAL_SA_REG(s,0,0,0,1, br, 4, 4, 4,0x0204, sr,4 , 16,0,0,0) + +#define XCHAL_CP0_SA_NUM 18 +#define XCHAL_CP0_SA_LIST(s) \ + XCHAL_SA_REG(s,0,0,1,0, fcr, 4, 4, 4,0x03E8, ur,232, 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0, fsr, 4, 4, 4,0x03E9, ur,233, 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, f0, 4, 4, 4,0x0030, f,0 , 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, f1, 4, 4, 4,0x0031, f,1 , 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, f2, 4, 4, 4,0x0032, f,2 , 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, f3, 4, 4, 4,0x0033, f,3 , 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, f4, 4, 4, 4,0x0034, f,4 , 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, f5, 4, 4, 4,0x0035, f,5 , 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, f6, 4, 4, 4,0x0036, f,6 , 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, f7, 4, 4, 4,0x0037, f,7 , 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, f8, 4, 4, 4,0x0038, f,8 , 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, f9, 4, 4, 4,0x0039, f,9 , 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, f10, 4, 4, 4,0x003A, f,10 , 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, f11, 4, 4, 4,0x003B, f,11 , 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, f12, 4, 4, 4,0x003C, f,12 , 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, f13, 4, 4, 4,0x003D, f,13 , 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, f14, 4, 4, 4,0x003E, f,14 , 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, f15, 4, 4, 4,0x003F, f,15 , 32,0,0,0) + +#define XCHAL_CP1_SA_NUM 0 +#define XCHAL_CP1_SA_LIST(s) /* empty */ + +#define XCHAL_CP2_SA_NUM 0 +#define XCHAL_CP2_SA_LIST(s) /* empty */ + +#define XCHAL_CP3_SA_NUM 0 +#define XCHAL_CP3_SA_LIST(s) /* empty */ + +#define XCHAL_CP4_SA_NUM 0 +#define XCHAL_CP4_SA_LIST(s) /* empty */ + +#define XCHAL_CP5_SA_NUM 0 +#define XCHAL_CP5_SA_LIST(s) /* empty */ + +#define XCHAL_CP6_SA_NUM 46 +#define XCHAL_CP6_SA_LIST(s) \ + XCHAL_SA_REG(s,0,0,1,0, ldcbhi,16, 4, 4,0x0300, ur,0 , 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0, ldcblo, 4, 4, 4,0x0301, ur,1 , 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0, stcbhi, 4, 4, 4,0x0302, ur,2 , 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0, stcblo, 4, 4, 4,0x0303, ur,3 , 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0, ldbrbase, 4, 4, 4,0x0308, ur,8 , 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0, ldbroff, 4, 4, 4,0x0309, ur,9 , 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0, ldbrinc, 4, 4, 4,0x030A, ur,10 , 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0, stbrbase, 4, 4, 4,0x030B, ur,11 , 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0, stbroff, 4, 4, 4,0x030C, ur,12 , 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0, stbrinc, 4, 4, 4,0x030D, ur,13 , 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0, scratch0, 4, 4, 4,0x0318, ur,24 , 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0, scratch1, 4, 4, 4,0x0319, ur,25 , 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0, scratch2, 4, 4, 4,0x031A, ur,26 , 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,1,0, scratch3, 4, 4, 4,0x031B, ur,27 , 32,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, wra0,16,16,16,0x1010, wra,0 ,128,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, wra1,16,16,16,0x1011, wra,1 ,128,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, wra2,16,16,16,0x1012, wra,2 ,128,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, wra3,16,16,16,0x1013, wra,3 ,128,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, wra4,16,16,16,0x1014, wra,4 ,128,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, wra5,16,16,16,0x1015, wra,5 ,128,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, wra6,16,16,16,0x1016, wra,6 ,128,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, wra7,16,16,16,0x1017, wra,7 ,128,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, wra8,16,16,16,0x1018, wra,8 ,128,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, wra9,16,16,16,0x1019, wra,9 ,128,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, wra10,16,16,16,0x101A, wra,10 ,128,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, wra11,16,16,16,0x101B, wra,11 ,128,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, wra12,16,16,16,0x101C, wra,12 ,128,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, wra13,16,16,16,0x101D, wra,13 ,128,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, wra14,16,16,16,0x101E, wra,14 ,128,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, wra15,16,16,16,0x101F, wra,15 ,128,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, wrb0,16,16,16,0x1020, wrb,0 ,128,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, wrb1,16,16,16,0x1021, wrb,1 ,128,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, wrb2,16,16,16,0x1022, wrb,2 ,128,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, wrb3,16,16,16,0x1023, wrb,3 ,128,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, wrb4,16,16,16,0x1024, wrb,4 ,128,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, wrb5,16,16,16,0x1025, wrb,5 ,128,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, wrb6,16,16,16,0x1026, wrb,6 ,128,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, wrb7,16,16,16,0x1027, wrb,7 ,128,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, wrb8,16,16,16,0x1028, wrb,8 ,128,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, wrb9,16,16,16,0x1029, wrb,9 ,128,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, wrb10,16,16,16,0x102A, wrb,10 ,128,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, wrb11,16,16,16,0x102B, wrb,11 ,128,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, wrb12,16,16,16,0x102C, wrb,12 ,128,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, wrb13,16,16,16,0x102D, wrb,13 ,128,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, wrb14,16,16,16,0x102E, wrb,14 ,128,0,0,0) \ + XCHAL_SA_REG(s,0,0,2,0, wrb15,16,16,16,0x102F, wrb,15 ,128,0,0,0) + +#define XCHAL_CP7_SA_NUM 0 +#define XCHAL_CP7_SA_LIST(s) /* empty */ + +/* Byte length of instruction from its first nibble (op0 field), per FLIX. */ +#define XCHAL_OP0_FORMAT_LENGTHS 3,3,3,3,3,3,3,3,2,2,2,2,2,2,8,8 + +#endif /*_XTENSA_CORE_TIE_H*/ + diff --git a/arch/xtensa/variants/s6000/irq.c b/arch/xtensa/variants/s6000/irq.c new file mode 100644 index 00000000..6651e328 --- /dev/null +++ b/arch/xtensa/variants/s6000/irq.c @@ -0,0 +1,74 @@ +/* + * s6000 irq crossbar + * + * Copyright (c) 2009 emlix GmbH + * Authors: Johannes Weiner <jw@emlix.com> + * Oskar Schirmer <os@emlix.com> + */ +#include <linux/io.h> +#include <asm/irq.h> +#include <variant/hardware.h> + +/* S6_REG_INTC */ +#define INTC_STATUS 0x000 +#define INTC_RAW 0x010 +#define INTC_STATUS_AG 0x100 +#define INTC_CFG(n) (0x200 + 4 * (n)) + +/* + * The s6000 has a crossbar that multiplexes interrupt output lines + * from the peripherals to input lines on the xtensa core. + * + * We leave the mapping decisions to the platform as it depends on the + * actually connected peripherals which distribution makes sense. + */ +extern const signed char *platform_irq_mappings[NR_IRQS]; + +static unsigned long scp_to_intc_enable[] = { +#define TO_INTC_ENABLE(n) (((n) << 1) + 1) + TO_INTC_ENABLE(0), + TO_INTC_ENABLE(1), + TO_INTC_ENABLE(2), + TO_INTC_ENABLE(3), + TO_INTC_ENABLE(4), + TO_INTC_ENABLE(5), + TO_INTC_ENABLE(6), + TO_INTC_ENABLE(7), + TO_INTC_ENABLE(8), + TO_INTC_ENABLE(9), + TO_INTC_ENABLE(10), + TO_INTC_ENABLE(11), + TO_INTC_ENABLE(12), + -1, + -1, + TO_INTC_ENABLE(13), + -1, + TO_INTC_ENABLE(14), + -1, + TO_INTC_ENABLE(15), +#undef TO_INTC_ENABLE +}; + +static void irq_set(unsigned int irq, int enable) +{ + unsigned long en; + const signed char *m = platform_irq_mappings[irq]; + + if (!m) + return; + en = enable ? scp_to_intc_enable[irq] : 0; + while (*m >= 0) { + writel(en, S6_REG_INTC + INTC_CFG(*m)); + m++; + } +} + +void variant_irq_enable(unsigned int irq) +{ + irq_set(irq, 1); +} + +void variant_irq_disable(unsigned int irq) +{ + irq_set(irq, 0); +} |