From c462e1a613c8f84bb503189b0796d036dd1e5376 Mon Sep 17 00:00:00 2001 From: Jason Jin Date: Thu, 4 Aug 2011 09:59:35 +0800 Subject: [PATCH 01/52] Coldfire architecture support in Linux 2.6.38 Coldfire architecture support in Linux 2.6.38. Signed-off-by: Alison Wang Signed-off-by: Jason Jin --- arch/m68k/Kconfig | 279 +++++++++- arch/m68k/Kconfig.debug | 9 + arch/m68k/Makefile | 48 ++- arch/m68k/boot/Makefile | 68 +++ arch/m68k/coldfire/Makefile | 10 + arch/m68k/coldfire/common/Makefile | 7 + arch/m68k/coldfire/common/cache.c | 45 ++ arch/m68k/coldfire/common/clk.c | 51 ++ arch/m68k/coldfire/common/entry.S | 745 ++++++++++++++++++++++++ arch/m68k/coldfire/common/head.S | 466 +++++++++++++++ arch/m68k/coldfire/common/ints.c | 544 ++++++++++++++++++ arch/m68k/coldfire/common/muldi3.S | 73 +++ arch/m68k/coldfire/common/signal.c | 991 ++++++++++++++++++++++++++++++++ arch/m68k/coldfire/common/traps.c | 457 +++++++++++++++ arch/m68k/include/asm/atomic.h | 33 +- arch/m68k/include/asm/bitops_mm.h | 12 +- arch/m68k/include/asm/bootinfo.h | 42 ++ arch/m68k/include/asm/cacheflush_mm.h | 14 +- arch/m68k/include/asm/cf-sram.h | 21 + arch/m68k/include/asm/cf_bitops.h | 443 ++++++++++++++ arch/m68k/include/asm/cf_cacheflush.h | 20 + arch/m68k/include/asm/cf_entry.h | 153 +++++ arch/m68k/include/asm/cf_io.h | 185 ++++++ arch/m68k/include/asm/cf_pgalloc.h | 112 ++++ arch/m68k/include/asm/cf_pgtable.h | 364 ++++++++++++ arch/m68k/include/asm/cf_raw_io.h | 188 ++++++ arch/m68k/include/asm/cf_tlbflush.h | 66 +++ arch/m68k/include/asm/cf_uaccess.h | 262 +++++++++ arch/m68k/include/asm/cf_virtconvert.h | 63 ++ arch/m68k/include/asm/cfcache.h | 146 +++++ arch/m68k/include/asm/cfmmu.h | 112 ++++ arch/m68k/include/asm/coldfire.h | 70 ++- arch/m68k/include/asm/delay_mm.h | 42 ++- arch/m68k/include/asm/div64.h | 11 +- arch/m68k/include/asm/dma.h | 109 ++++- arch/m68k/include/asm/elf.h | 70 +++- arch/m68k/include/asm/io_mm.h | 234 ++++++-- arch/m68k/include/asm/irq.h | 14 +- arch/m68k/include/asm/machdep.h | 15 +- arch/m68k/include/asm/mcfdspi.h | 59 ++ arch/m68k/include/asm/mcfsim.h | 121 ++++ arch/m68k/include/asm/mcfuart.h | 64 ++ arch/m68k/include/asm/mmu.h | 15 +- arch/m68k/include/asm/mmu_context.h | 184 ++++++- arch/m68k/include/asm/page.h | 10 +- arch/m68k/include/asm/page_mm.h | 61 ++ arch/m68k/include/asm/page_offset.h | 21 +- arch/m68k/include/asm/pgalloc.h | 12 +- arch/m68k/include/asm/pgtable_mm.h | 36 ++- arch/m68k/include/asm/processor.h | 45 ++- arch/m68k/include/asm/ptrace.h | 48 ++- arch/m68k/include/asm/raw_io.h | 15 +- arch/m68k/include/asm/segment.h | 17 + arch/m68k/include/asm/setup.h | 36 ++ arch/m68k/include/asm/signal.h | 10 +- arch/m68k/include/asm/string.h | 20 +- arch/m68k/include/asm/swab.h | 15 +- arch/m68k/include/asm/system_mm.h | 23 +- arch/m68k/include/asm/tlbflush.h | 24 +- arch/m68k/include/asm/uaccess_mm.h | 80 ++-- arch/m68k/include/asm/unistd.h | 11 +- arch/m68k/include/asm/virtconvert.h | 11 + arch/m68k/kernel/Makefile | 23 +- arch/m68k/kernel/asm-offsets.c | 28 + arch/m68k/kernel/dma.c | 47 ++- arch/m68k/kernel/process.c | 66 +++ arch/m68k/kernel/setup.c | 72 ++- arch/m68k/kernel/sys_m68k.c | 80 +++ arch/m68k/kernel/time.c | 142 +++++- arch/m68k/kernel/vmlinux-cf.lds | 142 +++++ arch/m68k/kernel/vmlinux.lds.S | 12 +- arch/m68k/lib/checksum.c | 129 +++++ arch/m68k/lib/muldi3.c | 13 + arch/m68k/lib/string.c | 68 +++ arch/m68k/lib/uaccess.c | 247 ++++++++ arch/m68k/mm/Makefile | 2 + arch/m68k/mm/cache.c | 19 + arch/m68k/mm/cf-mmu.c | 311 ++++++++++ arch/m68k/mm/cf-sram.c | 80 +++ arch/m68k/mm/hwtest.c | 10 + arch/m68k/mm/init.c | 15 +- arch/m68k/mm/kmap.c | 82 +++- arch/m68k/mm/memory.c | 17 + fs/namespace.c | 8 + include/linux/fsl_devices.h | 14 +- 85 files changed, 8962 insertions(+), 197 deletions(-) create mode 100644 arch/m68k/boot/Makefile create mode 100644 arch/m68k/coldfire/Makefile create mode 100644 arch/m68k/coldfire/common/Makefile create mode 100644 arch/m68k/coldfire/common/cache.c create mode 100644 arch/m68k/coldfire/common/clk.c create mode 100644 arch/m68k/coldfire/common/entry.S create mode 100644 arch/m68k/coldfire/common/head.S create mode 100644 arch/m68k/coldfire/common/ints.c create mode 100644 arch/m68k/coldfire/common/muldi3.S create mode 100644 arch/m68k/coldfire/common/signal.c create mode 100644 arch/m68k/coldfire/common/traps.c create mode 100644 arch/m68k/include/asm/cf-sram.h create mode 100644 arch/m68k/include/asm/cf_bitops.h create mode 100644 arch/m68k/include/asm/cf_cacheflush.h create mode 100644 arch/m68k/include/asm/cf_entry.h create mode 100644 arch/m68k/include/asm/cf_io.h create mode 100644 arch/m68k/include/asm/cf_pgalloc.h create mode 100644 arch/m68k/include/asm/cf_pgtable.h create mode 100644 arch/m68k/include/asm/cf_raw_io.h create mode 100644 arch/m68k/include/asm/cf_tlbflush.h create mode 100644 arch/m68k/include/asm/cf_uaccess.h create mode 100644 arch/m68k/include/asm/cf_virtconvert.h create mode 100644 arch/m68k/include/asm/cfcache.h create mode 100644 arch/m68k/include/asm/cfmmu.h create mode 100644 arch/m68k/include/asm/mcfdspi.h create mode 100644 arch/m68k/kernel/vmlinux-cf.lds create mode 100644 arch/m68k/mm/cf-mmu.c create mode 100644 arch/m68k/mm/cf-sram.c --- a/arch/m68k/Kconfig +++ b/arch/m68k/Kconfig @@ -9,6 +9,14 @@ config MMU bool default y +config GENERIC_TIME + bool "Enable generic timer" + default n + +config GENERIC_CLOCKEVENTS + bool "Enable generic clockevents" + default n + config RWSEM_GENERIC_SPINLOCK bool default y @@ -34,7 +42,7 @@ config GENERIC_CALIBRATE_DELAY config TIME_LOW_RES bool - default y + default n config GENERIC_IOMAP bool @@ -46,7 +54,7 @@ config ARCH_MAY_HAVE_PC_FDC default y config NO_IOPORT - def_bool y + def_bool !(M5445X || M547X_8X || M5441X) config NO_DMA def_bool SUN3 @@ -105,6 +113,35 @@ config PCMCIA To compile this driver as modules, choose M here: the modules will be called pcmcia_core and ds. +config COLDFIRE + bool "ColdFire V4e support" + default y + select CFV4E + help + Say Y if you want to build a kernel to run on one of the ColdFire + V4e boards. + +config CFV4E + bool + depends on COLDFIRE + select MMU_CFV4E if MMU + default y + +config FPU + bool "ColdFire V4e FPU support" + default n + help + This enables support for CFV4E FPU feature. + +config MCD_DMA + bool "ColdFire MCD DMA support" + depends on M547X_8X + default y + help + This enables support for the ColdFire 547x/548x family + multichannel DMA support. Many drivers need it. + If you want it, say Y + config AMIGA bool "Amiga support" select MMU_MOTOROLA if MMU @@ -122,6 +159,16 @@ config ATARI this kernel on an Atari, say Y here and browse the material available in ; otherwise say N. +config PCI + bool "PCI bus support" + depends on M54455 || M547X_8X + default n + 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. + config MAC bool "Macintosh support" select MMU_MOTOROLA if MMU @@ -276,6 +323,147 @@ config M68060 If you anticipate running this kernel on a computer with a MC68060 processor, say Y. Otherwise, say N. +config M5445X + bool "MCF5445x support" + depends on COLDFIRE + select GENERIC_TIME + select USB_EHCI_FSL + select HAVE_FSL_USB_DR + help + This option will add support for the MCF544x processor with mmu. + +config M54451 + bool + depends on M5445X + default n + +config M54455 + bool + depends on M5445X + default n + +choice + prompt "Model" + depends on M5445X + default M54451EVB + config M54451EVB + bool "M54451EVB" + select M54451 + config M54455EVB + bool "M54455EVB" + select M54455 +endchoice + +config HAVE_FSL_USB_DR + bool + default n + +config M547X_8X + bool "MCF547x/MCF548x support" + depends on COLDFIRE + help + This option will add support for the MCF547x/MCF548x processor with mmu. + +config M547X + bool + depends on M547X_8X + default n + +config M548X + bool + depends on M547X_8X + default n + +choice + prompt "Model" + depends on M547X_8X + default M5485CFE + +config M5474LITE + bool "MCF5474LITE" + select M547X +config M5475AFE + bool "MCF5475AFE" + select M547X +config M5475BFE + bool "MCF5475BFE" + select M547X +config M5475CFE + bool "MCF5475CFE" + select M547X +config M5475DFE + bool "MCF5475DFE" + select M547X +config M5475EFE + bool "MCF5475EFE" + select M547X +config M5475FFE + bool "MCF5475FFE" + select M547X +config M5484LITE + bool "MCF5484LITE" + select M548X +config M5485AFE + bool "MCF5485AFE" + select M548X +config M5485BFE + bool "MCF5485BFE" + select M548X +config M5485CFE + bool "MCF5485CFE" + select M548X +config M5485DFE + bool "MCF5485DFE" + select M548X +config M5485EFE + bool "MCF5485EFE" + select M548X +config M5485FFE + bool "MCF5485FFE" + select M548X + +endchoice + +config M5441X + bool "MCF5441x support" + depends on COLDFIRE + select GENERIC_TIME + select USB_EHCI_FSL + select HAVE_FSL_USB_DR + help + This option will add support for the MCF5441x processor with mmu. + +config M54418 + bool + depends on M5441X + default n +choice + prompt "Model" + depends on M5441X + default M54418EVB + config M54418EVB + bool "M54418EVB" + select M54418 +endchoice + +config MCFCLK + int + default 240000000 if M54451EVB + default 266666666 if M54455EVB + default 266000000 if M547X + default 200000000 if M548X + default 250000000 if M54418EVB && !USB_M5441X_PLLCLK + default 150000000 if M54418EVB && USB_M5441X_PLLCLK + help + Coldfire System clock. + +config MCF_USER_HALT + bool "Coldfire User Halt Enable" + depends on M5445X || M547X_8X || M5441X + default n + help + Enables the HALT instruction in User Mode. + config MMU_MOTOROLA bool @@ -283,6 +471,81 @@ config MMU_SUN3 bool depends on MMU && !MMU_MOTOROLA +config MMU_CFV4E + bool + +config SDRAM_BASE + hex + depends on COLDFIRE + default 0x40000000 if M5445X + default 0x00000000 if M547X_8X + default 0x40000000 if M5441X + +config SDRAM_SIZE + hex + depends on COLDFIRE + default 0x08000000 if M54451EVB + default 0x10000000 if M54455EVB + default 0x04000000 if M547X_8X + default 0x08000000 if M54418EVB + +config NOR_FLASH_BASE + hex "NOR Flash Base Address" + depends on COLDFIRE + default 0x00000000 if M54451EVB + default 0x00000000 if M54455EVB + default 0xE0000000 if M5475CFE + default 0xE0000000 if M5485CFE + default 0xFF800000 if M5484LITE + default 0xFF800000 if M5474LITE + default 0x00000000 if M54418EVB + +config DMA_BASE + hex + depends on COLDFIRE + default 0xef000000 if M5445X + default 0xef000000 if M547X_8X + default 0xdf000000 if M5441X + +config DMA_SIZE + hex + depends on COLDFIRE + default 0x1000000 if M5445X + default 0x800000 if M547X_8X + default 0x1000000 if M5441X + +config SRAM + bool "SRAM allocation APIs support on mcfv4 platform" + depends on COLDFIRE && (M5445X || M5441X) + default y + select GENERIC_ALLOCATOR + +config SRAM_BASE + hex + depends on COLDFIRE && SRAM + default 0x8ff00000 if M5445X + default 0x8ff00000 if M5441X + +config SRAM_SIZE + hex + depends on COLDFIRE && SRAM + default 0x8000 if M5445X + default 0x10000 if M5441X + +config SRAM_ALLOC_GRANULARITY + hex + depends on SRAM + default 0x200 if (M5445X || M5441X) + +config VDSO + bool "Support VDSO page" + depends on MMU + default n + help + This will enable support for the kernel mapping a vDSO page + in process space, and subsequently handing down the entry point + to the libc through the ELF auxiliary vector. + config M68KFPU_EMU bool "Math emulation support (EXPERIMENTAL)" depends on EXPERIMENTAL @@ -449,6 +712,14 @@ config ZONE_DMA source "drivers/pci/Kconfig" source "drivers/zorro/Kconfig" +endmenu + +menu "Power management options" + +config PM + bool "Power Management support" + help + Support processor power management modes endmenu @@ -583,7 +854,7 @@ config DN_SERIAL config SERIAL_CONSOLE bool "Support for serial port console" - depends on (AMIGA || ATARI || SUN3 || SUN3X || VME || APOLLO) && (ATARI_MFPSER=y || ATARI_MIDI=y || AMIGA_BUILTIN_SERIAL=y || GVPIOEXT=y || MULTIFACE_III_TTY=y || SERIAL=y || MVME147_SCC || SERIAL167 || MVME162_SCC || BVME6000_SCC || DN_SERIAL) + depends on (AMIGA || ATARI || SUN3 || SUN3X || VME || APOLLO || COLDFIRE) && (ATARI_MFPSER=y || ATARI_MIDI=y || AMIGA_BUILTIN_SERIAL=y || GVPIOEXT=y || MULTIFACE_III_TTY=y || SERIAL=y || MVME147_SCC || SERIAL167 || MVME162_SCC || BVME6000_SCC || DN_SERIAL || SERIAL_COLDFIRE) ---help--- If you say Y here, it will be possible to use a serial port as the system console (the system console is the device which receives all @@ -606,6 +877,8 @@ config SERIAL_CONSOLE endmenu +source "kernel/time/Kconfig" + source "fs/Kconfig" source "arch/m68k/Kconfig.debug" --- a/arch/m68k/Kconfig.debug +++ b/arch/m68k/Kconfig.debug @@ -2,4 +2,13 @@ menu "Kernel hacking" source "lib/Kconfig.debug" +config BOOTPARAM + bool 'Compiled-in Kernel Boot Parameter' + depends on COLDFIRE + +config BOOTPARAM_STRING + string 'Kernel Boot Parameter' + default 'console=ttyS0,115200' + depends on BOOTPARAM + endmenu --- a/arch/m68k/Makefile +++ b/arch/m68k/Makefile @@ -1,6 +1,8 @@ # # m68k/Makefile # +# Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved. +# # 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 @@ -10,13 +12,13 @@ # License. See the file "COPYING" in the main directory of this archive # for more details. # -# Copyright (C) 1994 by Hamish Macdonald -# -KBUILD_DEFCONFIG := multi_defconfig +KBUILD_DEFCONFIG := amiga_defconfig#multi_defconfig # override top level makefile +ifndef CONFIG_COLDFIRE AS += -m68020 +endif LDFLAGS := -m m68kelf KBUILD_LDFLAGS_MODULE += -T $(srctree)/arch/m68k/kernel/module.lds ifneq ($(SUBARCH),$(ARCH)) @@ -30,12 +32,18 @@ ifdef CONFIG_SUN3 LDFLAGS_vmlinux = -N endif +ifdef CONFIG_COLDFIRE +OBJCOPYFLAGS := -O binary -R .note -R .note.gnu.build-id -R .comment -S +# LDFLAGS_vmlinux = --verbose +endif + CHECKFLAGS += -D__mc68000__ # without -fno-strength-reduce the 53c7xx.c driver fails ;-( KBUILD_CFLAGS += -pipe -fno-strength-reduce -ffixed-a2 # enable processor switch if compiled only for a single cpu +ifndef CONFIG_COLDFIRE ifndef CONFIG_M68020 ifndef CONFIG_M68030 @@ -49,6 +57,22 @@ endif endif endif +endif + +ifdef CONFIG_M5445X +KBUILD_CFLAGS += -march=isac -mcpu=54455 -msoft-float -g +KBUILD_AFLAGS += -march=isac -mcpu=54455 -msoft-float +endif + +ifdef CONFIG_M547X_8X +KBUILD_CFLAGS += -mcfv4e -g +KBUILD_AFLAGS += -mcfv4e +endif + +ifdef CONFIG_M5441X +KBUILD_CFLAGS += -march=isac -mcpu=54418 -msoft-float -g +KBUILD_AFLAGS += -march=isac -mcpu=54418 -msoft-float +endif ifdef CONFIG_KGDB # If configured for kgdb support, include debugging infos and keep the @@ -57,8 +81,12 @@ KBUILD_CFLAGS := $(subst -fomit-frame-po endif ifndef CONFIG_SUN3 +ifndef CONFIG_COLDFIRE head-y := arch/m68k/kernel/head.o else +head-y := arch/m68k/coldfire/common/head.o +endif +else head-y := arch/m68k/kernel/sun3-head.o endif @@ -79,7 +107,20 @@ core-$(CONFIG_SUN3) += arch/m68k/sun3/ core-$(CONFIG_M68040) += arch/m68k/fpsp040/ core-$(CONFIG_M68060) += arch/m68k/ifpsp060/ core-$(CONFIG_M68KFPU_EMU) += arch/m68k/math-emu/ +core-$(CONFIG_COLDFIRE) += arch/m68k/coldfire/ + +ifdef CONFIG_COLDFIRE +boot := arch/m68k/boot + +all: uImage +zImage zImage.srec uImage uImage.srec vmlinux.srec: vmlinux + $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ + +archclean: + $(Q)$(MAKE) $(clean)=$(boot) + +else all: zImage lilo: vmlinux @@ -117,6 +158,7 @@ endif archclean: rm -f vmlinux.gz vmlinux.bz2 +endif install: sh $(srctree)/arch/m68k/install.sh $(KERNELRELEASE) vmlinux.gz System.map "$(INSTALL_PATH)" --- /dev/null +++ b/arch/m68k/boot/Makefile @@ -0,0 +1,68 @@ +# +# arch/m68k/boot/Makefile +# +# Based on arch/sh/boot/Makefile by Stuart Menefy +# +# Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved. +# by Kurt Mahan +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# + +MKIMAGE := $(srctree)/scripts/mkuboot.sh + +# +# Assign safe dummy values if these variables are not defined, +# in order to suppress error message. +# +CONFIG_SDRAM_BASE ?= 0x40000000 +CONFIG_IMG_START ?= 0x00020000 + +export CONFIG_SDRAM_BASE CONFIG_IMG_START + +targets := zImage zImage.srec vmlinux.srec uImage uImage.srec + +$(obj)/zImage: $(obj)/vmlinux.bin FORCE + $(call if_changed,gzip) + @echo ' Image $@ is ready' + +OBJCOPYFLAGS_zImage.srec := -I binary -O srec +$(obj)/zImage.srec: $(obj)/zImage + $(call if_changed,objcopy) + +KERNEL_LOAD := $(shell /bin/bash -c 'printf "0x%08x" \ + $$[$(CONFIG_SDRAM_BASE) + \ + $(CONFIG_IMG_START)]') + +KERNEL_ENTRY := $(shell /bin/bash -c 'printf "0x%08x" \ + $$[$(CONFIG_SDRAM_BASE) + \ + $(CONFIG_IMG_START)]') + +quiet_cmd_uimage = UIMAGE $@ + cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A m68k -O linux -T kernel \ + -C gzip -a $(KERNEL_LOAD) -e $(KERNEL_ENTRY) \ + -n 'Linux-$(KERNELRELEASE)' -d $< $@ + +$(obj)/uImage: $(obj)/vmlinux.bin.gz FORCE + $(call if_changed,uimage) + @echo ' Image $@ is ready' + +$(obj)/vmlinux.bin: vmlinux FORCE + $(call if_changed,objcopy) + +$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE + $(call if_changed,gzip) + +OBJCOPYFLAGS_vmlinux.srec := -I binary -O srec +$(obj)/vmlinux.srec: $(obj)/vmlinux.bin + $(call if_changed,objcopy) + +OBJCOPYFLAGS_uImage.srec := -I binary -O srec +$(obj)/uImage.srec: $(obj)/uImage + $(call if_changed,objcopy) + +clean-files += uImage uImage.srec \ + zImage zImage.srec \ + vmlinux.srec vmlinux.bin vmlinux.bin.gz --- /dev/null +++ b/arch/m68k/coldfire/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for Linux arch/m68k/coldfire source directory +# + +obj-y += common/ +obj-$(CONFIG_VDSO) += vdso/ + +obj-$(CONFIG_M5445X) += m5445x/ +obj-$(CONFIG_M547X_8X) += m547x/ +obj-$(CONFIG_M5441X) += m5441x/ --- /dev/null +++ b/arch/m68k/coldfire/common/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for Linux arch/m68k/coldfire/common source directory +# + +obj-y:= entry.o cache.o signal.o muldi3.o traps.o ints.o clk.o +extra-y:= head.o + --- /dev/null +++ b/arch/m68k/coldfire/common/cache.c @@ -0,0 +1,45 @@ +/* + * linux/arch/m68k/coldfire/cache.c + * + * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Matt Waddel Matt.Waddel@freescale.com + * Kurt Mahan kmahan@freescale.com + * Jason Jin Jason.Jin@freescale.com + * Shrek Wu B16972@freescale.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 +#include +#include +#include + +/* Cache Control Reg shadow reg */ +unsigned long shadow_cacr; + +/** + * cacr_set - Set the Cache Control Register + * @x Value to set + */ +void cacr_set(unsigned long x) +{ + shadow_cacr = x; + + __asm__ __volatile__ ("movec %0, %%cacr" + : /* no outputs */ + : "r" (shadow_cacr)); +} + +/** + * cacr_get - Get the current value of the Cache Control Register + * + * @return CACR value + */ +unsigned long cacr_get(void) +{ + return shadow_cacr; +} --- /dev/null +++ b/arch/m68k/coldfire/common/clk.c @@ -0,0 +1,51 @@ +/***************************************************************************/ + +/* + * clk.c -- general ColdFire CPU kernel clk handling + * + * Copyright (C) 2009, Greg Ungerer (gerg@snapgear.com) + * Copyright (C) 2011 Freescale Semiconductore, Inc. All Rights Reserved. + * + * 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 +#include +#include +#include + +/***************************************************************************/ + +struct clk *clk_get(struct device *dev, const char *id) +{ + return NULL; +} +EXPORT_SYMBOL(clk_get); + +int clk_enable(struct clk *clk) +{ + return 0; +} +EXPORT_SYMBOL(clk_enable); + +void clk_disable(struct clk *clk) +{ +} +EXPORT_SYMBOL(clk_disable); + +void clk_put(struct clk *clk) +{ +} +EXPORT_SYMBOL(clk_put); + +unsigned long clk_get_rate(struct clk *clk) +{ + return MCF_CLK; +} +EXPORT_SYMBOL(clk_get_rate); +/***************************************************************************/ --- /dev/null +++ b/arch/m68k/coldfire/common/entry.S @@ -0,0 +1,745 @@ +/* + * arch/m68k/coldfire/entry.S + * + * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Matt Waddel Matt.Waddel@freescale.com + * Kurt Mahan kmahan@freescale.com + * Jason Jin Jason.Jin@freescale.com + * Shrek Wu B16972@freescale.com + * + * Based on: + * + * arch/m68knommu/platform/5307/entry.S & + * arch/m68k/kernel/entry.S + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * TASK_INFO: + * + * - TINFO_PREEMPT (struct thread_info / preempt_count) + * Used to keep track of preemptability + * - TINFO_FLAGS (struct thread_info / flags - include/asm-m68k/thread_info.h) + * Various bit flags that are checked for scheduling/tracing + * Bits 0-7 are checked every exception exit + * 8-15 are checked every syscall exit + * + * TIF_SIGPENDING 6 + * TIF_NEED_RESCHED 7 + * TIF_DELAYED_TRACE 14 + * TIF_SYSCALL_TRACE 15 + * TIF_MEMDIE 16 (never checked here) + */ + +.bss + +sw_ksp: +.long 0 + +sw_usp: +.long 0 + +.text + +.globl system_call +.globl buserr +.globl trap +.globl resume +.globl ret_from_exception +.globl ret_from_signal +.globl sys_call_table +.globl ret_from_interrupt +.globl inthandler + +ENTRY(buserr) +#ifdef CONFIG_COLDFIRE_FOO + movew #0x2700,%sr /* lock interrupts */ +#endif + SAVE_ALL_INT +#ifdef CONFIG_COLDFIRE_FOO + movew PT_0FF_SR(%sp),%d3 /* get original %sr */ + oril #0x2000,%d3 /* set supervisor mode in it */ + movew %d3,%sr /* recover irq state */ +#endif + GET_CURRENT(%d0) + movel %sp,%sp@- /* stack frame pointer argument */ + jsr buserr_c + addql #4,%sp + jra .Lret_from_exception + +ENTRY(trap) + SAVE_ALL_INT + GET_CURRENT(%d0) + movel %sp,%sp@- /* stack frame pointer argument */ + jsr trap_c + addql #4,%sp + jra .Lret_from_exception + + /* After a fork we jump here directly from resume, + %d1 contains the previous task schedule_tail */ +ENTRY(ret_from_fork) + movel %d1,%sp@- + jsr schedule_tail + addql #4,%sp + jra .Lret_from_exception + +do_trace_entry: + movel #-ENOSYS,%d1 /* needed for strace */ + movel %d1,%sp@(PT_OFF_D0) + subql #4,%sp + SAVE_SWITCH_STACK + jbsr syscall_trace + RESTORE_SWITCH_STACK + addql #4,%sp + movel %sp@(PT_OFF_ORIG_D0),%d0 + cmpl #NR_syscalls,%d0 + jcs syscall +badsys: + movel #-ENOSYS,%d1 + movel %d1,%sp@(PT_OFF_D0) + jra ret_from_exception + +do_trace_exit: + subql #4,%sp + SAVE_SWITCH_STACK + jbsr syscall_trace + RESTORE_SWITCH_STACK + addql #4,%sp + jra .Lret_from_exception + +ENTRY(ret_from_signal) + RESTORE_SWITCH_STACK + addql #4,%sp + jra .Lret_from_exception + +ENTRY(system_call) + SAVE_ALL_SYS + + GET_CURRENT(%d1) + /* save top of frame */ + movel %sp,%curptr@(TASK_THREAD+THREAD_ESP0) + + /* syscall trace */ + tstb %curptr@(TASK_INFO+TINFO_FLAGS+2) + jmi do_trace_entry /* SYSCALL_TRACE is set */ + cmpl #NR_syscalls,%d0 + jcc badsys +syscall: + movel #sys_call_table,%a0 + asll #2,%d0 + addl %d0,%a0 + movel %a0@,%a0 + jsr %a0@ + movel %d0,%sp@(PT_OFF_D0) /* save the return value */ +ret_from_syscall: + movew %curptr@(TASK_INFO+TINFO_FLAGS+2),%d0 + jne syscall_exit_work /* flags set so process */ +1: RESTORE_ALL + +syscall_exit_work: + btst #5,%sp@(PT_OFF_SR) /* check if returning to kernel */ + bnes 1b /* if so, skip resched, signals */ + + btstl #15,%d0 /* check if SYSCALL_TRACE */ + jne do_trace_exit + btstl #14,%d0 /* check if DELAYED_TRACE */ + jne do_delayed_trace + btstl #6,%d0 /* check if SIGPENDING */ + jne do_signal_return + pea resume_userspace + jra schedule + +ENTRY(ret_from_exception) +.Lret_from_exception: + btst #5,%sp@(PT_OFF_SR) /* check if returning to kernel */ + bnes 1f /* if so, skip resched, signals */ + movel %d0,%sp@- /* Only allow interrupts when we are */ + move %sr,%d0 /* last one on the kernel stack, */ + andl #ALLOWINT,%d0 /* otherwise stack overflow can occur */ + move %d0,%sr /* during heavy interrupt load. */ + movel %sp@+,%d0 + +resume_userspace: + moveb %curptr@(TASK_INFO+TINFO_FLAGS+3),%d0 + jne exit_work /* SIGPENDING and/or NEED_RESCHED set */ +1: RESTORE_ALL + +exit_work: + /* save top of frame */ + movel %sp,%curptr@(TASK_THREAD+THREAD_ESP0) + btstl #6,%d0 /* check for SIGPENDING in flags */ + jne do_signal_return + pea resume_userspace + jra schedule + +do_signal_return: + subql #4,%sp /* dummy return address */ + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + clrl %sp@- + bsrl do_signal + addql #8,%sp + RESTORE_SWITCH_STACK + addql #4,%sp + jbra resume_userspace + +do_delayed_trace: + bclr #7,%sp@(PT_OFF_SR) /* clear trace bit in SR */ + pea 1 /* send SIGTRAP */ + movel %curptr,%sp@- + pea LSIGTRAP + jbsr send_sig + addql #8,%sp + addql #4,%sp + jbra resume_userspace + +/* + * This is the interrupt handler (for all hardware interrupt + * sources). It figures out the vector number and calls the appropriate + * interrupt service routine directly. + */ +ENTRY(inthandler) + SAVE_ALL_INT + GET_CURRENT(%d0) + movel %curptr@(TASK_INFO+TINFO_PREEMPT),%d0 + addil #0x10000,%d0 + movel %d0,%curptr@(TASK_INFO+TINFO_PREEMPT) + /* put exception # in d0 */ + movel %sp@(PT_VECTOR),%d0 + swap %d0 /* extract bits 25:18 */ + lsrl #2,%d0 + andl #0x0ff,%d0 + + movel %sp,%sp@- + movel %d0,%sp@- /* put vector # on stack */ +auto_irqhandler_fixup = . + 2 + jbsr process_int /* process the IRQ */ + addql #8,%sp /* pop parameters off stack */ + +ret_from_interrupt: + + movel %curptr@(TASK_INFO+TINFO_PREEMPT),%d0 + subil #0x10000,%d0 + movel %d0,%curptr@(TASK_INFO+TINFO_PREEMPT) + jeq ret_from_last_interrupt +2: RESTORE_ALL + + ALIGN +ret_from_last_interrupt: + moveb %sp@(PT_OFF_SR),%d0 + andl #(~ALLOWINT>>8)&0xff,%d0 + jne 2b + + /* check if we need to do software interrupts */ + tstl irq_stat+CPUSTAT_SOFTIRQ_PENDING + jeq .Lret_from_exception + pea ret_from_exception + jra do_softirq + +ENTRY(user_inthandler) + SAVE_ALL_INT + GET_CURRENT(%d0) + movel %curptr@(TASK_INFO+TINFO_PREEMPT),%d0 + addil #0x10000,%d0 + movel %d0,%curptr@(TASK_INFO+TINFO_PREEMPT) + /* put exception # in d0 */ + movel %sp@(PT_VECTOR),%d0 +user_irqvec_fixup = . + 2 + swap %d0 /* extract bits 25:18 */ + lsrl #2,%d0 + andl #0x0ff,%d0 + + movel %sp,%sp@- + movel %d0,%sp@- /* put vector # on stack */ +user_irqhandler_fixup = . + 2 + jbsr process_int /* process the IRQ */ + addql #8,%sp /* pop parameters off stack */ + + movel %curptr@(TASK_INFO+TINFO_PREEMPT),%d0 + subil #0x10000,%d0 + movel %d0,%curptr@(TASK_INFO+TINFO_PREEMPT) + jeq ret_from_last_interrupt + RESTORE_ALL + +/* Handler for uninitialized and spurious interrupts */ + +ENTRY(bad_inthandler) + SAVE_ALL_INT + GET_CURRENT(%d0) + movel %curptr@(TASK_INFO+TINFO_PREEMPT),%d0 + addil #0x10000,%d0 + movel %d0,%curptr@(TASK_INFO+TINFO_PREEMPT) + + movel %sp,%sp@- + jsr handle_badint + addql #4,%sp + + movel %curptr@(TASK_INFO+TINFO_PREEMPT),%d0 + subil #0x10000,%d0 + movel %d0,%curptr@(TASK_INFO+TINFO_PREEMPT) + jeq ret_from_last_interrupt + RESTORE_ALL + +ENTRY(sys_fork) + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + jbsr m68k_fork + addql #4,%sp + RESTORE_SWITCH_STACK + rts + +ENTRY(sys_clone) + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + jbsr m68k_clone + addql #4,%sp + RESTORE_SWITCH_STACK + rts + +ENTRY(sys_vfork) + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + jbsr m68k_vfork + addql #4,%sp + RESTORE_SWITCH_STACK + rts + +ENTRY(sys_sigsuspend) + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + jbsr do_sigsuspend + addql #4,%sp + RESTORE_SWITCH_STACK + rts + +ENTRY(sys_sigreturn) + SAVE_SWITCH_STACK + jbsr do_sigreturn + RESTORE_SWITCH_STACK + rts + +ENTRY(sys_rt_sigreturn) + SAVE_SWITCH_STACK + jbsr do_rt_sigreturn + RESTORE_SWITCH_STACK + rts + +resume: + /* + * Beware - when entering resume, prev (the current task) is + * in a0, next (the new task) is in a1,so don't change these + * registers until their contents are no longer needed. + */ + + /* save sr */ + movew %sr,%d0 + movew %d0,%a0@(TASK_THREAD+THREAD_SR) + + /* save usp */ + /* Save USP via %a1 (which is saved/restored from %d0) */ + movel %a1,%d0 + movel %usp,%a1 + movel %a1,%a0@(TASK_THREAD+THREAD_USP) + movel %d0,%a1 + + /* save non-scratch registers on stack */ + SAVE_SWITCH_STACK + + /* save current kernel stack pointer */ + movel %sp,%a0@(TASK_THREAD+THREAD_KSP) +#ifdef CONFIG_FPU + /* save floating point context */ + fsave %a0@(TASK_THREAD+THREAD_FPSTATE) + +1: tstb %a0@(TASK_THREAD+THREAD_FPSTATE) + jeq 3f +2: + fmovemd %fp0-%fp7,%a0@(TASK_THREAD+THREAD_FPREG) +3: +#endif + /* Return previous task in %d1 */ + movel %curptr,%d1 + + /* switch to new task (a1 contains new task) */ + movel %a1,%curptr +#ifdef CONFIG_FPU + /* restore floating point context */ +1: tstb %a1@(TASK_THREAD+THREAD_FPSTATE) + jeq 3f +2: + fmovemd %a1@(TASK_THREAD+THREAD_FPREG),%fp0-%fp7 +/* frestore %a1@(TASK_THREAD+THREAD_FPCNTL)*/ +3: frestore %a1@(TASK_THREAD+THREAD_FPSTATE) +#endif + /* restore the kernel stack pointer */ + movel %a1@(TASK_THREAD+THREAD_KSP),%sp + + /* restore non-scratch registers */ + RESTORE_SWITCH_STACK + + /* restore user stack pointer */ + movel %a1@(TASK_THREAD+THREAD_USP),%a0 + movel %a0,%usp + + /* restore status register */ + movew %a1@(TASK_THREAD+THREAD_SR),%d0 + movew %d0,%sr + + rts + +.data +ALIGN +sys_call_table: + .long sys_ni_syscall /* 0 - old "setup()" system call*/ + .long sys_exit + .long sys_fork + .long sys_read + .long sys_write + .long sys_open /* 5 */ + .long sys_close + .long sys_waitpid + .long sys_creat + .long sys_link + .long sys_unlink /* 10 */ + .long sys_execve + .long sys_chdir + .long sys_time + .long sys_mknod + .long sys_chmod /* 15 */ + .long sys_chown16 + .long sys_ni_syscall /* old break syscall holder */ + .long sys_stat + .long sys_lseek + .long sys_getpid /* 20 */ + .long sys_mount + .long sys_oldumount + .long sys_setuid16 + .long sys_getuid16 + .long sys_stime /* 25 */ + .long sys_ptrace + .long sys_alarm + .long sys_fstat + .long sys_pause + .long sys_utime /* 30 */ + .long sys_ni_syscall /* old stty syscall holder */ + .long sys_ni_syscall /* old gtty syscall holder */ + .long sys_access + .long sys_nice + .long sys_ni_syscall /* 35 */ /* old ftime syscall holder */ + .long sys_sync + .long sys_kill + .long sys_rename + .long sys_mkdir + .long sys_rmdir /* 40 */ + .long sys_dup + .long sys_pipe + .long sys_times + .long sys_ni_syscall /* old prof syscall holder */ + .long sys_brk /* 45 */ + .long sys_setgid16 + .long sys_getgid16 + .long sys_signal + .long sys_geteuid16 + .long sys_getegid16 /* 50 */ + .long sys_acct + .long sys_umount /* recycled never used phys() */ + .long sys_ni_syscall /* old lock syscall holder */ + .long sys_ioctl + .long sys_fcntl /* 55 */ + .long sys_ni_syscall /* old mpx syscall holder */ + .long sys_setpgid + .long sys_ni_syscall /* old ulimit syscall holder */ + .long sys_ni_syscall + .long sys_umask /* 60 */ + .long sys_chroot + .long sys_ustat + .long sys_dup2 + .long sys_getppid + .long sys_getpgrp /* 65 */ + .long sys_setsid + .long sys_sigaction + .long sys_sgetmask + .long sys_ssetmask + .long sys_setreuid16 /* 70 */ + .long sys_setregid16 + .long sys_sigsuspend + .long sys_sigpending + .long sys_sethostname + .long sys_setrlimit /* 75 */ + .long sys_old_getrlimit + .long sys_getrusage + .long sys_gettimeofday + .long sys_settimeofday + .long sys_getgroups16 /* 80 */ + .long sys_setgroups16 + .long old_select + .long sys_symlink + .long sys_lstat + .long sys_readlink /* 85 */ + .long sys_uselib + .long sys_swapon + .long sys_reboot + .long sys_old_readdir + .long old_mmap /* 90 */ + .long sys_munmap + .long sys_truncate + .long sys_ftruncate + .long sys_fchmod + .long sys_fchown16 /* 95 */ + .long sys_getpriority + .long sys_setpriority + .long sys_ni_syscall /* old profil syscall holder */ + .long sys_statfs + .long sys_fstatfs /* 100 */ + .long sys_ni_syscall /* ioperm for i386 */ + .long sys_socketcall + .long sys_syslog + .long sys_setitimer + .long sys_getitimer /* 105 */ + .long sys_newstat + .long sys_newlstat + .long sys_newfstat + .long sys_ni_syscall + .long sys_ni_syscall /* 110 */ /* iopl for i386 */ + .long sys_vhangup + .long sys_ni_syscall /* obsolete idle() syscall */ + .long sys_ni_syscall /* vm86old for i386 */ + .long sys_wait4 + .long sys_swapoff /* 115 */ + .long sys_sysinfo + .long sys_ipc + .long sys_fsync + .long sys_sigreturn + .long sys_clone /* 120 */ + .long sys_setdomainname + .long sys_newuname + .long sys_cacheflush /* modify_ldt for i386 */ + .long sys_adjtimex + .long sys_mprotect /* 125 */ + .long sys_sigprocmask + .long sys_ni_syscall /* old "create_module" */ + .long sys_init_module + .long sys_delete_module + .long sys_ni_syscall /* 130 - old "get_kernel_syms" */ + .long sys_quotactl + .long sys_getpgid + .long sys_fchdir + .long sys_bdflush + .long sys_sysfs /* 135 */ + .long sys_personality + .long sys_ni_syscall /* for afs_syscall */ + .long sys_setfsuid16 + .long sys_setfsgid16 + .long sys_llseek /* 140 */ + .long sys_getdents + .long sys_select + .long sys_flock + .long sys_msync + .long sys_readv /* 145 */ + .long sys_writev + .long sys_getsid + .long sys_fdatasync + .long sys_sysctl + .long sys_mlock /* 150 */ + .long sys_munlock + .long sys_mlockall + .long sys_munlockall + .long sys_sched_setparam + .long sys_sched_getparam /* 155 */ + .long sys_sched_setscheduler + .long sys_sched_getscheduler + .long sys_sched_yield + .long sys_sched_get_priority_max + .long sys_sched_get_priority_min /* 160 */ + .long sys_sched_rr_get_interval + .long sys_nanosleep + .long sys_mremap + .long sys_setresuid16 + .long sys_getresuid16 /* 165 */ + .long sys_getpagesize + .long sys_ni_syscall /* old sys_query_module */ + .long sys_poll + .long sys_nfsservctl + .long sys_setresgid16 /* 170 */ + .long sys_getresgid16 + .long sys_prctl + .long sys_rt_sigreturn + .long sys_rt_sigaction + .long sys_rt_sigprocmask /* 175 */ + .long sys_rt_sigpending + .long sys_rt_sigtimedwait + .long sys_rt_sigqueueinfo + .long sys_rt_sigsuspend + .long sys_pread64 /* 180 */ + .long sys_pwrite64 + .long sys_lchown16; + .long sys_getcwd + .long sys_capget + .long sys_capset /* 185 */ + .long sys_sigaltstack + .long sys_sendfile + .long sys_ni_syscall /* streams1 */ + .long sys_ni_syscall /* streams2 */ + .long sys_vfork /* 190 */ + .long sys_getrlimit + .long sys_mmap2 + .long sys_truncate64 + .long sys_ftruncate64 + .long sys_stat64 /* 195 */ + .long sys_lstat64 + .long sys_fstat64 + .long sys_chown + .long sys_getuid + .long sys_getgid /* 200 */ + .long sys_geteuid + .long sys_getegid + .long sys_setreuid + .long sys_setregid + .long sys_getgroups /* 205 */ + .long sys_setgroups + .long sys_fchown + .long sys_setresuid + .long sys_getresuid + .long sys_setresgid /* 210 */ + .long sys_getresgid + .long sys_lchown + .long sys_setuid + .long sys_setgid + .long sys_setfsuid /* 215 */ + .long sys_setfsgid + .long sys_pivot_root + .long sys_ni_syscall + .long sys_ni_syscall + .long sys_getdents64 /* 220 */ + .long sys_gettid + .long sys_tkill + .long sys_setxattr + .long sys_lsetxattr + .long sys_fsetxattr /* 225 */ + .long sys_getxattr + .long sys_lgetxattr + .long sys_fgetxattr + .long sys_listxattr + .long sys_llistxattr /* 230 */ + .long sys_flistxattr + .long sys_removexattr + .long sys_lremovexattr + .long sys_fremovexattr + .long sys_futex /* 235 */ + .long sys_sendfile64 + .long sys_mincore + .long sys_madvise + .long sys_fcntl64 + .long sys_readahead /* 240 */ + .long sys_io_setup + .long sys_io_destroy + .long sys_io_getevents + .long sys_io_submit + .long sys_io_cancel /* 245 */ + .long sys_fadvise64 + .long sys_exit_group + .long sys_lookup_dcookie + .long sys_epoll_create + .long sys_epoll_ctl /* 250 */ + .long sys_epoll_wait + .long sys_remap_file_pages + .long sys_set_tid_address + .long sys_timer_create + .long sys_timer_settime /* 255 */ + .long sys_timer_gettime + .long sys_timer_getoverrun + .long sys_timer_delete + .long sys_clock_settime + .long sys_clock_gettime /* 260 */ + .long sys_clock_getres + .long sys_clock_nanosleep + .long sys_statfs64 + .long sys_fstatfs64 + .long sys_tgkill /* 265 */ + .long sys_utimes + .long sys_fadvise64_64 + .long sys_mbind + .long sys_get_mempolicy + .long sys_set_mempolicy /* 270 */ + .long sys_mq_open + .long sys_mq_unlink + .long sys_mq_timedsend + .long sys_mq_timedreceive + .long sys_mq_notify /* 275 */ + .long sys_mq_getsetattr + .long sys_waitid + .long sys_ni_syscall /* for sys_vserver */ + .long sys_add_key + .long sys_request_key /* 280 */ + .long sys_keyctl + .long sys_ioprio_set + .long sys_ioprio_get + .long sys_inotify_init + .long sys_inotify_add_watch /* 285 */ + .long sys_inotify_rm_watch + .long sys_migrate_pages + .long sys_openat + .long sys_mkdirat + .long sys_mknodat /* 290 */ + .long sys_fchownat + .long sys_futimesat + .long sys_fstatat64 + .long sys_unlinkat + .long sys_renameat /* 295 */ + .long sys_linkat + .long sys_symlinkat + .long sys_readlinkat + .long sys_fchmodat + .long sys_faccessat /* 300 */ + .long sys_ni_syscall /* Reserved for pselect6 */ + .long sys_ni_syscall /* Reserved for ppoll */ + .long sys_unshare + .long sys_set_robust_list + .long sys_get_robust_list /* 305 */ + .long sys_splice + .long sys_sync_file_range + .long sys_tee + .long sys_vmsplice + .long sys_move_pages /* 310 */ + .long sys_sched_setaffinity + .long sys_sched_getaffinity + .long sys_kexec_load + .long sys_getcpu + .long sys_epoll_pwait /* 315 */ + .long sys_utimensat + .long sys_signalfd + .long sys_timerfd_create + .long sys_eventfd + .long sys_fallocate /* 320 */ + .long sys_timerfd_settime + .long sys_timerfd_gettime + .long sys_signalfd4 + .long sys_eventfd2 + .long sys_epoll_create1 /* 325 */ + .long sys_dup3 + .long sys_pipe2 + .long sys_inotify_init1 + .long sys_preadv + .long sys_pwritev /* 330 */ + .long sys_rt_tgsigqueueinfo + .long sys_perf_event_open + .long sys_get_thread_area + .long sys_set_thread_area + .long sys_atomic_cmpxchg_32 /* 335 */ + .long sys_atomic_barrier + .long sys_fanotify_init + .long sys_fanotify_mark + .long sys_prlimit64 --- /dev/null +++ b/arch/m68k/coldfire/common/head.S @@ -0,0 +1,466 @@ +/* + * head.S is the MMU enabled ColdFire specific initial boot code + * + * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Matt Waddel Matt.Waddel@freescale.com + * Kurt Mahan kmahan@freescale.com + * Jason Jin Jason.Jin@freescale.com + * Shrek Wu B16972@freescale.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. + * + * Parts of this code came from arch/m68k/kernel/head.S + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG + +.globl kernel_pg_dir +.globl availmem +.globl set_context +.globl set_fpga + +#ifdef DEBUG +/* When debugging use readable names for labels */ +#ifdef __STDC__ +#define L(name) .head.S.##name +#else +#define L(name) .head.S./**/name +#endif +#else +#ifdef __STDC__ +#define L(name) .L##name +#else +#define L(name) .L/**/name +#endif +#endif + +/* The __INITDATA stuff is a no-op when ftrace or kgdb are turned on */ +#ifndef __INITDATA +#define __INITDATA .data +#define __FINIT .previous +#endif + +/* + * Kernel mapped to physical ram address. + * + * M5445x: + * Data[0]: 0xF0000000 -> 0xFFFFFFFF System regs + * Data[1]: 0x40000000 -> 0x4FFFFFFF SDRAM - cached + * Code[0]: Not Mapped + * Code[1]: 0x40000000 -> 0x4FFFFFFF SDRAM - cached + * + * M547x/M548x + * Data[0]: 0xF0000000 -> 0xFFFFFFFF System regs + * Data[1]: 0x00000000 -> 0x0FFFFFFF SDRAM - uncached + * Code[0]: Not Mapped + * Code[1]: 0x00000000 -> 0x0FFFFFFF SDRAM - cached + * + * M5441X: + * Data[0]: 0xE0000000 -> 0xFFFFFFFF System regs + * Data[1]: 0x40000000 -> 0x4FFFFFFF SDRAM - cached + * Code[0]: Not Mapped + * Code[1]: 0x40000000 -> 0x4FFFFFFF SDRAM - cached + */ +#if defined(CONFIG_M5445X) +#define ACR0_DEFAULT #0xF00FA048 /* System Regs uncached/precise */ +#define ACR1_DEFAULT #0x400FA028 /* SDRAM cached/copyback */ +#define ACR2_DEFAULT #0x00000000 /* Not mapped */ +#define ACR3_DEFAULT #0x400FA028 /* SDRAM cached/copyback */ +#elif defined(CONFIG_M547X_8X) +#define ACR0_DEFAULT #0xF00FA048 /* System Regs */ +#define ACR1_DEFAULT #0x000FA028 /* SDRAM cached/copy-back */ +#define ACR2_DEFAULT #0x00000000 /* Not mapped */ +#define ACR3_DEFAULT #0x000FA028 /* Instruction cached/copy-back */ +#elif defined(CONFIG_M5441X) +#define ACR0_DEFAULT #0xE01FA048 /* System Regs */ +#define ACR1_DEFAULT #0x400FA028 /* SDRAM cached/copyback */ +#define ACR4_DEFAULT #0x00000000 /* Not mapped */ +#define ACR5_DEFAULT #0x00000000 /* Not mapped */ +#define ACR2_DEFAULT #0x00000000 /* Not mapped */ +#define ACR3_DEFAULT #0x400FA028 /* Instruction cached/copy-back */ +#define ACR6_DEFAULT #0x00000000 /* Not mapped */ +#define ACR7_DEFAULT #0x00000000 /* Not mapped */ +#endif + +/* ACR mapping for FPGA (maps 0) */ +#define ACR0_FPGA #0x000FA048 /* ACR0 enable FPGA */ + +/* Several macros to make the writing of subroutines easier: + * - func_start marks the beginning of the routine which setups the frame + * register and saves the registers, it also defines another macro + * to automatically restore the registers again. + * - func_return marks the end of the routine and simply calls the prepared + * macro to restore registers and jump back to the caller. + * - func_define generates another macro to automatically put arguments + * onto the stack call the subroutine and cleanup the stack again. + */ + +.macro load_symbol_address symbol,register + movel #\symbol,\register +.endm + +.macro func_start name,saveregs,savesize,stack=0 +L(\name): + linkw %a6,#-\stack + subal #(\savesize),%sp + moveml \saveregs,%sp@ +.set stackstart,-\stack + +.macro func_return_\name + moveml %sp@,\saveregs + addal #(\savesize),%sp + unlk %a6 + rts +.endm +.endm + +.macro func_return name + func_return_\name +.endm + +.macro func_call name + jbsr L(\name) +.endm + +.macro move_stack nr,arg1,arg2,arg3,arg4 +.if \nr + move_stack "(\nr-1)",\arg2,\arg3,\arg4 + movel \arg1,%sp@- +.endif +.endm + +.macro func_define name,nr=0 +.macro \name arg1,arg2,arg3,arg4 + move_stack \nr,\arg1,\arg2,\arg3,\arg4 + func_call \name +.if \nr + lea %sp@(\nr*4),%sp +.endif +.endm +.endm + +func_define serial_putc,1 + +.macro putc ch + pea \ch + func_call serial_putc + addql #4,%sp +.endm + +.macro dputc ch +#ifdef DEBUG + putc \ch +#endif +.endm + +func_define putn,1 + +.macro dputn nr +#ifdef DEBUG + putn \nr +#endif +.endm + +/* + mmu_map - creates a new TLB entry + + virt_addr Must be on proper boundary + phys_addr Must be on proper boundary + itlb MMUOR_ITLB if instruction TLB or 0 + asid address space ID + shared_global MMUTR_SG if shared between different ASIDs or 0 + size_code MMUDR_SZ1M 1 MB + MMUDR_SZ4K 4 KB + MMUDR_SZ8K 8 KB + MMUDR_SZ16M 16 MB + cache_mode MMUDR_INC instruction non-cacheable + MMUDR_IC instruction cacheable + MMUDR_DWT data writethrough + MMUDR_DCB data copyback + MMUDR_DNCP data non-cacheable, precise + MMUDR_DNCIP data non-cacheable, imprecise + super_prot MMUDR_SP if user mode generates exception or 0 + readable MMUDR_R if permits read access (data TLB) or 0 + writable MMUDR_W if permits write access (data TLB) or 0 + executable MMUDR_X if permits execute access (instruction TLB) or 0 + locked MMUDR_LK prevents TLB entry from being replaced or 0 + temp_data_reg a data register to use for temporary values +*/ +.macro mmu_map virt_addr,phys_addr,itlb,asid,shared_global,size_code, \ + cache_mode,super_prot,readable,writable,executable,locked,temp_data_reg + /* Set up search of TLB. */ + movel #(\virt_addr+1), \temp_data_reg + movel \temp_data_reg, MMUAR + /* Search. */ + movel #(MMUOR_STLB + MMUOR_ADR +\itlb), \temp_data_reg + movew \temp_data_reg, (MMUOR) + /* Set up tag value. */ + movel #(\virt_addr + \asid + \shared_global + MMUTR_V), \temp_data_reg + movel \temp_data_reg, MMUTR + /* Set up data value. */ + movel #(\phys_addr + \size_code + \cache_mode + \super_prot + \ + \readable + \writable + \executable + \locked), \temp_data_reg + movel \temp_data_reg, MMUDR + /* Save it. */ + movel #(MMUOR_ACC + MMUOR_UAA + \itlb), \temp_data_reg + movew \temp_data_reg, (MMUOR) +.endm /* mmu_map */ + +.macro mmu_unmap virt_addr,itlb,temp_data_reg + /* Set up search of TLB. */ + movel #(\virt_addr+1), \temp_data_reg + movel \temp_data_reg, MMUAR + /* Search. */ + movel #(MMUOR_STLB + MMUOR_ADR +\itlb), \temp_data_reg + movew \temp_data_reg, (MMUOR) + /* Test for hit. */ + movel MMUSR,\temp_data_reg + btst #MMUSR_HITN,\temp_data_reg + beq 1f + /* Read the TLB. */ + movel #(MMUOR_RW + MMUOR_ACC +\itlb), \temp_data_reg + movew \temp_data_reg, (MMUOR) + movel MMUSR,\temp_data_reg + /* Set up tag value. */ + movel #0, \temp_data_reg + movel \temp_data_reg, MMUTR + /* Set up data value. */ + movel #0, \temp_data_reg + movel \temp_data_reg, MMUDR + /* Save it. */ + movel #(MMUOR_ACC + MMUOR_UAA + \itlb), \temp_data_reg + movew \temp_data_reg, (MMUOR) +1: +.endm /* mmu_unmap */ + +/* .text */ +.section ".text.head","ax" +ENTRY(_stext) +/* Version numbers of the bootinfo interface -- if we later pass info + * from boot ROM we might want to put something real here. + * + * The area from _stext to _start will later be used as kernel pointer table + */ + bras 1f /* Jump over bootinfo version numbers */ + + .long BOOTINFOV_MAGIC + .long 0 +1: jmp __start + +.equ kernel_pg_dir,_stext +.equ .,_stext+0x1000 + +ENTRY(_start) + jra __start +__INIT +ENTRY(__start) +/* Save the location of u-boot info - cmd line, bd_info, etc. */ + movel %a7,%a4 /* Don't use %a4 before cf_early_init */ + addl #0x00000004,%a4 /* offset past top */ + addl #(PAGE_OFFSET-CONFIG_SDRAM_BASE),%a4 /* high mem offset */ + +/* Setup initial stack pointer */ + movel #CONFIG_SDRAM_BASE+0x1000,%sp + +/* Setup usp */ + subl %a0,%a0 + movel %a0,%usp + +#if defined(CONFIG_M5445X) || defined(CONFIG_M5441X) +#if defined(CONFIG_SRAM) + movel #(CONFIG_SRAM_BASE+0x221), %d0 +#else + movel #0x80000000, %d0 +#endif + +#ifdef CONFIG_M5441X + movec %d0, %rambar +#else + movec %d0, %rambar1 +#endif +#elif defined(CONFIG_M547X_8X) + movel #MCF_MBAR, %d0 + movec %d0, %mbar + move.l #(MCF_RAMBAR0 + 0x21), %d0 + movec %d0, %rambar0 + move.l #(MCF_RAMBAR1 + 0x21), %d0 + movec %d0, %rambar1 +#endif + + movew #0x2700,%sr + +/* reset cache */ + movel #(CF_CACR_ICINVA + CF_CACR_DCINVA),%d0 + movecl %d0,%cacr + + movel #(MMU_BASE+1),%d0 + movecl %d0,%mmubar + movel #MMUOR_CA,%a0 /* Clear tlb entries */ + movew %a0,(MMUOR) + movel #(MMUOR_CA + MMUOR_ITLB),%a0 /* Use ITLB for searches */ + movew %a0,(MMUOR) + movel #0,%a0 /* Clear Addr Space User ID */ + movecl %a0,%asid + +/* setup ACRs */ +#if defined(CONFIG_M5445X) || defined(CONFIG_M547X_8X) || defined(CONFIG_M5441X) + movel ACR0_DEFAULT, %d0 /* ACR0 (DATA) setup */ + movec %d0, %acr0 + nop + movel ACR1_DEFAULT, %d0 /* ACR1 (DATA) setup */ + movec %d0, %acr1 + nop + movel ACR2_DEFAULT, %d0 /* ACR2 (CODE) setup */ + movec %d0, %acr2 + nop + movel ACR3_DEFAULT, %d0 /* ACR3 (CODE) setup */ + movec %d0, %acr3 + nop +#endif + /* Turn on MMU */ + movel #(MMUCR_EN),%a0 + movel %a0,MMUCR + nop /* This synchs the pipeline after a write to MMUCR */ + + movel #__running_high,%a0 /* Get around PC-relative addressing. */ + jmp %a0@ + +ENTRY(__running_high) + load_symbol_address _stext,%sp + movel L(memory_start),%a0 + movel %a0,availmem + load_symbol_address L(phys_kernel_start),%a0 + load_symbol_address _stext,%a1 + subl #_stext,%a1 + addl #PAGE_OFFSET,%a1 + movel %a1,%a0@ + +/* zero bss */ + lea _sbss,%a0 + lea _ebss,%a1 + clrl %d0 +_loop_bss: + movel %d0,(%a0)+ + cmpl %a0,%a1 + bne _loop_bss + +/* create dma memory mirror TLB mapping */ +#if defined(CONFIG_M5445X) || defined(CONFIG_M5441X) + mmu_map CONFIG_DMA_BASE, \ + CONFIG_SDRAM_BASE, 0, 0, \ + MMUTR_SG, MMUDR_SZ16M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, MMUDR_W, \ + 0, MMUDR_LK, %d0 +#elif defined(CONFIG_M547X_8X) + mmu_map (CONFIG_DMA_BASE + 0*1024*1024), \ + (CONFIG_SDRAM_BASE + 0*1024*1024), 0, 0, \ + MMUTR_SG, MMUDR_SZ1M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, \ + MMUDR_W, 0, MMUDR_LK, %d0 + mmu_map (CONFIG_DMA_BASE + 1*1024*1024), \ + (CONFIG_SDRAM_BASE + 1*1024*1024), 0, 0, \ + MMUTR_SG, MMUDR_SZ1M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, \ + MMUDR_W, 0, MMUDR_LK, %d0 + mmu_map (CONFIG_DMA_BASE + 2*1024*1024), \ + (CONFIG_SDRAM_BASE + 2*1024*1024), 0, 0, \ + MMUTR_SG, MMUDR_SZ1M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, \ + MMUDR_W, 0, MMUDR_LK, %d0 + mmu_map (CONFIG_DMA_BASE + 3*1024*1024), \ + (CONFIG_SDRAM_BASE + 3*1024*1024), 0, 0, \ + MMUTR_SG, MMUDR_SZ1M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, \ + MMUDR_W, 0, MMUDR_LK, %d0 + mmu_map (CONFIG_DMA_BASE + 4*1024*1024), \ + (CONFIG_SDRAM_BASE + 4*1024*1024), 0, 0, \ + MMUTR_SG, MMUDR_SZ1M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, \ + MMUDR_W, 0, MMUDR_LK, %d0 + mmu_map (CONFIG_DMA_BASE + 5*1024*1024), \ + (CONFIG_SDRAM_BASE + 5*1024*1024), 0, 0, \ + MMUTR_SG, MMUDR_SZ1M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, \ + MMUDR_W, 0, MMUDR_LK, %d0 + mmu_map (CONFIG_DMA_BASE + 6*1024*1024), \ + (CONFIG_SDRAM_BASE + 6*1024*1024), 0, 0, \ + MMUTR_SG, MMUDR_SZ1M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, \ + MMUDR_W, 0, MMUDR_LK, %d0 + mmu_map (CONFIG_DMA_BASE + 7*1024*1024), \ + (CONFIG_SDRAM_BASE + 7*1024*1024), 0, 0, \ + MMUTR_SG, MMUDR_SZ1M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, \ + MMUDR_W, 0, MMUDR_LK, %d0 +#endif + +/* Setup initial stack pointer */ + lea init_task,%a2 + lea init_thread_union+THREAD_SIZE,%sp + subl %a6,%a6 /* clear a6 for gdb */ + +#ifdef CONFIG_MCF_USER_HALT +/* Setup debug control reg to allow halts from user space */ + lea wdbg_uhe,%a0 + wdebug (%a0) +#endif + + movel %a4,uboot_info_stk /* save uboot info to variable */ + jsr cf_early_init + jmp start_kernel + +.section ".text.head","ax" +set_context: +func_start set_context,%d0,(1*4) + movel 12(%sp),%d0 + movec %d0,%asid +func_return set_context + +#ifdef CONFIG_M54455 +/* + * set_fpga(addr,val) on the M5445X + * + * Map in 0x00000000 -> 0x0fffffff and then do the write. + */ +set_fpga: + movew %sr,%d1 + movew #0x2700,%sr + movel ACR0_FPGA, %d0 + movec %d0, %acr0 + nop + moveal 4(%sp),%a0 + movel 8(%sp),%a0@ + movel ACR0_DEFAULT, %d0 + movec %d0, %acr0 + nop + movew %d1,%sr + rts +#endif + + .data + .align 4 + +availmem: + .long 0 +L(phys_kernel_start): + .long PAGE_OFFSET +L(kernel_end): + .long 0 +L(memory_start): + .long PAGE_OFFSET_RAW + +#ifdef CONFIG_MCF_USER_HALT +/* + * Enable User Halt Enable in the debug control register. + */ +wdbg_uhe: + .word 0x2c80 /* DR0 */ + .word 0x00b0 /* 31:16 */ + .word 0x0400 /* 15:0 -- enable UHE */ + .word 0x0000 /* unused */ +#endif + + --- /dev/null +++ b/arch/m68k/coldfire/common/ints.c @@ -0,0 +1,544 @@ +/* + * linux/arch/m68k/coldfire/ints.c -- General interrupt handling code + * + * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Matt Waddel Matt.Waddel@freescale.com + * Kurt Mahan kmahan@freescale.com + * Jason Jin Jason.Jin@freescale.com + * Shrek Wu B16972@freescale.com + * + * Based on: + * linux/arch/m68k/kernel/ints.c & + * linux/arch/m68knommu/5307/ints.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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +/* + * IRQ Handler lists. + */ +static struct irq_node *irq_list[SYS_IRQS]; +static struct irq_controller *irq_controller[SYS_IRQS]; +static int irq_depth[SYS_IRQS]; + +#define POOL_SIZE SYS_IRQS +static struct irq_node pool[POOL_SIZE]; +static struct irq_node *get_irq_node(void); + +/* The number of spurious interrupts */ +unsigned int num_spurious; +asmlinkage void handle_badint(struct pt_regs *regs); + +/* + * process_int(unsigned long vec, struct pt_regs *fp) + * + * Process an interrupt. Called from entry.S. + */ +asmlinkage void process_int(unsigned long vec, struct pt_regs *fp) +{ + struct pt_regs *old_regs; + struct irq_node *node; + old_regs = set_irq_regs(fp); + kstat_cpu(0).irqs[vec]++; + + node = irq_list[vec]; + if (!node) + handle_badint(fp); + else { + do { + node->handler(vec, node->dev_id); + node = node->next; + } while (node); + } + + set_irq_regs(old_regs); +} + +/* + * show_interrupts( struct seq_file *p, void *v) + * + * Called to show all the current interrupt information. + */ +int show_interrupts(struct seq_file *p, void *v) +{ + struct irq_controller *contr; + struct irq_node *node; + int i = *(loff_t *) v; + + if ((i < NR_IRQS) && (irq_list[i])) { + contr = irq_controller[i]; + node = irq_list[i]; + seq_printf(p, "%-8s %3u: %10u %s", contr->name, i, + kstat_cpu(0).irqs[i], node->devname); + while ((node = node->next)) + seq_printf(p, ", %s", node->devname); + + seq_printf(p, "\n"); + } + + return 0; +} + +/* + * get_irq_node(void) + * + * Get an irq node from the pool. + */ +struct irq_node *get_irq_node(void) +{ + struct irq_node *p = pool; + int i; + + for (i = 0; i < POOL_SIZE; i++, p++) { + if (!p->handler) { + memset(p, 0, sizeof(struct irq_node)); + return p; + } + } + printk(KERN_INFO "%s(%s:%d): No more irq nodes, I suggest you \ + increase POOL_SIZE", __func__, __FILE__, __LINE__); + return NULL; +} + +void init_irq_proc(void) +{ + /* Insert /proc/irq driver here */ +} + +int setup_irq(unsigned int irq, struct irq_node *node) +{ + struct irq_controller *contr; + struct irq_node **prev; + unsigned long flags; + + if (irq >= NR_IRQS || !irq_controller[irq]) { + printk("%s: Incorrect IRQ %d from %s\n", + __func__, irq, node->devname); + return -ENXIO; + } + + contr = irq_controller[irq]; + spin_lock_irqsave(&contr->lock, flags); + + prev = irq_list + irq; + if (*prev) { + /* Can't share interrupts unless both agree to */ + if (!((*prev)->flags & node->flags & IRQF_SHARED)) { + spin_unlock_irqrestore(&contr->lock, flags); + printk(KERN_INFO "%s: -BUSY-Incorrect IRQ %d\n", + __func__, irq); + return -EBUSY; + } + while (*prev) + prev = &(*prev)->next; + } + + if (!irq_list[irq]) { + if (contr->startup) + contr->startup(irq); + else + contr->enable(irq); + } + node->next = NULL; + *prev = node; + + spin_unlock_irqrestore(&contr->lock, flags); + + return 0; +} + +int request_irq(unsigned int irq, + irq_handler_t handler, + unsigned long flags, const char *devname, void *dev_id) +{ + struct irq_node *node = get_irq_node(); + int res; + + if (!node) { + printk(KERN_INFO "%s:get_irq_node error %x\n", + __func__, (unsigned int) node); + return -ENOMEM; + } + node->handler = handler; + node->flags = flags; + node->dev_id = dev_id; + node->devname = devname; + + res = setup_irq(irq, node); + if (res) + node->handler = NULL; + + return res; +} +EXPORT_SYMBOL(request_irq); + +void free_irq(unsigned int irq, void *dev_id) +{ + struct irq_controller *contr; + struct irq_node **p, *node; + unsigned long flags; + + if (irq >= NR_IRQS || !irq_controller[irq]) { + printk(KERN_DEBUG "%s: Incorrect IRQ %d\n", __func__, irq); + return; + } + + contr = irq_controller[irq]; + spin_lock_irqsave(&contr->lock, flags); + + p = irq_list + irq; + while ((node = *p)) { + if (node->dev_id == dev_id) + break; + p = &node->next; + } + + if (node) { + *p = node->next; + node->handler = NULL; + } else + printk(KERN_DEBUG "%s: Removing probably wrong IRQ %d\n", + __func__, irq); + + if (!irq_list[irq]) { + if (contr->shutdown) + contr->shutdown(irq); + else + contr->disable(irq); + } + + spin_unlock_irqrestore(&contr->lock, flags); +} +EXPORT_SYMBOL(free_irq); + +void enable_irq(unsigned int irq) +{ + struct irq_controller *contr; + unsigned long flags; + + if (irq >= NR_IRQS || !irq_controller[irq]) { + printk(KERN_DEBUG "%s: Incorrect IRQ %d\n", __func__, irq); + return; + } + + contr = irq_controller[irq]; + spin_lock_irqsave(&contr->lock, flags); + if (irq_depth[irq]) { + if (!--irq_depth[irq]) { + if (contr->enable) + contr->enable(irq); + } + } else + WARN_ON(1); + spin_unlock_irqrestore(&contr->lock, flags); +} +EXPORT_SYMBOL(enable_irq); + +void disable_irq(unsigned int irq) +{ + struct irq_controller *contr; + unsigned long flags; + + if (irq >= NR_IRQS || !irq_controller[irq]) { + printk(KERN_DEBUG "%s: Incorrect IRQ %d\n", __func__, irq); + return; + } + + contr = irq_controller[irq]; + spin_lock_irqsave(&contr->lock, flags); + if (!irq_depth[irq]++) { + if (contr->disable) + contr->disable(irq); + } + spin_unlock_irqrestore(&contr->lock, flags); +} +EXPORT_SYMBOL(disable_irq); + +void disable_irq_nosync(unsigned int irq) __attribute__((alias("disable_irq"))); +EXPORT_SYMBOL(disable_irq_nosync); + + +unsigned long probe_irq_on(void) +{ + return 0; +} +EXPORT_SYMBOL(probe_irq_on); + +int probe_irq_off(unsigned long irqs) +{ + return 0; +} +EXPORT_SYMBOL(probe_irq_off); + +asmlinkage void handle_badint(struct pt_regs *regs) +{ + kstat_cpu(0).irqs[0]++; + num_spurious++; + printk(KERN_DEBUG "unexpected interrupt from %u\n", regs->vector); +} +EXPORT_SYMBOL(handle_badint); + +unsigned int irq_canonicalize(unsigned int irq) +{ +#ifdef CONFIG_Q40 + if (MACH_IS_Q40 && irq == 11) + irq = 10; +#endif + return irq; +} +EXPORT_SYMBOL(irq_canonicalize); + +#ifdef CONFIG_M5445X +/* + * M5445X Implementation + */ +void m5445x_irq_enable(unsigned int irq) +{ + /* enable the interrupt hardware */ + if (irq < 64) + return; + + /* adjust past non-hardware ints */ + irq -= 64; + + /* check for eport */ + if ((irq > 0) && (irq < 8)) { + /* enable eport */ + MCF_EPORT_EPPAR &= ~(3 << (irq*2)); /* level */ + MCF_EPORT_EPDDR &= ~(1 << irq); /* input */ + MCF_EPORT_EPIER |= 1 << irq; /* irq enabled */ + } + + if (irq < 64) { + /* controller 0 */ + MCF_INTC0_ICR(irq) = 0x02; + MCF_INTC0_CIMR = irq; + } else { + /* controller 1 */ + irq -= 64; + MCF_INTC1_ICR(irq) = 0x02; + MCF_INTC1_CIMR = irq; + } +} + +void m5445x_irq_disable(unsigned int irq) +{ + /* disable the interrupt hardware */ + if (irq < 64) + return; + + /* adjust past non-hardware ints */ + irq -= 64; + + /* check for eport */ + if ((irq > 0) && (irq < 8)) { + /* disable eport */ + MCF_EPORT_EPIER &= ~(1 << irq); + } + + if (irq < 64) { + /* controller 0 */ + MCF_INTC0_ICR(irq) = 0x00; + MCF_INTC0_SIMR = irq; + } else { + /* controller 1 */ + irq -= 64; + MCF_INTC1_ICR(irq) = 0x00; + MCF_INTC1_SIMR = irq; + } +} +#elif defined(CONFIG_M547X_8X) +/* + * M547X_8X Implementation + */ +void m547x_8x_irq_enable(unsigned int irq) +{ + /* enable the interrupt hardware */ + if (irq < 64) + return; + + /* adjust past non-hardware ints */ + irq -= 64; + + /* check for eport */ + if ((irq > 0) && (irq < 8)) { + /* enable eport */ + MCF_EPPAR &= ~(3 << (irq*2)); + /* level */ + MCF_EPDDR &= ~(1 << irq); + /* input */ + MCF_EPIER |= 1 << irq; + /* irq enabled */ + } + + if (irq < 32) { + /* *grumble* don't set low bit of IMRL */ + MCF_IMRL &= (~(1 << irq) & 0xfffffffe); + } else { + MCF_IMRH &= ~(1 << (irq - 32)); + } +} + +void m547x_8x_irq_disable(unsigned int irq) +{ + /* disable the interrupt hardware */ + if (irq < 64) + return; + + /* adjust past non-hardware ints */ + irq -= 64; + + /* check for eport */ + if ((irq > 0) && (irq < 8)) { + /* disable eport */ + MCF_EPIER &= ~(1 << irq); + } + + if (irq < 32) + MCF_IMRL |= (1 << irq); + else + MCF_IMRH |= (1 << (irq - 32)); +} + +#elif defined(CONFIG_M5441X) +/* + * M5441X Implementation + */ +void m5441x_irq_enable(unsigned int irq) +{ + /* enable the interrupt hardware */ + if (irq < 64) + return; + + /* adjust past non-hardware ints */ + irq -= 64; + + /* check for eport */ + if ((irq > 0) && (irq < 8)) { + /* enable eport */ + MCF_EPORT_EPPAR &= ~(3 << (irq*2)); /* level */ + MCF_EPORT_EPIER |= 1 << irq; /* irq enabled */ + } + + if (irq < 64) { + /* controller 0 */ + MCF_INTC0_ICR(irq) = 0x02; + MCF_INTC0_CIMR = irq; + } else if (irq >= 64 && irq < 128) { + /* controller 1 */ + irq -= 64; + MCF_INTC1_ICR(irq) = 0x02; + MCF_INTC1_CIMR = irq; + } else if (irq >= 128 && irq < 192) { + /* controller 2 */ + irq -= 128; + MCF_INTC2_ICR(irq) = 0x02; + MCF_INTC2_CIMR = irq; + } else { + /* invalid irq number */ + return; + } +} + +void m5441x_irq_disable(unsigned int irq) +{ + /* disable the interrupt hardware */ + if (irq < 64) + return; + + /* adjust past non-hardware ints */ + irq -= 64; + + /* check for eport */ + if ((irq > 0) && (irq < 8)) { + /* disable eport */ + MCF_EPORT_EPIER &= ~(1 << irq); + } + + if (irq < 64) { + /* controller 0 */ + MCF_INTC0_ICR(irq) = 0x00; + MCF_INTC0_SIMR = irq; + } else if (irq >= 64 && irq < 128) { + /* controller 1 */ + irq -= 64; + MCF_INTC1_ICR(irq) = 0x00; + MCF_INTC1_SIMR = irq; + } else if (irq >= 128 && irq < 192) { + /* controller 2 */ + irq -= 128; + MCF_INTC2_ICR(irq) = 0x00; + MCF_INTC2_SIMR = irq; + } +} +#endif + +/* + * IRQ Controller + */ +#if defined(CONFIG_M5445X) +static struct irq_controller m5445x_irq_controller = { + .name = "M5445X", + .lock = __SPIN_LOCK_UNLOCKED(m5445x_irq_controller.lock), + .enable = m5445x_irq_enable, + .disable = m5445x_irq_disable, +}; +#elif defined(CONFIG_M547X_8X) +static struct irq_controller m547x_8x_irq_controller = { + .name = "M547X_8X", + .lock = __SPIN_LOCK_UNLOCKED(m547x_8x_irq_controller.lock), + .enable = m547x_8x_irq_enable, + .disable = m547x_8x_irq_disable, +}; +#elif defined(CONFIG_M5441X) +static struct irq_controller m5441x_irq_controller = { + .name = "M5441X", + .lock = __SPIN_LOCK_UNLOCKED(m5441x_irq_controller.lock), + .enable = m5441x_irq_enable, + .disable = m5441x_irq_disable, +}; +#else +# error No IRQ controller defined +#endif + +/* + * void init_IRQ(void) + * + * This function should be called during kernel startup to initialize + * the IRQ handling routines. + */ +void __init init_IRQ(void) +{ + int i; + +#if defined(CONFIG_M5445X) + for (i = 0; i < SYS_IRQS; i++) + irq_controller[i] = &m5445x_irq_controller; +#elif defined(CONFIG_M547X_8X) + for (i = 0; i < SYS_IRQS; i++) + irq_controller[i] = &m547x_8x_irq_controller; +#elif defined(CONFIG_M5441X) + for (i = 0; i < SYS_IRQS; i++) + irq_controller[i] = &m5441x_irq_controller; +#endif +} --- /dev/null +++ b/arch/m68k/coldfire/common/muldi3.S @@ -0,0 +1,73 @@ +/* + * Coldfire muldi3 assembly verion + * + * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Jason Jin Jason.Jin@freescale.com + * Shrek Wu B16972@freescale.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 +.globl __muldi3 + +ENTRY(__muldi3) + linkw %fp,#0 + lea %sp@(-32),%sp + moveml %d2-%d7/%a2-%a3,%sp@ + moveal %fp@(8), %a2 + moveal %fp@(12), %a3 + moveal %fp@(16), %a0 + moveal %fp@(20),%a1 + movel %a3,%d2 + andil #65535,%d2 + movel %a3,%d3 + clrw %d3 + swap %d3 + movel %a1,%d0 + andil #65535,%d0 + movel %a1,%d1 + clrw %d1 + swap %d1 + movel %d2,%d7 + mulsl %d0,%d7 + movel %d2,%d4 + mulsl %d1,%d4 + movel %d3,%d2 + mulsl %d0,%d2 + mulsl %d1,%d3 + movel %d7,%d0 + clrw %d0 + swap %d0 + addl %d0,%d4 + addl %d2,%d4 + cmpl %d4,%d2 + blss 1f + addil #65536,%d3 +1: + movel %d4,%d0 + clrw %d0 + swap %d0 + movel %d3,%d5 + addl %d0,%d5 + movew %d4,%d6 + swap %d6 + movew %d7,%d6 + movel %d5,%d0 + movel %d6,%d1 + movel %a3,%d2 + movel %a0,%d3 + mulsl %d3,%d2 + movel %a2,%d3 + movel %a1,%d4 + mulsl %d4,%d3 + addl %d3,%d2 + movel %d2,%d0 + addl %d5,%d0 + moveml %sp@, %d2-%d7/%a2-%a3 + lea %sp@(32),%sp + unlk %fp + rts --- /dev/null +++ b/arch/m68k/coldfire/common/signal.c @@ -0,0 +1,991 @@ +/* + * linux/arch/m68k/kernel/signal.c + * + * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Matt Waddel Matt.Waddel@freescale.com + * Jason Jin Jason.Jin@freescale.com + * Shrek Wu B16972@freescale.com + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + * + * Derived from m68k/kernel/signal.c and the original authors are credited + * there. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + +asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs); + +const int frame_extra_sizes[16] = { + [1] = -1, + [2] = -1, + [3] = -1, + [4] = 0, + [5] = 1, + [6] = 1, + [7] = 2, + [8] = 3, + [9] = -1, + [10] = -1, + [11] = -1, + [12] = -1, + [13] = -1, + [14] = -1, + [15] = -1, +}; + +/* + * Atomically swap in the new signal mask, and wait for a signal. + */ +asmlinkage int do_sigsuspend(struct pt_regs *regs) +{ + old_sigset_t mask = regs->d3; + sigset_t saveset; + + mask &= _BLOCKABLE; + spin_lock_irq(¤t->sighand->siglock); + saveset = current->blocked; + siginitset(¤t->blocked, mask); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + regs->d0 = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(&saveset, regs)) + return -EINTR; + } +} + +asmlinkage int +do_rt_sigsuspend(struct pt_regs *regs) +{ + sigset_t __user *unewset = (sigset_t __user *)regs->d1; + size_t sigsetsize = (size_t)regs->d2; + sigset_t saveset, newset; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + if (copy_from_user(&newset, unewset, sizeof(newset))) + return -EFAULT; + sigdelsetmask(&newset, ~_BLOCKABLE); + + spin_lock_irq(¤t->sighand->siglock); + saveset = current->blocked; + current->blocked = newset; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + regs->d0 = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(&saveset, regs)) + return -EINTR; + } +} + +asmlinkage int +sys_sigaction(int sig, const struct old_sigaction __user *act, + struct old_sigaction __user *oact) +{ + struct k_sigaction new_ka, old_ka; + int ret; + + if (act) { + old_sigset_t mask; + if (!access_ok(VERIFY_READ, act, sizeof(*act)) || + __get_user(new_ka.sa.sa_handler, &act->sa_handler) || + __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) + return -EFAULT; + __get_user(new_ka.sa.sa_flags, &act->sa_flags); + __get_user(mask, &act->sa_mask); + siginitset(&new_ka.sa.sa_mask, mask); + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || + __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || + __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) + return -EFAULT; + __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); + } + + return ret; +} + +asmlinkage int +sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss) +{ + return do_sigaltstack(uss, uoss, rdusp()); +} + + +/* + * Do a signal return; undo the signal stack. + * + * Keep the return code on the stack quadword aligned! + * That makes the cache flush below easier. + */ + +struct sigframe { + char __user *pretcode; + int sig; + int code; + struct sigcontext __user *psc; + char retcode[8]; + unsigned long extramask[_NSIG_WORDS-1]; + struct sigcontext sc; +}; + +struct rt_sigframe { + char __user *pretcode; + int sig; + struct siginfo __user *pinfo; + void __user *puc; + char retcode[8]; + struct siginfo info; + struct ucontext uc; +}; + +#define FPCONTEXT_SIZE 216 +#define uc_fpstate uc_filler[0] +#define uc_formatvec uc_filler[FPCONTEXT_SIZE/4] +#define uc_extra uc_filler[FPCONTEXT_SIZE/4+1] + +#ifdef CONFIG_FPU +static unsigned char fpu_version; /* version num of fpu, set by setup_frame */ + +static inline int restore_fpu_state(struct sigcontext *sc) +{ + int err = 1; + + if (FPU_IS_EMU) { + /* restore registers */ + memcpy(current->thread.fpcntl, sc->sc_fpcntl, 12); + memcpy(current->thread.fp, sc->sc_fpregs, 24); + return 0; + } + + if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) { + /* Verify the frame format. */ + if (!CPU_IS_060 && (sc->sc_fpstate[0] != fpu_version)) + goto out; + if (CPU_IS_020_OR_030) { + if (m68k_fputype & FPU_68881 && + !(sc->sc_fpstate[1] == 0x18 || + sc->sc_fpstate[1] == 0xb4)) + goto out; + if (m68k_fputype & FPU_68882 && + !(sc->sc_fpstate[1] == 0x38 || + sc->sc_fpstate[1] == 0xd4)) + goto out; + } else if (CPU_IS_040) { + if (!(sc->sc_fpstate[1] == 0x00 || + sc->sc_fpstate[1] == 0x28 || + sc->sc_fpstate[1] == 0x60)) + goto out; + } else if (CPU_IS_060) { + if (!(sc->sc_fpstate[3] == 0x00 || + sc->sc_fpstate[3] == 0x60 || + sc->sc_fpstate[3] == 0xe0)) + goto out; + } else if (CPU_IS_CFV4E) { + pr_debug("restore v4e fpu state at %s\n", __func__); + } else + goto out; +#ifdef CONFIG_CFV4E + __asm__ volatile ("fmovem %0,%/fp0-%/fp1\n\t" + QCHIP_RESTORE_DIRECTIVE + : /* no outputs */ + : "m" (sc->sc_fpregs[0][0]) + : "memory"); + __asm__ volatile ("fmovel %0,%/fpcr" + : : "m" (sc->sc_fpcntl[0]) + : "memory"); + __asm__ volatile ("fmovel %0,%/fpsr" + : : "m" (sc->sc_fpcntl[1]) + : "memory"); + __asm__ volatile ("fmovel %0,%/fpiar" + : : "m" (sc->sc_fpcntl[2]) + : "memory"); + +#endif + } + +#ifdef CONFIG_CFV4E + __asm__ volatile ("frestore %0\n\t" + QCHIP_RESTORE_DIRECTIVE : : "m" (*sc->sc_fpstate)); +#endif + err = 0; + +out: + return err; +} + +static inline int rt_restore_fpu_state(struct ucontext __user *uc) +{ + unsigned char fpstate[FPCONTEXT_SIZE]; + int context_size = CPU_IS_060 ? 8 : 0; + fpregset_t fpregs; + int err = 1; + + if (FPU_IS_EMU) { + /* restore fpu control register */ + if (__copy_from_user(current->thread.fpcntl, + uc->uc_mcontext.fpregs.f_fpcntl, 12)) + goto out; + /* restore all other fpu register */ + if (__copy_from_user(current->thread.fp, + uc->uc_mcontext.fpregs.f_fpregs, 96)) + goto out; + return 0; + } + + if (__get_user(*(long *)fpstate, (long __user *)&uc->uc_fpstate)) + goto out; + if (CPU_IS_060 ? fpstate[2] : fpstate[0]) { + if (!CPU_IS_060) + context_size = fpstate[1]; + /* Verify the frame format. */ + if (!CPU_IS_060 && (fpstate[0] != fpu_version)) + goto out; + if (CPU_IS_020_OR_030) { + if (m68k_fputype & FPU_68881 && + !(context_size == 0x18 || context_size == 0xb4)) + goto out; + if (m68k_fputype & FPU_68882 && + !(context_size == 0x38 || context_size == 0xd4)) + goto out; + } else if (CPU_IS_040) { + if (!(context_size == 0x00 || + context_size == 0x28 || + context_size == 0x60)) + goto out; + } else if (CPU_IS_060) { + if (!(fpstate[3] == 0x00 || + fpstate[3] == 0x60 || + fpstate[3] == 0xe0)) + goto out; + } else if (CPU_IS_CFV4E) { + pr_debug("restore coldfire rt v4e fpu" + " state at %s\n", __func__); + } else + goto out; + if (__copy_from_user(&fpregs, &uc->uc_mcontext.fpregs, + sizeof(fpregs))) + goto out; +#ifdef CONFIG_CFV4E + __asm__ volatile ("fmovem %0,%/fp0-%/fp7\n\t" + QCHIP_RESTORE_DIRECTIVE + : /* no outputs */ + : "m" (fpregs.f_fpregs[0][0]) + : "memory"); + __asm__ volatile ("fmovel %0,%/fpcr" + : : "m" (fpregs.f_fpcntl[0]) + : "memory"); + __asm__ volatile ("fmovel %0,%/fpsr" + : : "m" (fpregs.f_fpcntl[1]) + : "memory"); + __asm__ volatile ("fmovel %0,%/fpiar" + : : "m" (fpregs.f_fpcntl[2]) + : "memory"); +#endif + } + if (context_size && + __copy_from_user(fpstate + 4, (long __user *)&uc->uc_fpstate + 1, + context_size)) + goto out; +#ifdef CONFIG_CFV4E + __asm__ volatile ("frestore %0\n\t" + QCHIP_RESTORE_DIRECTIVE : : "m" (*fpstate)); +#endif + err = 0; + +out: + return err; +} +#endif + +static inline int +restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *usc, + void __user *fp, int *pd0) +{ + int fsize, formatvec; + struct sigcontext context; + int err = 0; + + /* get previous context */ + if (copy_from_user(&context, usc, sizeof(context))) + goto badframe; + + /* restore passed registers */ + regs->d1 = context.sc_d1; + regs->a0 = context.sc_a0; + regs->a1 = context.sc_a1; + regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff); + regs->pc = context.sc_pc; + regs->orig_d0 = -1; /* disable syscall checks */ + wrusp(context.sc_usp); + formatvec = context.sc_formatvec; + regs->format = formatvec >> 12; + regs->vector = formatvec & 0xfff; + +#ifdef CONFIG_FPU + err = restore_fpu_state(&context); +#endif + + fsize = frame_extra_sizes[regs->format]; + if (fsize < 0) { + /* + * user process trying to return with weird frame format + */ +#ifdef DEBUG + printk(KERN_DEBUG "user process returning with weird \ + frame format\n"); +#endif + goto badframe; + } + + /* OK. Make room on the supervisor stack for the extra junk, + * if necessary. + */ + + { + struct switch_stack *sw = (struct switch_stack *)regs - 1; + regs->d0 = context.sc_d0; +#define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack)) + __asm__ __volatile__ + (" movel %0,%/sp\n\t" + " bra ret_from_signal\n" + "4:\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 2b,4b\n" + ".previous" + : /* no outputs, it doesn't ever return */ + : "a" (sw), "d" (fsize), "d" (frame_offset/4-1), + "n" (frame_offset), "a" (fp) + : "a0"); +#undef frame_offset + /* + * If we ever get here an exception occurred while + * building the above stack-frame. + */ + goto badframe; + } + + *pd0 = context.sc_d0; + return err; + +badframe: + return 1; +} + +static inline int +rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw, + struct ucontext __user *uc, int *pd0) +{ + int fsize, temp; + greg_t __user *gregs = uc->uc_mcontext.gregs; + unsigned long usp; + int err; + + err = __get_user(temp, &uc->uc_mcontext.version); + if (temp != MCONTEXT_VERSION) + goto badframe; + /* restore passed registers */ + err |= __get_user(regs->d0, &gregs[0]); + err |= __get_user(regs->d1, &gregs[1]); + err |= __get_user(regs->d2, &gregs[2]); + err |= __get_user(regs->d3, &gregs[3]); + err |= __get_user(regs->d4, &gregs[4]); + err |= __get_user(regs->d5, &gregs[5]); + err |= __get_user(sw->d6, &gregs[6]); + err |= __get_user(sw->d7, &gregs[7]); + err |= __get_user(regs->a0, &gregs[8]); + err |= __get_user(regs->a1, &gregs[9]); + err |= __get_user(regs->a2, &gregs[10]); + err |= __get_user(sw->a3, &gregs[11]); + err |= __get_user(sw->a4, &gregs[12]); + err |= __get_user(sw->a5, &gregs[13]); + err |= __get_user(sw->a6, &gregs[14]); + err |= __get_user(usp, &gregs[15]); + wrusp(usp); + err |= __get_user(regs->pc, &gregs[16]); + err |= __get_user(temp, &gregs[17]); + regs->sr = (regs->sr & 0xff00) | (temp & 0xff); + regs->orig_d0 = -1; /* disable syscall checks */ + err |= __get_user(temp, &uc->uc_formatvec); + regs->format = temp >> 12; + regs->vector = temp & 0xfff; + +#ifdef CONFIG_FPU + err |= rt_restore_fpu_state(uc); +#endif + + if (do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT) + goto badframe; + + fsize = frame_extra_sizes[regs->format]; + if (fsize < 0) { + /* + * user process trying to return with weird frame format + */ +#ifdef DEBUG + printk(KERN_DEBUG "user process returning with weird \ + frame format\n"); +#endif + goto badframe; + } + + /* OK. Make room on the supervisor stack for the extra junk, + * if necessary. + */ + + { +#define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack)) + __asm__ __volatile__ + (" movel %0,%/sp\n\t" + " bra ret_from_signal\n" + "4:\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 2b,4b\n" + ".previous" + : /* no outputs, it doesn't ever return */ + : "a" (sw), "d" (fsize), "d" (frame_offset/4-1), + "n" (frame_offset), "a" (&uc->uc_extra) + : "a0"); +#undef frame_offset + /* + * If we ever get here an exception occurred while + * building the above stack-frame. + */ + goto badframe; + } + + *pd0 = regs->d0; + return err; + +badframe: + return 1; +} + +asmlinkage int do_sigreturn(unsigned long __unused) +{ + struct switch_stack *sw = (struct switch_stack *) &__unused; + struct pt_regs *regs = (struct pt_regs *) (sw + 1); + unsigned long usp = rdusp(); + struct sigframe __user *frame = (struct sigframe __user *)(usp - 4); + sigset_t set; + int d0; + + if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + if (__get_user(set.sig[0], &frame->sc.sc_mask) || + (_NSIG_WORDS > 1 && + __copy_from_user(&set.sig[1], &frame->extramask, + sizeof(frame->extramask)))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sighand->siglock); + current->blocked = set; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + if (restore_sigcontext(regs, &frame->sc, frame + 1, &d0)) + goto badframe; + return d0; + +badframe: + force_sig(SIGSEGV, current); + return 0; +} + +asmlinkage int do_rt_sigreturn(unsigned long __unused) +{ + struct switch_stack *sw = (struct switch_stack *) &__unused; + struct pt_regs *regs = (struct pt_regs *) (sw + 1); + unsigned long usp = rdusp(); + struct rt_sigframe __user *frame = + (struct rt_sigframe __user *)(usp - 4); + sigset_t set; + int d0; + + 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); + spin_lock_irq(¤t->sighand->siglock); + current->blocked = set; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + if (rt_restore_ucontext(regs, sw, &frame->uc, &d0)) + goto badframe; + return d0; + +badframe: + force_sig(SIGSEGV, current); + return 0; +} + +#ifdef CONFIG_FPU +/* + * Set up a signal frame. + */ + +static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs) +{ + if (FPU_IS_EMU) { + /* save registers */ + memcpy(sc->sc_fpcntl, current->thread.fpcntl, 12); + memcpy(sc->sc_fpregs, current->thread.fp, 24); + return; + } + +#ifdef CONFIG_CFV4E + __asm__ volatile ("fsave %0\n\t" + QCHIP_RESTORE_DIRECTIVE + : : "m" (*sc->sc_fpstate) : "memory"); +#endif + + if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) { + fpu_version = sc->sc_fpstate[0]; + if (CPU_IS_020_OR_030 && + regs->vector >= (VEC_FPBRUC * 4) && + regs->vector <= (VEC_FPNAN * 4)) { + /* Clear pending exception in 68882 idle frame */ + if (*(unsigned short *) sc->sc_fpstate == 0x1f38) + sc->sc_fpstate[0x38] |= 1 << 3; + } +#ifdef CONFIG_CFV4E + __asm__ volatile ("fmovemd %/fp0-%/fp1,%0" + : : "m" (sc->sc_fpregs[0][0]) + : "memory"); + __asm__ volatile ("fmovel %/fpcr,%0" + : : "m" (sc->sc_fpcntl[0]) + : "memory"); + __asm__ volatile ("fmovel %/fpsr,%0" + : : "m" (sc->sc_fpcntl[1]) + : "memory"); + __asm__ volatile ("fmovel %/fpiar,%0" + : : "m" (sc->sc_fpcntl[2]) + : "memory"); + +#endif + } +} + +static inline int rt_save_fpu_state(struct ucontext __user *uc, + struct pt_regs *regs) +{ + unsigned char fpstate[FPCONTEXT_SIZE]; + int context_size = CPU_IS_060 ? 8 : 0; + int err = 0; + + if (FPU_IS_EMU) { + /* save fpu control register */ + err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpcntl, + current->thread.fpcntl, 12); + /* save all other fpu register */ + err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpregs, + current->thread.fp, 96); + return err; + } + +#ifdef CONFIG_CFV4E + __asm__ volatile ("fsave %0\n\t" + QCHIP_RESTORE_DIRECTIVE + : : "m" (*fpstate) : "memory"); +#endif + err |= __put_user(*(long *)fpstate, (long *)&uc->uc_fpstate); + if (CPU_IS_060 ? fpstate[2] : fpstate[0]) { + fpregset_t fpregs; + if (!CPU_IS_060) + context_size = fpstate[1]; + fpu_version = fpstate[0]; +#ifdef CONFIG_CFV4E + __asm__ volatile ("fmovemd %/fp0-%/fp7,%0" + : : "m" (fpregs.f_fpregs[0][0]) + : "memory"); + __asm__ volatile ("fmovel %/fpcr,%0" + : : "m" (fpregs.f_fpcntl[0]) + : "memory"); + __asm__ volatile ("fmovel %/fpsr,%0" + : : "m" (fpregs.f_fpcntl[1]) + : "memory"); + __asm__ volatile ("fmovel %/fpiar,%0" + : : "m" (fpregs.f_fpcntl[2]) + : "memory"); +#endif + err |= copy_to_user(&uc->uc_mcontext.fpregs, &fpregs, + sizeof(fpregs)); + } + if (context_size) + err |= copy_to_user((long *)&uc->uc_fpstate + 1, fpstate + 4, + context_size); + return err; + + + return err; +} +#endif + +static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, + unsigned long mask) +{ + sc->sc_mask = mask; + sc->sc_usp = rdusp(); + sc->sc_d0 = regs->d0; + sc->sc_d1 = regs->d1; + sc->sc_a0 = regs->a0; + sc->sc_a1 = regs->a1; + sc->sc_sr = regs->sr; + sc->sc_pc = regs->pc; + sc->sc_formatvec = regs->format << 12 | regs->vector; +#ifdef CONFIG_FPU + save_fpu_state(sc, regs); +#endif +} + +static inline int rt_setup_ucontext(struct ucontext __user *uc, + struct pt_regs *regs) +{ + struct switch_stack *sw = (struct switch_stack *)regs - 1; + greg_t __user *gregs = uc->uc_mcontext.gregs; + int err = 0; + + err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version); + err |= __put_user(regs->d0, &gregs[0]); + err |= __put_user(regs->d1, &gregs[1]); + err |= __put_user(regs->d2, &gregs[2]); + err |= __put_user(regs->d3, &gregs[3]); + err |= __put_user(regs->d4, &gregs[4]); + err |= __put_user(regs->d5, &gregs[5]); + err |= __put_user(sw->d6, &gregs[6]); + err |= __put_user(sw->d7, &gregs[7]); + err |= __put_user(regs->a0, &gregs[8]); + err |= __put_user(regs->a1, &gregs[9]); + err |= __put_user(regs->a2, &gregs[10]); + err |= __put_user(sw->a3, &gregs[11]); + err |= __put_user(sw->a4, &gregs[12]); + err |= __put_user(sw->a5, &gregs[13]); + err |= __put_user(sw->a6, &gregs[14]); + err |= __put_user(rdusp(), &gregs[15]); + err |= __put_user(regs->pc, &gregs[16]); + err |= __put_user(regs->sr, &gregs[17]); + err |= __put_user((regs->format << 12) | regs->vector, + &uc->uc_formatvec); +#ifdef CONFIG_FPU + err |= rt_save_fpu_state(uc, regs); +#endif + return err; +} + +static inline void push_cache(unsigned long vaddr) +{ +#if defined(CONFIG_M5445X) || defined(CONFIG_M5441X) + pgd_t *pdir; + pmd_t *pmdp; + pte_t *ptep; + unsigned long paddr; + + pdir = pgd_offset(current->mm, vaddr); + pmdp = pmd_offset(pdir, vaddr); + ptep = pte_offset_map(pmdp, vaddr); + paddr = ((pte_val(*ptep) & PAGE_MASK) | (vaddr & ~PAGE_MASK)); + cf_icache_flush_range(paddr, paddr + 8); +#elif defined(CONFIG_M547X_8X) + flush_icache_range(vaddr, vaddr + 8); +#endif +} + +static inline void __user * +get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) +{ + unsigned long usp; + + /* Default to using normal stack. */ + usp = rdusp(); + + /* This is the X/Open sanctioned signal stack switching. */ + if (ka->sa.sa_flags & SA_ONSTACK) { + if (!sas_ss_flags(usp)) + usp = current->sas_ss_sp + current->sas_ss_size; + } + return (void __user *)((usp - frame_size) & -8UL); +} + +static void setup_frame(int sig, struct k_sigaction *ka, + sigset_t *set, struct pt_regs *regs) +{ + struct sigframe __user *frame; + int fsize = frame_extra_sizes[regs->format]; + struct sigcontext context; + int err = 0; + + if (fsize < 0) { +#ifdef DEBUG + printk(KERN_DEBUG "setup_frame: Unknown frame format %#x\n", + regs->format); +#endif + goto give_sigsegv; + } + + frame = get_sigframe(ka, regs, sizeof(*frame)); + + err |= __put_user((current_thread_info()->exec_domain + && current_thread_info()->exec_domain->signal_invmap + && sig < 32 + ? current_thread_info()->exec_domain->signal_invmap[sig] + : sig), + &frame->sig); + + err |= __put_user(regs->vector, &frame->code); + err |= __put_user(&frame->sc, &frame->psc); + + if (_NSIG_WORDS > 1) + err |= copy_to_user(frame->extramask, &set->sig[1], + sizeof(frame->extramask)); + + setup_sigcontext(&context, regs, set->sig[0]); + err |= copy_to_user(&frame->sc, &context, sizeof(context)); + + /* Set up to return from userspace. */ + err |= __put_user(frame->retcode, &frame->pretcode); + /* moveq #,d0; trap #0 */ + err |= __put_user(0x70004e40 + (__NR_sigreturn << 16), + (long __user *)(frame->retcode)); + + if (err) + goto give_sigsegv; + + push_cache((unsigned long) &frame->retcode); + + /* Set up registers for signal handler */ + wrusp((unsigned long) frame); + regs->pc = (unsigned long) ka->sa.sa_handler; + +adjust_stack: + /* Prepare to skip over the extra stuff in the exception frame. */ + if (regs->stkadj) { + struct pt_regs *tregs = + (struct pt_regs *)((ulong)regs + regs->stkadj); +#ifdef DEBUG + printk(KERN_DEBUG "Performing stackadjust=%04x\n", + regs->stkadj); +#endif + /* This must be copied with decreasing addresses to + handle overlaps. */ + tregs->vector = 0; + tregs->format = 0; + tregs->pc = regs->pc; + tregs->sr = regs->sr; + } + return; + +give_sigsegv: + force_sigsegv(sig, current); + goto adjust_stack; +} + +static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *set, struct pt_regs *regs) +{ + struct rt_sigframe __user *frame; + int fsize = frame_extra_sizes[regs->format]; + int err = 0; + + if (fsize < 0) { +#ifdef DEBUG + printk(KERN_DEBUG "setup_frame: Unknown frame format %#x\n", + regs->format); +#endif + goto give_sigsegv; + } + + frame = get_sigframe(ka, regs, sizeof(*frame)); + + if (fsize) { + err |= copy_to_user(&frame->uc.uc_extra, regs + 1, fsize); + regs->stkadj = fsize; + } + + err |= __put_user((current_thread_info()->exec_domain + && current_thread_info()->exec_domain->signal_invmap + && sig < 32 + ? current_thread_info()->exec_domain->signal_invmap[sig] + : sig), + &frame->sig); + err |= __put_user(&frame->info, &frame->pinfo); + err |= __put_user(&frame->uc, &frame->puc); + err |= copy_siginfo_to_user(&frame->info, info); + + /* Create the ucontext. */ + err |= __put_user(0, &frame->uc.uc_flags); + err |= __put_user(NULL, &frame->uc.uc_link); + err |= __put_user((void __user *)current->sas_ss_sp, + &frame->uc.uc_stack.ss_sp); + err |= __put_user(sas_ss_flags(rdusp()), + &frame->uc.uc_stack.ss_flags); + err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); + err |= rt_setup_ucontext(&frame->uc, regs); + err |= copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); + + /* Set up to return from userspace. */ + err |= __put_user(frame->retcode, &frame->pretcode); + + /* movel #__NR_rt_sigreturn(0xAD),d0; trap #0 */ + err |= __put_user(0x203c0000, (long *)(frame->retcode + 0)); + err |= __put_user(0x00ad4e40, (long *)(frame->retcode + 4)); + + if (err) + goto give_sigsegv; + + push_cache((unsigned long) &frame->retcode); + + /* Set up registers for signal handler */ + wrusp((unsigned long) frame); + regs->pc = (unsigned long) ka->sa.sa_handler; + +adjust_stack: + /* Prepare to skip over the extra stuff in the exception frame. */ + if (regs->stkadj) { + struct pt_regs *tregs = + (struct pt_regs *)((ulong)regs + regs->stkadj); +#ifdef DEBUG + printk(KERN_DEBUG "Performing stackadjust=%04x\n", + regs->stkadj); +#endif + /* This must be copied with decreasing addresses to + handle overlaps. */ + tregs->vector = 0; + tregs->format = 0; + tregs->pc = regs->pc; + tregs->sr = regs->sr; + } + return; + +give_sigsegv: + force_sigsegv(sig, current); + goto adjust_stack; +} + +static inline void +handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler) +{ + switch (regs->d0) { + case -ERESTARTNOHAND: + if (!has_handler) + goto do_restart; + regs->d0 = -EINTR; + break; + + case -ERESTARTSYS: + if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) { + regs->d0 = -EINTR; + break; + } + /* fallthrough */ + case -ERESTARTNOINTR: +do_restart: + regs->d0 = regs->orig_d0; + regs->pc -= 2; + break; + } +} + +/* + * OK, we're invoking a handler + */ +static void +handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *oldset, struct pt_regs *regs) +{ + /* are we from a system call? */ + if (regs->orig_d0 >= 0) + /* If so, check system call restarting.. */ + handle_restart(regs, ka, 1); + + /* set up the stack frame */ + if (ka->sa.sa_flags & SA_SIGINFO) + setup_rt_frame(sig, ka, info, oldset, regs); + else + setup_frame(sig, ka, oldset, regs); + + if (ka->sa.sa_flags & SA_ONESHOT) + ka->sa.sa_handler = SIG_DFL; + + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) + sigaddset(¤t->blocked, sig); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); +} + +/* + * Note that 'init' is a special process: it doesn't get signals it doesn't + * want to handle. Thus you cannot kill init even with a SIGKILL even by + * mistake. + */ +asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs) +{ + siginfo_t info; + struct k_sigaction ka; + int signr; + + current->thread.esp0 = (unsigned long) regs; + + if (!oldset) + oldset = ¤t->blocked; + + signr = get_signal_to_deliver(&info, &ka, regs, NULL); + if (signr > 0) { + /* Whee! Actually deliver the signal. */ + handle_signal(signr, &ka, &info, oldset, regs); + return 1; + } + + /* Did we come from a system call? */ + if (regs->orig_d0 >= 0) + /* Restart the system call - no handlers present */ + handle_restart(regs, NULL, 0); + + return 0; +} --- /dev/null +++ b/arch/m68k/coldfire/common/traps.c @@ -0,0 +1,457 @@ +/* + * linux/arch/m68knommu/kernel/traps.c + * + * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Jason Jin Jason.Jin@freescale.com + * Shrek Wu B16972@freescale.com + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +/* + * Sets up all exception vectors + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +static char const * const vec_names[] = { + "RESET SP", "RESET PC", "BUS ERROR", "ADDRESS ERROR", + "ILLEGAL INSTRUCTION", "ZERO DIVIDE", "CHK", "TRAPcc", + "PRIVILEGE VIOLATION", "TRACE", "LINE 1010", "LINE 1111", + "UNASSIGNED RESERVED 12", "COPROCESSOR PROTOCOL VIOLATION", + "FORMAT ERROR", "UNINITIALIZED INTERRUPT", + "UNASSIGNED RESERVED 16", "UNASSIGNED RESERVED 17", + "UNASSIGNED RESERVED 18", "UNASSIGNED RESERVED 19", + "UNASSIGNED RESERVED 20", "UNASSIGNED RESERVED 21", + "UNASSIGNED RESERVED 22", "UNASSIGNED RESERVED 23", + "SPURIOUS INTERRUPT", "LEVEL 1 INT", "LEVEL 2 INT", "LEVEL 3 INT", + "LEVEL 4 INT", "LEVEL 5 INT", "LEVEL 6 INT", "LEVEL 7 INT", + "SYSCALL", "TRAP #1", "TRAP #2", "TRAP #3", + "TRAP #4", "TRAP #5", "TRAP #6", "TRAP #7", + "TRAP #8", "TRAP #9", "TRAP #10", "TRAP #11", + "TRAP #12", "TRAP #13", "TRAP #14", "TRAP #15", + "FPCP BSUN", "FPCP INEXACT", "FPCP DIV BY 0", "FPCP UNDERFLOW", + "FPCP OPERAND ERROR", "FPCP OVERFLOW", "FPCP SNAN", + "FPCP UNSUPPORTED OPERATION", + "MMU CONFIGURATION ERROR" +}; + +asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address, + unsigned long error_code); +asmlinkage void trap_c(struct frame *fp); +extern void __init coldfire_trap_init(void); + +void __init trap_init(void) +{ + coldfire_trap_init(); +} + +/* The following table converts the FS encoding of a ColdFire + exception stack frame into the error_code value needed by + do_fault. */ + +static const unsigned char fs_err_code[] = { + 0, /* 0000 */ + 0, /* 0001 */ + 0, /* 0010 */ + 0, /* 0011 */ + 1, /* 0100 */ + 0, /* 0101 */ + 0, /* 0110 */ + 0, /* 0111 */ + 2, /* 1000 */ + 3, /* 1001 */ + 2, /* 1010 */ + 0, /* 1011 */ + 1, /* 1100 */ + 1, /* 1101 */ + 0, /* 1110 */ + 0 /* 1111 */ +}; + +#ifdef DEBUG +static const char *fs_err_msg[16] = { + "Normal", + "Reserved", + "Interrupt during debug service routine", + "Reserved", + "X Protection", + "TLB X miss (opword)", + "TLB X miss (ext. word)", + "IFP in emulator mode", + "W Protection", + "Write error", + "TLB W miss", + "Reserved", + "R Protection", + "R/RMW Protection", + "TLB R miss", + "OEP in emulator mode", +}; +#endif + +static inline void access_errorCF(struct frame *fp) +{ + unsigned long int mmusr, complainingAddress; + unsigned int err_code, fs; + int need_page_fault; + + mmusr = fp->ptregs.mmusr; + complainingAddress = fp->ptregs.mmuar; +#ifdef DEBUG + printk(KERN_DEBUG "pc %#lx, mmusr %#lx, complainingAddress %#lx\n", \ + fp->ptregs.pc, mmusr, complainingAddress); +#endif + + /* + * error_code: + * bit 0 == 0 means no page found, 1 means protection fault + * bit 1 == 0 means read, 1 means write + */ + + fs = (fp->ptregs.fs2 << 2) | fp->ptregs.fs1; + switch (fs) { + case 5: /* 0101 TLB opword X miss */ + need_page_fault = cf_tlb_miss(&fp->ptregs, 0, 0, 0); + complainingAddress = fp->ptregs.pc; + break; + case 6: /* 0110 TLB extension word X miss */ + need_page_fault = cf_tlb_miss(&fp->ptregs, 0, 0, 1); + complainingAddress = fp->ptregs.pc + sizeof(long); + break; + case 10: /* 1010 TLB W miss */ + need_page_fault = cf_tlb_miss(&fp->ptregs, 1, 1, 0); + break; + case 14: /* 1110 TLB R miss */ + need_page_fault = cf_tlb_miss(&fp->ptregs, 0, 1, 0); + break; + default: + /* 0000 Normal */ + /* 0001 Reserved */ + /* 0010 Interrupt during debug service routine */ + /* 0011 Reserved */ + /* 0100 X Protection */ + /* 0111 IFP in emulator mode */ + /* 1000 W Protection*/ + /* 1001 Write error*/ + /* 1011 Reserved*/ + /* 1100 R Protection*/ + /* 1101 R Protection*/ + /* 1111 OEP in emulator mode*/ + need_page_fault = 1; + break; + } + + if (need_page_fault) { + err_code = fs_err_code[fs]; + if ((fs == 13) && (mmusr & MMUSR_WF)) /* rd-mod-wr access */ + err_code |= 2; /* bit1 - write, bit0 - protection */ + do_page_fault(&fp->ptregs, complainingAddress, err_code); + } +} + +void die_if_kernel(char *str, struct pt_regs *fp, int nr) +{ + if (!(fp->sr & PS_S)) + return; + + console_verbose(); + printk(KERN_EMERG "%s: %08x\n", str, nr); + printk(KERN_EMERG "PC: [<%08lx>]", fp->pc); + print_symbol(" %s", fp->pc); + printk(KERN_EMERG "\nSR: %04x SP: %p a2: %08lx\n", + fp->sr, fp, fp->a2); + printk(KERN_EMERG "d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n", + fp->d0, fp->d1, fp->d2, fp->d3); + printk(KERN_EMERG "d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n", + fp->d4, fp->d5, fp->a0, fp->a1); + + printk(KERN_EMERG "Process %s (pid: %d, stackpage=%08lx)\n", + current->comm, current->pid, PAGE_SIZE+(unsigned long)current); + show_stack(NULL, (unsigned long *)fp); + do_exit(SIGSEGV); +} + +asmlinkage void buserr_c(struct frame *fp) +{ + unsigned int fs; + + /* Only set esp0 if coming from user mode */ + if (user_mode(&fp->ptregs)) + current->thread.esp0 = (unsigned long) fp; + + fs = (fp->ptregs.fs2 << 2) | fp->ptregs.fs1; +#if defined(DEBUG) + printk(KERN_DEBUG "*** Bus Error *** (%x)%s\n", fs, + fs_err_msg[fs & 0xf]); +#endif + switch (fs) { + case 0x5: + case 0x6: + case 0x7: + case 0x9: + case 0xa: + case 0xd: + case 0xe: + case 0xf: + access_errorCF(fp); + break; + default: + die_if_kernel("bad frame format", &fp->ptregs, 0); +#if defined(DEBUG) + printk(KERN_DEBUG "Unknown SIGSEGV - 4\n"); +#endif + force_sig(SIGSEGV, current); + } +} + +void show_trace(unsigned long *stack) +{ + unsigned long *endstack; + unsigned long addr; + int i; + + printk(KERN_INFO "Call Trace:"); + addr = (unsigned long)stack + THREAD_SIZE - 1; + endstack = (unsigned long *)(addr & -THREAD_SIZE); + i = 0; + while (stack + 1 <= endstack) { + addr = *stack++; + /* + * If the address is either in the text segment of the + * kernel, or in the region which contains vmalloc'ed + * memory, it *may* be the address of a calling + * routine; if so, print it so that someone tracing + * down the cause of the crash will be able to figure + * out the call path that was taken. + */ + if (__kernel_text_address(addr)) { +#ifndef CONFIG_KALLSYMS + if (i % 5 == 0) + printk("\n "); +#endif + printk(" [<%08lx>] %pS\n", addr, (void *)addr); + i++; + } + } + printk(KERN_INFO "\n"); +} + +int kstack_depth_to_print = 48; +void show_stack(struct task_struct *task, unsigned long *stack) +{ + unsigned long *p; + unsigned long *endstack; + int i; + + if (!stack) { + if (task) + stack = (unsigned long *)task->thread.esp0; + else + stack = (unsigned long *)&stack; + } + endstack = (unsigned long *)(((unsigned long)stack + THREAD_SIZE - 1) + & -THREAD_SIZE); + + printk(KERN_INFO "Stack from %08lx:", (unsigned long)stack); + p = stack; + for (i = 0; i < kstack_depth_to_print; i++) { + if (p + 1 > endstack) + break; + if (i % 8 == 0) + printk("\n "); + printk(" %08lx", *p++); + } + printk("\n"); + show_trace(stack); +} + +void bad_super_trap(struct frame *fp) +{ + console_verbose(); + if (fp->ptregs.vector < sizeof(vec_names)/sizeof(vec_names[0])) + printk(KERN_WARNING "*** %s *** FORMAT=%X\n", + vec_names[fp->ptregs.vector], + fp->ptregs.format); + else + printk(KERN_WARNING "*** Exception %d *** FORMAT=%X\n", + fp->ptregs.vector, + fp->ptregs.format); + printk(KERN_WARNING "Current process id is %d\n", current->pid); + die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0); +} + +asmlinkage void trap_c(struct frame *fp) +{ + int sig; + siginfo_t info; + + if (fp->ptregs.sr & PS_S) { + if (fp->ptregs.vector == VEC_TRACE) { + /* traced a trapping instruction */ + current->ptrace |= PT_DTRACE; + } else + bad_super_trap(fp); + return; + } + + /* send the appropriate signal to the user program */ + switch (fp->ptregs.vector) { + case VEC_ADDRERR: + info.si_code = BUS_ADRALN; + sig = SIGBUS; + break; + case VEC_ILLEGAL: + case VEC_LINE10: + case VEC_LINE11: + info.si_code = ILL_ILLOPC; + sig = SIGILL; + break; + case VEC_PRIV: + info.si_code = ILL_PRVOPC; + sig = SIGILL; + break; + case VEC_COPROC: + info.si_code = ILL_COPROC; + sig = SIGILL; + break; + case VEC_TRAP1: /* gdbserver breakpoint */ + fp->ptregs.pc -= 2; + info.si_code = TRAP_TRACE; + sig = SIGTRAP; + break; + case VEC_TRAP2: + case VEC_TRAP3: + case VEC_TRAP4: + case VEC_TRAP5: + case VEC_TRAP6: + case VEC_TRAP7: + case VEC_TRAP8: + case VEC_TRAP9: + case VEC_TRAP10: + case VEC_TRAP11: + case VEC_TRAP12: + case VEC_TRAP13: + case VEC_TRAP14: + info.si_code = ILL_ILLTRP; + sig = SIGILL; + break; + case VEC_FPBRUC: + case VEC_FPOE: + case VEC_FPNAN: + info.si_code = FPE_FLTINV; + sig = SIGFPE; + break; + case VEC_FPIR: + info.si_code = FPE_FLTRES; + sig = SIGFPE; + break; + case VEC_FPDIVZ: + info.si_code = FPE_FLTDIV; + sig = SIGFPE; + break; + case VEC_FPUNDER: + info.si_code = FPE_FLTUND; + sig = SIGFPE; + break; + case VEC_FPOVER: + info.si_code = FPE_FLTOVF; + sig = SIGFPE; + break; + case VEC_ZERODIV: + info.si_code = FPE_INTDIV; + sig = SIGFPE; + break; + case VEC_CHK: + case VEC_TRAP: + info.si_code = FPE_INTOVF; + sig = SIGFPE; + break; + case VEC_TRACE: /* ptrace single step */ + info.si_code = TRAP_TRACE; + sig = SIGTRAP; + break; + case VEC_TRAP15: /* breakpoint */ + info.si_code = TRAP_BRKPT; + sig = SIGTRAP; + break; + default: + info.si_code = ILL_ILLOPC; + sig = SIGILL; + break; + } + info.si_signo = sig; + info.si_errno = 0; + switch (fp->ptregs.format) { + default: + info.si_addr = (void *) fp->ptregs.pc; + break; + case 2: + info.si_addr = (void *) fp->un.fmt2.iaddr; + break; + case 7: + info.si_addr = (void *) fp->un.fmt7.effaddr; + break; + case 9: + info.si_addr = (void *) fp->un.fmt9.iaddr; + break; + case 10: + info.si_addr = (void *) fp->un.fmta.daddr; + break; + case 11: + info.si_addr = (void *) fp->un.fmtb.daddr; + break; + } + force_sig_info(sig, &info, current); +} + +asmlinkage void set_esp0(unsigned long ssp) +{ + current->thread.esp0 = ssp; +} + +/* + * The architecture-independent backtrace generator + */ +void dump_stack(void) +{ + unsigned long stack; + + show_stack(current, &stack); +} +EXPORT_SYMBOL(dump_stack); + +#ifdef CONFIG_M68KFPU_EMU +asmlinkage void fpemu_signal(int signal, int code, void *addr) +{ + siginfo_t info; + + info.si_signo = signal; + info.si_errno = 0; + info.si_code = code; + info.si_addr = addr; + force_sig_info(signal, &info, current); +} +#endif --- a/arch/m68k/include/asm/atomic.h +++ b/arch/m68k/include/asm/atomic.h @@ -1,3 +1,11 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + #ifndef __ARCH_M68K_ATOMIC__ #define __ARCH_M68K_ATOMIC__ @@ -30,12 +38,20 @@ static inline void atomic_add(int i, atomic_t *v) { - __asm__ __volatile__("addl %1,%0" : "+m" (*v) : ASM_DI (i)); +#ifndef CONFIG_COLDFIRE + __asm__ __volatile__("addl %1,%0" : "+m" (*v) : ASM_DI(i)); +#else + __asm__ __volatile__("addl %1,%0" : "=m" (*v) : ASM_DI(i), "m" (*v)); +#endif } static inline void atomic_sub(int i, atomic_t *v) { - __asm__ __volatile__("subl %1,%0" : "+m" (*v) : ASM_DI (i)); +#ifndef CONFIG_COLDFIRE + __asm__ __volatile__("subl %1,%0" : "+m" (*v) : ASM_DI(i)); +#else + __asm__ __volatile__("subl %1,%0" : "=m" (*v) : ASM_DI(i), "m" (*v)); +#endif } static inline void atomic_inc(atomic_t *v) @@ -55,6 +71,14 @@ static inline int atomic_dec_and_test(at return c != 0; } +static inline int atomic_dec_and_test_lt(volatile atomic_t *v) +{ + char c; + __asm__ __volatile__("subql #1,%1; slt %0" : "=d" (c), "=m" (*v) + : "m" (*v)); + return c != 0 ; +} + static inline int atomic_inc_and_test(atomic_t *v) { char c; @@ -167,9 +191,14 @@ static inline int atomic_sub_and_test(in static inline int atomic_add_negative(int i, atomic_t *v) { char c; +#ifndef CONFIG_COLDFIRE __asm__ __volatile__("addl %2,%1; smi %0" : "=d" (c), "+m" (*v) : "id" (i)); +#else + __asm__ __volatile__("addl %2,%1; smi %0" : "=d" (c), "=m" (*v) + : "d" (i) , "m" (*v)); +#endif return c != 0; } --- a/arch/m68k/include/asm/bitops_mm.h +++ b/arch/m68k/include/asm/bitops_mm.h @@ -1,12 +1,18 @@ -#ifndef _M68K_BITOPS_H -#define _M68K_BITOPS_H /* * Copyright 1992, Linus Torvalds. * + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive * for more details. */ +#ifndef _M68K_BITOPS_H +#define _M68K_BITOPS_H + +#ifdef CONFIG_COLDFIRE +#include +#else #ifndef _LINUX_BITOPS_H #error only can be included directly @@ -463,4 +469,6 @@ static inline unsigned long generic_find #endif /* __KERNEL__ */ +#endif /* CONFIG_COLDFIRE */ + #endif /* _M68K_BITOPS_H */ --- a/arch/m68k/include/asm/bootinfo.h +++ b/arch/m68k/include/asm/bootinfo.h @@ -2,6 +2,7 @@ ** asm/bootinfo.h -- Definition of the Linux/m68k boot information structure ** ** Copyright 1992 by Greg Harp + * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved. ** ** This file is subject to the terms and conditions of the GNU General Public ** License. See the file COPYING in the main directory of this archive @@ -24,6 +25,47 @@ #ifndef _M68K_BOOTINFO_H #define _M68K_BOOTINFO_H +#ifndef __ASSEMBLY__ +/* + * UBoot Support + * + * bd_info structure from uboot1.3.2/arch/m68k/include/asm/u-boot.h + */ +struct bd_info { + unsigned long bi_memstart; /* start of DRAM memory */ + unsigned long bi_memsize; /* size of DRAM memory in bytes */ + unsigned long bi_flashstart; /* start of FLASH memory */ + unsigned long bi_flashsize; /* size of FLASH memory */ + unsigned long bi_flashoffset; /* reserved area for startup monitor */ + unsigned long bi_sramstart; /* start of SRAM memory */ + unsigned long bi_sramsize; /* size of SRAM memory */ + unsigned long bi_mbar_base; /* base of internal registers */ + unsigned long bi_bootflags; /* boot / reboot flag (for LynxOS) */ + unsigned long bi_boot_params; /* where this board expects params */ + unsigned long bi_ip_addr; /* IP Address */ + unsigned char bi_enet0addr[6]; /* Ethernet 0 mac address */ + unsigned short bi_ethspeed; /* Ethernet speed in Mbps */ + unsigned long bi_intfreq; /* Internal Freq, in MHz */ + unsigned long bi_busfreq; /* Bus Freq, in MHz */ +#ifdef UBOOT_EXTRA_CLOCK + unsigned long bi_inpfreq; /* input Freq in MHz */ + unsigned long bi_vcofreq; /* vco Freq in MHz */ + unsigned long bi_flbfreq; /* Flexbus Freq in MHz */ +#endif + unsigned long bi_baudrate; /* Console Baudrate */ + unsigned char bi_enet1addr[6]; /* eth1 mac address */ + unsigned char bi_enet2addr[6]; /* eth2 mac address */ + unsigned char bi_enet3addr[6]; /* eth3 mac address */ +}; + +struct uboot_record { + struct bd_info *bdi; + unsigned long initrd_start; + unsigned long initrd_end; + unsigned long cmd_line_start; + unsigned long cmd_line_stop; +}; +#endif /* __ASSEMBLY__ */ /* * Bootinfo definitions --- a/arch/m68k/include/asm/cacheflush_mm.h +++ b/arch/m68k/include/asm/cacheflush_mm.h @@ -1,3 +1,11 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + #ifndef _M68K_CACHEFLUSH_H #define _M68K_CACHEFLUSH_H @@ -6,6 +14,10 @@ /* cache code */ #define FLUSH_I_AND_D (0x00000808) #define FLUSH_I (0x00000008) +#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1 +#ifdef CONFIG_COLDFIRE +#include +#else /* !CONFIG_COLDFIRE */ /* * Cache handling functions @@ -128,7 +140,6 @@ static inline void __flush_page_to_ram(v } } -#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1 #define flush_dcache_page(page) __flush_page_to_ram(page_address(page)) #define flush_dcache_mmap_lock(mapping) do { } while (0) #define flush_dcache_mmap_unlock(mapping) do { } while (0) @@ -154,4 +165,5 @@ static inline void copy_from_user_page(s memcpy(dst, src, len); } +#endif /* !CONFIG_COLDFIRE */ #endif /* _M68K_CACHEFLUSH_H */ --- /dev/null +++ b/arch/m68k/include/asm/cf-sram.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2009-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Author: Lanttor.Guo@freescale.com + * + * Providing on-chip SRAM allocation and free APIs to kernel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef CF_SRAM_H +#define CF_SRAM_H + +extern int declare_sram_pool(void *start, size_t size); + +extern void *sram_alloc(size_t len); +extern void sram_free(void *addr, size_t len); + +#endif --- /dev/null +++ b/arch/m68k/include/asm/cf_bitops.h @@ -0,0 +1,443 @@ +/* + * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ +#ifndef __CF_BITOPS__ +#define __CF_BITOPS__ + +#ifndef _LINUX_BITOPS_H +#error only can be included directly +#endif + +#include + +#define test_and_set_bit(nr, vaddr) \ + (__builtin_constant_p(nr) ? \ + __constant_coldfire_test_and_set_bit(nr, vaddr) : \ + __generic_coldfire_test_and_set_bit(nr, vaddr)) + +static inline int __constant_coldfire_test_and_set_bit(int nr, + volatile void *vaddr) +{ + char retval; + volatile char *p = &((volatile char *)vaddr)[(nr^31) >> 3]; + __asm__ __volatile__ ("bset %2,(%4); sne %0" + : "=d" (retval), "=m" (*p) + : "di" (nr & 7), "m" (*p), "a" (p)); + return retval; +} + +static inline int __generic_coldfire_test_and_set_bit(int nr, + volatile void *vaddr) +{ + char retval; + + __asm__ __volatile__ ("bset %2,%1; sne %0" + : "=d" (retval), "=m" (((volatile char *)vaddr)[(nr^31) >> 3]) + : "d" (nr) + : "memory"); + return retval; +} +#define __test_and_set_bit(nr, vaddr) test_and_set_bit(nr, vaddr) + +#define set_bit(nr, vaddr) \ + (__builtin_constant_p(nr) ? \ + __constant_coldfire_set_bit(nr, vaddr) : \ + __generic_coldfire_set_bit(nr, vaddr)) + +static inline void __constant_coldfire_set_bit(int nr, + volatile void *vaddr) +{ + volatile char *p = &((volatile char *)vaddr)[(nr^31) >> 3]; + __asm__ __volatile__ ("bset %1,(%3)" + : "=m" (*p) : "di" (nr & 7), "m" (*p), "a" (p)); +} + +static inline void __generic_coldfire_set_bit(int nr, + volatile void *vaddr) +{ + __asm__ __volatile__ ("bset %1,%0" + : "=m" (((volatile char *)vaddr)[(nr^31) >> 3]) + : "d" (nr) + : "memory"); +} +#define __set_bit(nr, vaddr) set_bit(nr, vaddr) + +#define test_and_clear_bit(nr, vaddr) \ + (__builtin_constant_p(nr) ? \ + __constant_coldfire_test_and_clear_bit(nr, vaddr) : \ + __generic_coldfire_test_and_clear_bit(nr, vaddr)) + +static inline int __constant_coldfire_test_and_clear_bit(int nr, + volatile void *vaddr) +{ + char retval; + volatile char *p = &((volatile char *)vaddr)[(nr^31) >> 3]; + + __asm__ __volatile__ ("bclr %2,(%4); sne %0" + : "=d" (retval), "=m" (*p) + : "id" (nr & 7), "m" (*p), "a" (p)); + + return retval; +} + +static inline int __generic_coldfire_test_and_clear_bit(int nr, + volatile void *vaddr) +{ + char retval; + + __asm__ __volatile__ ("bclr %2,%1; sne %0" + : "=d" (retval), "=m" (((volatile char *)vaddr)[(nr^31) >> 3]) + : "d" (nr & 7) + : "memory"); + + return retval; +} +#define __test_and_clear_bit(nr, vaddr) test_and_clear_bit(nr, vaddr) + +/* + * clear_bit() doesn't provide any barrier for the compiler. + */ +#define smp_mb__before_clear_bit() barrier() +#define smp_mb__after_clear_bit() barrier() + +#define clear_bit(nr, vaddr) \ + (__builtin_constant_p(nr) ? \ + __constant_coldfire_clear_bit(nr, vaddr) : \ + __generic_coldfire_clear_bit(nr, vaddr)) + +static inline void __constant_coldfire_clear_bit(int nr, + volatile void *vaddr) +{ + volatile char *p = &((volatile char *)vaddr)[(nr^31) >> 3]; + __asm__ __volatile__ ("bclr %1,(%3)" + : "=m" (*p) : "id" (nr & 7), "m" (*p), "a" (p)); +} + +static inline void __generic_coldfire_clear_bit(int nr, + volatile void *vaddr) +{ + __asm__ __volatile__ ("bclr %1,%0" + : "=m" (((volatile char *)vaddr)[(nr^31) >> 3]) + : "d" (nr) + : "memory"); +} +#define __clear_bit(nr, vaddr) clear_bit(nr, vaddr) + +#define test_and_change_bit(nr, vaddr) \ + (__builtin_constant_p(nr) ? \ + __constant_coldfire_test_and_change_bit(nr, vaddr) : \ + __generic_coldfire_test_and_change_bit(nr, vaddr)) + +static inline int __constant_coldfire_test_and_change_bit(int nr, + volatile void *vaddr) +{ + char retval; + volatile char *p = &((volatile char *)vaddr)[(nr^31) >> 3]; + + __asm__ __volatile__ ("bchg %2,(%4); sne %0" + : "=d" (retval), "=m" (*p) + : "id" (nr & 7), "m" (*p), "a" (p)); + + return retval; +} + +static inline int __generic_coldfire_test_and_change_bit(int nr, + volatile void *vaddr) +{ + char retval; + + __asm__ __volatile__ ("bchg %2,%1; sne %0" + : "=d" (retval), "=m" (((volatile char *)vaddr)[(nr^31) >> 3]) + : "id" (nr) + : "memory"); + + return retval; +} +#define __test_and_change_bit(nr, vaddr) test_and_change_bit(nr, vaddr) +#define __change_bit(nr, vaddr) change_bit(nr, vaddr) + +#define change_bit(nr, vaddr) \ + (__builtin_constant_p(nr) ? \ + __constant_coldfire_change_bit(nr, vaddr) : \ + __generic_coldfire_change_bit(nr, vaddr)) + +static inline void __constant_coldfire_change_bit(int nr, + volatile void *vaddr) +{ + volatile char *p = &((volatile char *)vaddr)[(nr^31) >> 3]; + __asm__ __volatile__ ("bchg %1,(%3)" + : "=m" (*p) : "id" (nr & 7), "m" (*p), "a" (p)); +} + +static inline void __generic_coldfire_change_bit(int nr, + volatile void *vaddr) +{ + __asm__ __volatile__ ("bchg %1,%0" + : "=m" (((volatile char *)vaddr)[(nr^31) >> 3]) + : "d" (nr) + : "memory"); +} + +static inline int test_bit(int nr, const unsigned long *vaddr) +{ + return (vaddr[nr >> 5] & (1UL << (nr & 31))) != 0; +} + +static inline unsigned long ffz(unsigned long word) +{ + unsigned long result = 0; + + while (word & 1) { + result++; + word >>= 1; + } + return result; +} + +/* find_next_zero_bit() finds the first zero bit in a bit string of length + * 'size' bits, starting the search at bit 'offset'. This is largely based + * on Linus's ALPHA routines. + */ +static inline unsigned long find_next_zero_bit(void *addr, + unsigned long size, unsigned long offset) +{ + unsigned long *p = ((unsigned long *) addr) + (offset >> 5); + unsigned long result = offset & ~31UL; + unsigned long tmp; + + if (offset >= size) + return size; + size -= result; + offset &= 31UL; + if (offset) { + tmp = *(p++); + tmp |= ~0UL >> (32-offset); + if (size < 32) + goto found_first; + if (~tmp) + goto found_middle; + size -= 32; + result += 32; + } + while (size & ~31UL) { + tmp = *(p++); + if (~tmp) + goto found_middle; + result += 32; + size -= 32; + } + if (!size) + return result; + tmp = *p; + +found_first: + tmp |= ~0UL >> size; +found_middle: + return result + ffz(tmp); +} + +#define find_first_zero_bit(addr, size) find_next_zero_bit(((void *)addr), \ + (size), 0) + +/* Ported from included/linux/bitops.h */ +static inline int ffs(int x) +{ + int r = 1; + + if (!x) + return 0; + if (!(x & 0xffff)) { + x >>= 16; + r += 16; + } + if (!(x & 0xff)) { + x >>= 8; + r += 8; + } + if (!(x & 0xf)) { + x >>= 4; + r += 4; + } + if (!(x & 3)) { + x >>= 2; + r += 2; + } + if (!(x & 1)) { + x >>= 1; + r += 1; + } + return r; +} +#define __ffs(x) (ffs(x) - 1) + +/* find_next_bit - find the next set bit in a memory region + * (from asm-ppc/bitops.h) + */ +static inline unsigned long find_next_bit(const unsigned long *addr, + unsigned long size, unsigned long offset) +{ + unsigned int *p = ((unsigned int *) addr) + (offset >> 5); + unsigned int result = offset & ~31UL; + unsigned int tmp; + + if (offset >= size) + return size; + size -= result; + offset &= 31UL; + if (offset) { + tmp = *p++; + tmp &= ~0UL << offset; + if (size < 32) + goto found_first; + if (tmp) + goto found_middle; + size -= 32; + result += 32; + } + while (size >= 32) { + tmp = *p++; + if (tmp != 0) + goto found_middle; + result += 32; + size -= 32; + } + if (!size) + return result; + tmp = *p; + +found_first: + tmp &= ~0UL >> (32 - size); + if (tmp == 0UL) /* Are any bits set? */ + return result + size; /* Nope. */ +found_middle: + return result + __ffs(tmp); +} + +#define find_first_bit(addr, size) find_next_bit((addr), (size), 0) + +#ifdef __KERNEL__ + +/* Ported from include/linux/bitops.h */ +static inline int fls(int x) +{ + int r = 32; + + if (!x) + return 0; + if (!(x & 0xffff0000u)) { + x <<= 16; + r -= 16; + } + if (!(x & 0xff000000u)) { + x <<= 8; + r -= 8; + } + if (!(x & 0xf0000000u)) { + x <<= 4; + r -= 4; + } + if (!(x & 0xc0000000u)) { + x <<= 2; + r -= 2; + } + if (!(x & 0x80000000u)) { + x <<= 1; + r -= 1; + } + return r; +} + +static inline int __fls(int x) +{ + return fls(x) - 1; +} + +#include +#include +#include +#include + +#define minix_find_first_zero_bit(addr, size) find_next_zero_bit((addr), \ + (size), 0) +#define minix_test_and_set_bit(nr, addr) test_and_set_bit((nr), \ + (unsigned long *)(addr)) +#define minix_set_bit(nr, addr) set_bit((nr), \ + (unsigned long *)(addr)) +#define minix_test_and_clear_bit(nr, addr) test_and_clear_bit((nr), \ + (unsigned long *)(addr)) + +static inline int minix_test_bit(int nr, const volatile unsigned long *vaddr) +{ + int *a = (int *)vaddr; + int mask; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + return ((mask & *a) != 0); +} + +#define ext2_set_bit(nr, addr) test_and_set_bit((nr) ^ 24, \ + (unsigned long *)(addr)) +#define ext2_set_bit_atomic(lock, nr, addr) test_and_set_bit((nr) ^ 24, \ + (unsigned long *)(addr)) +#define ext2_clear_bit(nr, addr) test_and_clear_bit((nr) ^ 24, \ + (unsigned long *)(addr)) +#define ext2_clear_bit_atomic(lock, nr, addr) test_and_clear_bit((nr) ^ 24, \ + (unsigned long *)(addr)) + +static inline int ext2_test_bit(int nr, const void *vaddr) +{ + const unsigned char *p = vaddr; + return (p[nr >> 3] & (1U << (nr & 7))) != 0; +} + +static inline int ext2_find_first_zero_bit(const void *vaddr, unsigned size) +{ + const unsigned long *p = vaddr, *addr = vaddr; + int res; + + if (!size) + return 0; + + size = (size >> 5) + ((size & 31) > 0); + while (*p++ == ~0UL) { + if (--size == 0) + return (p - addr) << 5; + } + + --p; + for (res = 0; res < 32; res++) + if (!ext2_test_bit(res, p)) + break; + return (p - addr) * 32 + res; +} + +static inline int ext2_find_next_zero_bit(const void *vaddr, unsigned size, + unsigned offset) +{ + const unsigned long *addr = vaddr; + const unsigned long *p = addr + (offset >> 5); + int bit = offset & 31UL, res; + + if (offset >= size) + return size; + + if (bit) { + /* Look for zero in first longword */ + for (res = bit; res < 32; res++) + if (!ext2_test_bit(res, p)) + return (p - addr) * 32 + res; + p++; + } + /* No zero yet, search remaining full bytes for a zero */ + res = ext2_find_first_zero_bit(p, size - 32 * (p - addr)); + return (p - addr) * 32 + res; +} + +#endif /* KERNEL */ + +#endif /* __CF_BITOPS__ */ --- /dev/null +++ b/arch/m68k/include/asm/cf_cacheflush.h @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#ifndef M68K_CF_CACHEFLUSH_H +#define M68K_CF_CACHEFLUSH_H + +#ifdef CONFIG_M5445X +#include "cf_5445x_cacheflush.h" +#elif defined(CONFIG_M5441X) +#include "cf_5441x_cacheflush.h" +#elif defined(CONFIG_M547X_8X) +#include "cf_548x_cacheflush.h" +#endif + +#endif /* M68K_CF_CACHEFLUSH_H */ --- /dev/null +++ b/arch/m68k/include/asm/cf_entry.h @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#ifndef __CF_M68K_ENTRY_H +#define __CF_M68K_ENTRY_H + +#include +#include +#include +#include + +/* + * Stack layout in 'ret_from_exception': + * + * This allows access to the syscall arguments in registers d1-d5 + * + * 0(sp) - d1 + * 4(sp) - d2 + * 8(sp) - d3 + * C(sp) - d4 + * 10(sp) - d5 + * 14(sp) - a0 + * 18(sp) - a1 + * 1C(sp) - a2 + * 20(sp) - d0 + * 24(sp) - orig_d0 + * 28(sp) - stack adjustment + * 2C(sp) - sr + * 2E(sp) - pc + * 32(sp) - format & vector + * 36(sp) - MMUSR + * 3A(sp) - MMUAR + */ + +/* + * 97/05/14 Andreas: Register %a2 is now set to the current task throughout + * the whole kernel. + */ + +/* the following macro is used when enabling interrupts */ +/* portable version */ +#define ALLOWINT (~0x700) +#define MAX_NOINT_IPL 0 + +#ifdef __ASSEMBLY__ + +#define curptr a2 + +LFLUSH_I_AND_D = 0x00000808 +LSIGTRAP = 5 + +/* process bits for task_struct.ptrace */ +PT_TRACESYS_OFF = 3 +PT_TRACESYS_BIT = 1 +PT_PTRACED_OFF = 3 +PT_PTRACED_BIT = 0 +PT_DTRACE_OFF = 3 +PT_DTRACE_BIT = 2 + +#define SAVE_ALL_INT save_all_int +#define SAVE_ALL_SYS save_all_sys +#define RESTORE_ALL restore_all +/* + * This defines the normal kernel pt-regs layout. + * + * regs a3-a6 and d6-d7 are preserved by C code + * the kernel doesn't mess with usp unless it needs to + */ + +/* + * a -1 in the orig_d0 field signifies + * that the stack frame is NOT for syscall + */ +.macro save_all_int + movel MMUSR, % sp@ - + movel MMUAR, % sp@ - + clrl % sp@ - | stk_adj + pea - 1 : w | orig d0 + movel % d0, % sp@ - | d0 + subal #(8*4), % sp + moveml % d1-%d5/%a0-%a1/%curptr, % sp@ +.endm + +.macro save_all_sys + movel MMUSR, % sp@- + movel MMUAR, % sp@- + clrl % sp@ - | stk_adj + movel % d0, % sp@ - | orig d0 + movel % d0, % sp@ - | d0 + subal #(8*4), % sp + moveml % d1-%d5/%a0-%a1/%curptr, % sp@ +.endm + +.macro restore_all + moveml % sp@, % a0-%a1/%curptr/%d1-%d5 + addal #(8*4), % sp + movel % sp@+, % d0 | d0 + addql #4, % sp | orig d0 + addl % sp@+, % sp | stk_adj + addql #8, % sp | MMUAR & MMUSR + rte +.endm + +#define SWITCH_STACK_SIZE (6*4+4) /* includes return address */ + +#define SAVE_SWITCH_STACK save_switch_stack +#define RESTORE_SWITCH_STACK restore_switch_stack +#define GET_CURRENT(tmp) get_current tmp + +.macro save_switch_stack + subal #(6*4), % sp + moveml % a3-%a6/%d6-%d7, % sp@ +.endm + +.macro restore_switch_stack + moveml % sp@, % a3-%a6/%d6-%d7 + addal #(6*4), % sp +.endm + +.macro get_current reg = % d0 + movel % sp, \reg + andl #-THREAD_SIZE, \reg + movel \reg, % curptr + movel % curptr@, % curptr +.endm + +#else /* C source */ + +#define STR(X) STR1(X) +#define STR1(X) #X + +#define PT_OFF_ORIG_D0 0x24 +#define PT_OFF_FORMATVEC 0x32 +#define PT_OFF_SR 0x2C +#define SAVE_ALL_INT \ + "clrl %%sp@-;" /* stk_adj */ \ + "pea -1:w;" /* orig d0 = -1 */ \ + "movel %%d0,%%sp@-;" /* d0 */ \ + "subal #(8*4),%sp" \ + "moveml %%d1-%%d5/%%a0-%%a2,%%sp@" +#define GET_CURRENT(tmp) \ + "movel %%sp,"#tmp"\n\t" \ + "andw #-"STR(THREAD_SIZE)","#tmp"\n\t" \ + "movel "#tmp",%%a2\n\t" + +#endif + +#endif /* __CF_M68K_ENTRY_H */ --- /dev/null +++ b/arch/m68k/include/asm/cf_io.h @@ -0,0 +1,185 @@ +/* + * linux/include/asm-m68k/cf_io.h + * + * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * 9/30/08 JKM - Separated Coldfire pieces out from m68k. + * + * This file is subject to 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 __CF_IO__ +#define __CF_IO__ + +#ifdef __KERNEL__ + +#include +#include +#include + +#include + +#define readb_relaxed(addr) readb(addr) +#define readw_relaxed(addr) readw(addr) +#define readl_relaxed(addr) readl(addr) + +#ifdef CONFIG_PCI + +/* + * IO space in Coldfire + */ +#define inb_p inb +#define inw_p inw +#define inl_p inl +#define outb_p outb +#define outw_p outw +#define outl_p outl + +#ifndef CONFIG_COLDFIRE +#define inb(port) in_8(port) +#define outb(val, port) out_8((port), (val)) +#define inw(port) in_le16(port) +#define outw(val, port) out_le16((port), (val)) +#define inl(port) in_le32(port) +#define outl(val, port) out_le32((port), (val)) +#define insb(port, buf, nr) \ + raw_insb((u8 *)(port), (u8 *)(buf), (nr)) +#define outsb(port, buf, nr) \ + raw_outsb((u8 *)(port), (u8 *)(buf), (nr)) +#define insw(port, buf, nr) \ + raw_insw_swapw((u16 *)(port), (u16 *)(buf), (nr)) +#define outsw(port, buf, nr) \ + raw_outsw_swapw((u16 *)(port), (u16 *)(buf), (nr)) +#define insl(port, buf, nr) \ + raw_insw_swapw((u16 *)(port), (u16 *)(buf), (nr)<<1) +#define outsl(port, buf, nr) \ + raw_outsw_swapw((u16 *)(port), (u16 *)(buf), (nr)<<1) +#else +#define inb(port) pci_inb(port) +#define outb(val, port) pci_outb((val), (port)) +#define inw(port) pci_inw(port) +#define outw(val, port) pci_outw((val), (port)) +#define insb(a, b, c) \ + pci_insb((volatile unsigned char *)a, (unsigned char *)b, c) +#define insw(a, b, c) \ + pci_insw((volatile unsigned short *)a, (unsigned short *)b, c) +#define insl(a, b, c) \ + pci_insl((volatile unsigned long *)a, (unsigned long *)b, c) +#define outsb(a, b, c) \ + pci_outsb((volatile unsigned char *)a, (const unsigned char *)b, c) +#define outsw(a, b, c) \ + pci_outsw((volatile unsigned short *)a, (const unsigned short *)b, c) +#define outsl(a, b, c) \ + pci_outsl((volatile unsigned long *)a, (const unsigned long *)b, c) +#define inl(port) pci_inl(port) +#define outl(val, port) pci_outl((val), (port)) +#endif + +#else +/* no pci */ + +#define inb(port) in_8(port) +#define outb(val, port) out_8((port), (val)) +#define inw(port) in_le16(port) +#define outw(val, port) out_le16((port), (val)) +#define inl(port) in_le32(port) +#define outl(val, port) out_le32((port), (val)) +#define insb(port, buf, nr) \ + raw_insb((u8 *)(port), (u8 *)(buf), (nr)) +#define outsb(port, buf, nr) \ + raw_outsb((u8 *)(port), (u8 *)(buf), (nr)) +#define insw(port, buf, nr) \ + raw_insw_swapw((u16 *)(port), (u16 *)(buf), (nr)) +#define outsw(port, buf, nr) \ + raw_outsw_swapw((u16 *)(port), (u16 *)(buf), (nr)) +#define insl(port, buf, nr) \ + raw_insw_swapw((u16 *)(port), (u16 *)(buf), (nr)<<1) +#define outsl(port, buf, nr) \ + raw_outsw_swapw((u16 *)(port), (u16 *)(buf), (nr)<<1) + +#endif /* CONFIG_PCI */ + +#define mmiowb() + +static inline void __iomem *ioremap(unsigned long physaddr, unsigned long size) +{ + return __ioremap(physaddr, size, IOMAP_NOCACHE_SER); +} +static inline void __iomem *ioremap_nocache(unsigned long physaddr, + unsigned long size) +{ + return __ioremap(physaddr, size, IOMAP_NOCACHE_SER); +} +static inline void __iomem *ioremap_writethrough(unsigned long physaddr, + unsigned long size) +{ + return __ioremap(physaddr, size, IOMAP_WRITETHROUGH); +} +static inline void __iomem *ioremap_fullcache(unsigned long physaddr, + unsigned long size) +{ + return __ioremap(physaddr, size, IOMAP_FULL_CACHING); +} + +static inline void memset_io(volatile void __iomem *addr, + unsigned char val, int count) +{ + __builtin_memset((void __force *) addr, val, count); +} +static inline void memcpy_fromio(void *dst, const volatile void __iomem *src, + int count) +{ + __builtin_memcpy(dst, (void __force *) src, count); +} +static inline void memcpy_toio(volatile void __iomem *dst, + const void *src, int count) +{ + __builtin_memcpy((void __force *) dst, src, count); +} + +#define IO_SPACE_LIMIT 0xffffffff + +#endif /* __KERNEL__ */ + +#define __ARCH_HAS_NO_PAGE_ZERO_MAPPED 1 + +/* + * 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 + +#define __raw_readb(addr) \ + ({ unsigned char __v = (*(volatile unsigned char *) (addr)); __v; }) +#define __raw_readw(addr) \ + ({ unsigned short __v = (*(volatile unsigned short *) (addr)); __v; }) +#define __raw_readl(addr) \ + ({ unsigned long __v = (*(volatile unsigned long *) (addr)); __v; }) +#define __raw_writeb(b, addr) (void)((*(volatile unsigned char *) (addr)) = (b)) +#define __raw_writew(b, addr) \ + (void)((*(volatile unsigned short *) (addr)) = (b)) +#define __raw_writel(b, addr) (void)((*(volatile unsigned int *) (addr)) = (b)) + +#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)) + +#if !defined(readb) +#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)) +#endif /* readb */ + +#endif /* _IO_H */ --- /dev/null +++ b/arch/m68k/include/asm/cf_pgalloc.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#ifndef M68K_CF_PGALLOC_H +#define M68K_CF_PGALLOC_H +#include +#include +#include +#include +#include + +extern inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte) +{ + free_page((unsigned long) pte); +} + +extern const char bad_pmd_string[]; + +extern inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, + unsigned long address) +{ + unsigned long page = __get_free_page(GFP_KERNEL|__GFP_REPEAT); + + if (!page) + return NULL; + + memset((void *)page, 0, PAGE_SIZE); + return (pte_t *) (page); +} + +extern inline pmd_t *pmd_alloc_kernel(pgd_t *pgd, unsigned long address) +{ + return (pmd_t *) pgd; +} + +#define pmd_alloc_one_fast(mm, address) ({ BUG(); ((pmd_t *)1); }) +#define pmd_alloc_one(mm, address) ({ BUG(); ((pmd_t *)2); }) + +#define pte_alloc_one_fast(mm, addr) pte_alloc_one(mm, addr) + +#define pmd_populate(mm, pmd, page) (pmd_val(*pmd) = \ + (unsigned long)(page_address(page))) + +#define pmd_populate_kernel(mm, pmd, pte) (pmd_val(*pmd) = (unsigned long)(pte)) + +#define pmd_pgtable(pmd) pmd_page(pmd) + +static inline void __pte_free_tlb(struct mmu_gather *tlb, struct page *page, + unsigned long address) +{ + __free_page(page); +} + +#define __pmd_free_tlb(tlb, pmd, address) do { } while (0) + +static inline struct page *pte_alloc_one(struct mm_struct *mm, + unsigned long address) +{ + struct page *page = alloc_pages(GFP_KERNEL|__GFP_REPEAT, 0); + pte_t *pte; + + if (!page) + return NULL; + + pte = kmap(page); + if (pte) { + clear_page(pte); + __flush_page_to_ram(pte); + flush_tlb_kernel_page(pte); + nocache_page(pte); + } + kunmap(page); + + return page; +} + +extern inline void pte_free(struct mm_struct *mm, struct page *page) +{ + __free_page(page); +} + +/* + * In our implementation, each pgd entry contains 1 pmd that is never allocated + * or freed. pgd_present is always 1, so this should never be called. -NL + */ +#define pmd_free(mm, pmd) BUG() + +extern inline void pgd_free(struct mm_struct *mm, pgd_t *pgd) +{ + free_page((unsigned long) pgd); +} + +extern inline pgd_t *pgd_alloc(struct mm_struct *mm) +{ + pgd_t *new_pgd; + + new_pgd = (pgd_t *)__get_free_page(GFP_KERNEL | __GFP_NOWARN); + if (!new_pgd) + return NULL; + memcpy(new_pgd, swapper_pg_dir, PAGE_SIZE); + memset(new_pgd, 0, PAGE_OFFSET >> PGDIR_SHIFT); + return new_pgd; +} + +#define pgd_populate(mm, pmd, pte) BUG() + +#endif /* M68K_CF_PGALLOC_H */ --- /dev/null +++ b/arch/m68k/include/asm/cf_pgtable.h @@ -0,0 +1,364 @@ +/* + * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#ifndef _CF_PGTABLE_H +#define _CF_PGTABLE_H + +#include +#include + +#ifndef __ASSEMBLY__ +#include +#include + +/* For virtual address to physical address conversion */ +#define VTOP(addr) __pa(addr) +#define PTOV(addr) __va(addr) + + +#endif /* !__ASSEMBLY__ */ + +/* Page protection values within PTE. */ + +/* MMUDR bits, in proper place. */ +#define CF_PAGE_LOCKED (0x00000002) +#define CF_PAGE_EXEC (0x00000004) +#define CF_PAGE_WRITABLE (0x00000008) +#define CF_PAGE_READABLE (0x00000010) +#define CF_PAGE_SYSTEM (0x00000020) +#define CF_PAGE_COPYBACK (0x00000040) +#define CF_PAGE_NOCACHE (0x00000080) + +#define CF_CACHEMASK (~0x00000040) +#define CF_PAGE_MMUDR_MASK (0x000000fe) + +#define _PAGE_NOCACHE030 (CF_PAGE_NOCACHE) + +/* MMUTR bits, need shifting down. */ +#define CF_PAGE_VALID (0x00000400) +#define CF_PAGE_SHARED (0x00000800) + +#define CF_PAGE_MMUTR_MASK (0x00000c00) +#define CF_PAGE_MMUTR_SHIFT (10) +#define CF_ASID_MMU_SHIFT (2) + +/* Fake bits, not implemented in CF, will get masked out before + hitting hardware, and might go away altogether once this port is + complete. */ +#if PAGE_SHIFT < 13 +#error COLDFIRE Error: Pages must be at least 8k in size +#endif +#define CF_PAGE_ACCESSED (0x00001000) +#define CF_PAGE_FILE (0x00000200) +#define CF_PAGE_DIRTY (0x00000001) + +#define _PAGE_CACHE040 0x020 /* 68040 cache mode, cachable, copyback */ +#define _PAGE_NOCACHE_S 0x040 /* 68040 no-cache mode, serialized */ +#define _PAGE_NOCACHE 0x060 /* 68040 cache mode, non-serialized */ +#define _PAGE_CACHE040W 0x000 /* 68040 cache mode, cachable, write-through */ +#define _DESCTYPE_MASK 0x003 +#define _CACHEMASK040 (~0x060) +#define _PAGE_GLOBAL040 0x400 /* 68040 global bit, used for kva descs */ + + +/* Externally used page protection values. */ +#define _PAGE_PRESENT (CF_PAGE_VALID) +#define _PAGE_ACCESSED (CF_PAGE_ACCESSED) +#define _PAGE_DIRTY (CF_PAGE_DIRTY) +#define _PAGE_READWRITE (CF_PAGE_WRITABLE \ + | CF_PAGE_READABLE \ + | CF_PAGE_SHARED \ + | CF_PAGE_SYSTEM) + +/* Compound page protection values. */ +#define PAGE_NONE __pgprot(CF_PAGE_VALID \ + | CF_PAGE_ACCESSED) + +#define PAGE_SHARED __pgprot(CF_PAGE_VALID \ + | CF_PAGE_READABLE \ + | CF_PAGE_WRITABLE \ + | CF_PAGE_ACCESSED) + +#define PAGE_INIT __pgprot(CF_PAGE_VALID \ + | CF_PAGE_WRITABLE \ + | CF_PAGE_READABLE \ + | CF_PAGE_EXEC \ + | CF_PAGE_SYSTEM \ + | CF_PAGE_SHARED) + +#define PAGE_KERNEL __pgprot(CF_PAGE_VALID \ + | CF_PAGE_WRITABLE \ + | CF_PAGE_READABLE \ + | CF_PAGE_EXEC \ + | CF_PAGE_SYSTEM \ + | CF_PAGE_SHARED \ + | CF_PAGE_ACCESSED) + +#define PAGE_COPY __pgprot(CF_PAGE_VALID \ + | CF_PAGE_ACCESSED \ + | CF_PAGE_READABLE) + +/* + * Page protections for initialising protection_map. See mm/mmap.c + * for use. In general, the bit positions are xwr, and P-items are + * private, the S-items are shared. + */ + +#define __P000 PAGE_NONE +#define __P100 __pgprot(CF_PAGE_VALID \ + | CF_PAGE_ACCESSED \ + | CF_PAGE_EXEC) +#define __P010 __pgprot(CF_PAGE_VALID \ + | CF_PAGE_WRITABLE \ + | CF_PAGE_ACCESSED) +#define __P110 __pgprot(CF_PAGE_VALID \ + | CF_PAGE_ACCESSED \ + | CF_PAGE_WRITABLE \ + | CF_PAGE_EXEC) +#define __P001 __pgprot(CF_PAGE_VALID \ + | CF_PAGE_ACCESSED \ + | CF_PAGE_READABLE) +#define __P101 __pgprot(CF_PAGE_VALID \ + | CF_PAGE_ACCESSED \ + | CF_PAGE_READABLE \ + | CF_PAGE_EXEC) +#define __P011 __pgprot(CF_PAGE_VALID \ + | CF_PAGE_READABLE \ + | CF_PAGE_WRITABLE \ + | CF_PAGE_ACCESSED) +#define __P111 __pgprot(CF_PAGE_VALID \ + | CF_PAGE_ACCESSED \ + | CF_PAGE_WRITABLE \ + | CF_PAGE_READABLE \ + | CF_PAGE_EXEC) + +#define __S000 PAGE_NONE +#define __S100 __pgprot(CF_PAGE_VALID \ + | CF_PAGE_ACCESSED \ + | CF_PAGE_EXEC) +#define __S010 PAGE_SHARED +#define __S110 __pgprot(CF_PAGE_VALID \ + | CF_PAGE_ACCESSED \ + | CF_PAGE_WRITABLE \ + | CF_PAGE_EXEC) +#define __S001 __pgprot(CF_PAGE_VALID \ + | CF_PAGE_ACCESSED \ + | CF_PAGE_READABLE) +#define __S101 __pgprot(CF_PAGE_VALID \ + | CF_PAGE_ACCESSED \ + | CF_PAGE_READABLE \ + | CF_PAGE_EXEC) +#define __S011 PAGE_SHARED +#define __S111 __pgprot(CF_PAGE_VALID \ + | CF_PAGE_ACCESSED \ + | CF_PAGE_READABLE \ + | CF_PAGE_WRITABLE \ + | CF_PAGE_EXEC) + +#define PTE_MASK PAGE_MASK +#define CF_PAGE_CHG_MASK (PTE_MASK | CF_PAGE_ACCESSED | CF_PAGE_DIRTY) + +#ifndef __ASSEMBLY__ + +/* + * 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 mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot)) + +extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot) +{ + pte_val(pte) = (pte_val(pte) & CF_PAGE_CHG_MASK) | pgprot_val(newprot); + return pte; +} + +#define pmd_set(pmdp, ptep) do {} while (0) + +static inline void pgd_set(pgd_t *pgdp, pmd_t *pmdp) +{ + pgd_val(*pgdp) = virt_to_phys(pmdp); +} + +#define __pte_page(pte) \ + ((unsigned long) ((pte_val(pte) & CF_PAGE_PGNUM_MASK) + PAGE_OFFSET)) +#define __pmd_page(pmd) ((unsigned long) (pmd_val(pmd))) + +extern inline int pte_none(pte_t pte) +{ + return !pte_val(pte); +} +extern inline int pte_present(pte_t pte) +{ + return pte_val(pte) & CF_PAGE_VALID; +} +extern inline void pte_clear(struct mm_struct *mm, unsigned long addr, + pte_t *ptep) +{ + pte_val(*ptep) = 0; +} + +#define pte_pagenr(pte) ((__pte_page(pte) - PAGE_OFFSET) >> PAGE_SHIFT) +#define pte_page(pte) virt_to_page(__pte_page(pte)) + +extern inline int pmd_none2(pmd_t *pmd) { return !pmd_val(*pmd); } +#define pmd_none(pmd) pmd_none2(&(pmd)) +extern inline int pmd_bad2(pmd_t *pmd) { return 0; } +#define pmd_bad(pmd) pmd_bad2(&(pmd)) +#define pmd_present(pmd) (!pmd_none2(&(pmd))) +extern inline void pmd_clear(pmd_t *pmdp) { pmd_val(*pmdp) = 0; } + +extern inline int pgd_none(pgd_t pgd) { return 0; } +extern inline int pgd_bad(pgd_t pgd) { return 0; } +extern inline int pgd_present(pgd_t pgd) { return 1; } +extern inline void pgd_clear(pgd_t *pgdp) {} + + +#define pte_ERROR(e) \ + printk(KERN_ERR "%s:%d: bad pte %08lx.\n", \ + __FILE__, __LINE__, pte_val(e)) +#define pmd_ERROR(e) \ + printk(KERN_ERR "%s:%d: bad pmd %08lx.\n", \ + __FILE__, __LINE__, pmd_val(e)) +#define pgd_ERROR(e) \ + printk(KERN_ERR "%s:%d: bad pgd %08lx.\n", \ + __FILE__, __LINE__, pgd_val(e)) + + +/* + * The following only work if pte_present() is true. + * Undefined behaviour if not... + * [we have the full set here even if they don't change from m68k] + */ +extern inline int pte_read(pte_t pte) \ + { return pte_val(pte) & CF_PAGE_READABLE; } +extern inline int pte_write(pte_t pte) \ + { return pte_val(pte) & CF_PAGE_WRITABLE; } +extern inline int pte_exec(pte_t pte) \ + { return pte_val(pte) & CF_PAGE_EXEC; } +extern inline int pte_dirty(pte_t pte) \ + { return pte_val(pte) & CF_PAGE_DIRTY; } +extern inline int pte_young(pte_t pte) \ + { return pte_val(pte) & CF_PAGE_ACCESSED; } +extern inline int pte_file(pte_t pte) \ + { return pte_val(pte) & CF_PAGE_FILE; } +static inline int pte_special(pte_t pte) { return 0; } + + +extern inline pte_t pte_wrprotect(pte_t pte) \ + { pte_val(pte) &= ~CF_PAGE_WRITABLE; return pte; } +extern inline pte_t pte_rdprotect(pte_t pte) \ + { pte_val(pte) &= ~CF_PAGE_READABLE; return pte; } +extern inline pte_t pte_exprotect(pte_t pte) \ + { pte_val(pte) &= ~CF_PAGE_EXEC; return pte; } +extern inline pte_t pte_mkclean(pte_t pte) \ + { pte_val(pte) &= ~CF_PAGE_DIRTY; return pte; } +extern inline pte_t pte_mkold(pte_t pte) \ + { pte_val(pte) &= ~CF_PAGE_ACCESSED; return pte; } +extern inline pte_t pte_mkwrite(pte_t pte) \ + { pte_val(pte) |= CF_PAGE_WRITABLE; return pte; } +extern inline pte_t pte_mkread(pte_t pte) \ + { pte_val(pte) |= CF_PAGE_READABLE; return pte; } +extern inline pte_t pte_mkexec(pte_t pte) \ + { pte_val(pte) |= CF_PAGE_EXEC; return pte; } +extern inline pte_t pte_mkdirty(pte_t pte) \ + { pte_val(pte) |= CF_PAGE_DIRTY; return pte; } +extern inline pte_t pte_mkyoung(pte_t pte) \ + { pte_val(pte) |= CF_PAGE_ACCESSED; return pte; } +extern inline pte_t pte_mknocache(pte_t pte) \ + { pte_val(pte) |= 0x80 | (pte_val(pte) & ~0x40); return pte; } +extern inline pte_t pte_mkcache(pte_t pte) \ + { pte_val(pte) &= ~CF_PAGE_NOCACHE; return pte; } +static inline pte_t pte_mkspecial(pte_t pte) { return pte; } + + +#define swapper_pg_dir kernel_pg_dir +extern pgd_t kernel_pg_dir[PTRS_PER_PGD]; + +/* Find an entry in a pagetable directory. */ +#define pgd_index(address) ((address) >> PGDIR_SHIFT) + +#define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address)) + +/* Find an entry in a kernel pagetable directory. */ +#define pgd_offset_k(address) pgd_offset(&init_mm, address) + +/* Find an entry in the second-level pagetable. */ +extern inline pmd_t *pmd_offset(pgd_t *pgd, unsigned long address) +{ + return (pmd_t *) pgd; +} + +/* Find an entry in the third-level pagetable. */ +#define __pte_offset(address) ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) +#define pte_offset_kernel(dir, address) ((pte_t *) __pmd_page(*(dir)) + \ + __pte_offset(address)) + +/* Disable caching for page at given kernel virtual address. */ +static inline void nocache_page(void *vaddr) +{ + pgd_t *dir; + pmd_t *pmdp; + pte_t *ptep; + unsigned long addr = (unsigned long)vaddr; + + dir = pgd_offset_k(addr); + pmdp = pmd_offset(dir, addr); + ptep = pte_offset_kernel(pmdp, addr); + *ptep = pte_mknocache(*ptep); +} + +/* Enable caching for page at given kernel virtual address. */ +static inline void cache_page(void *vaddr) +{ + pgd_t *dir; + pmd_t *pmdp; + pte_t *ptep; + unsigned long addr = (unsigned long)vaddr; + + dir = pgd_offset_k(addr); + pmdp = pmd_offset(dir, addr); + ptep = pte_offset_kernel(pmdp, addr); + *ptep = pte_mkcache(*ptep); +} + +#define PTE_FILE_MAX_BITS 21 +#define PTE_FILE_SHIFT 11 + +static inline unsigned long pte_to_pgoff(pte_t pte) +{ + return pte_val(pte) >> PTE_FILE_SHIFT; +} + +static inline pte_t pgoff_to_pte(unsigned pgoff) +{ + pte_t pte = __pte((pgoff << PTE_FILE_SHIFT) + CF_PAGE_FILE); + return pte; +} + +/* Encode and de-code a swap entry (must be !pte_none(e) && !pte_present(e)) */ +#define __swp_entry(type, offset) ((swp_entry_t) { (type) | \ + (offset << PTE_FILE_SHIFT) }) +#define __swp_type(x) ((x).val & 0xFF) +#define __swp_offset(x) ((x).val >> PTE_FILE_SHIFT) +#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) +#define __swp_entry_to_pte(x) (__pte((x).val)) + +#define pmd_page(pmd) (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT)) + +#define pte_offset_map(pmdp, address) ((pte_t *)__pmd_page(*pmdp) + \ + __pte_offset(address)) +#define pte_offset_map_nested(pmdp, address) pte_offset_map(pmdp, address) +#define pte_unmap(pte) do { } while (0) +#define pte_unmap_nested(pte) kunmap(pte) + +#define pfn_pte(pfn, prot) __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot)) +#define pte_pfn(pte) (pte_val(pte) >> PAGE_SHIFT) + + +#endif /* !__ASSEMBLY__ */ +#endif /* !_CF_PGTABLE_H */ --- /dev/null +++ b/arch/m68k/include/asm/cf_raw_io.h @@ -0,0 +1,188 @@ +/* + * linux/include/asm-m68k/cf_raw_io.h + * + * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * 09/30/08 JKM: split Coldfire pieces into separate file + * + * This file is subject to 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 __CF_RAW_IO__ +#define __CF_RAW_IO__ + +#ifdef __KERNEL__ + +#include + +/* Values for nocacheflag and cmode */ +#define IOMAP_FULL_CACHING 0 +#define IOMAP_NOCACHE_SER 1 +#define IOMAP_NOCACHE_NONSER 2 +#define IOMAP_WRITETHROUGH 3 + +extern void iounmap(void __iomem *addr); + +extern void __iomem *__ioremap(unsigned long physaddr, unsigned long size, + int cacheflag); +extern void __iounmap(void *addr, unsigned long size); + + +/* ++roman: The assignments to temp. vars avoid that gcc sometimes generates + * two accesses to memory, which may be undesirable for some devices. + */ +#define in_8(addr) \ + ({ u8 __v = (*(__force volatile u8 *) (addr)); __v; }) +#define in_be16(addr) \ + ({ u16 __v = (*(__force volatile u16 *) (addr)); __v; }) +#define in_be32(addr) \ + ({ u32 __v = (*(__force volatile u32 *) (addr)); __v; }) +#define in_le16(addr) \ + ({ u16 __v = le16_to_cpu(*(__force volatile __le16 *) (addr)); __v; }) +#define in_le32(addr) \ + ({ u32 __v = le32_to_cpu(*(__force volatile __le32 *) (addr)); __v; }) + +#define out_8(addr, b) (void)((*(__force volatile u8 *) (addr)) = (b)) +#define out_be16(addr, w) (void)((*(__force volatile u16 *) (addr)) = (w)) +#define out_be32(addr, l) (void)((*(__force volatile u32 *) (addr)) = (l)) +#define out_le16(addr, w) \ + (void)((*(__force volatile __le16 *) (addr)) = cpu_to_le16(w)) +#define out_le32(addr, l) \ + (void)((*(__force volatile __le32 *) (addr)) = cpu_to_le32(l)) + + +#ifdef CONFIG_PCI +/* pci */ +unsigned char pci_inb(long addr); +unsigned short pci_inw(long addr); +unsigned long pci_inl(long addr); + +void pci_outb(unsigned char val, long addr); +void pci_outw(unsigned short val, long addr); +void pci_outl(unsigned long val, long addr); + +void pci_insb(volatile unsigned char *addr, + unsigned char *buf, int len); +void pci_insw(volatile unsigned short *addr, + unsigned short *buf, int len); +void pci_insl(volatile unsigned long *addr, + unsigned long *buf, int len); + +void pci_outsb(volatile unsigned char *addr, + const unsigned char *buf, int len); +void pci_outsw(volatile unsigned short *addr, + const unsigned short *buf, int len); +void pci_outsl(volatile unsigned long *addr, + const unsigned long *buf, int len); + +unsigned short pci_raw_inw(long addr); +unsigned long pci_raw_inl(long addr); +void pci_raw_outw(unsigned short val, long addr); +void pci_raw_outl(unsigned long val, long addr); + +#define raw_inb(port) pci_inb((long)((volatile unsigned char *)(port))) +#define raw_inw(port) pci_raw_inw((long)((volatile unsigned short *)(port))) +#define raw_inl(port) pci_raw_inl((long)((volatile unsigned long *)(port))) + +#define raw_outb(val, port) \ + pci_outb((val), (long)((volatile unsigned char *)(port))) +#define raw_outw(val, port) \ + pci_raw_outw((val), (long)((volatile unsigned short *)(port))) +#define raw_outl(val, port) \ + pci_raw_outl((val), (long)((volatile unsigned long *)(port))) + +#define swap_inw(port) pci_inw((long)((volatile unsigned short *)(port))) +#define swap_outw(val, port) \ + pci_outw((val), (long)((volatile unsigned short *)(port))) + +#else +/* non-pci */ +#define raw_inb in_8 +#define raw_inw in_be16 +#define raw_inl in_be32 + +#define raw_outb(val, port) out_8((port), (val)) +#define raw_outw(val, port) out_be16((port), (val)) +#define raw_outl(val, port) out_be32((port), (val)) + +#define swap_inw(port) in_le16((port)) +#define swap_outw(val, port) out_le16((port), (val)) +#endif + +static inline void raw_insb(volatile u8 __iomem *port, + u8 *buf, unsigned int len) +{ + unsigned int i; + + for (i = 0; i < len; i++) + *buf++ = in_8(port); +} + +static inline void raw_outsb(volatile u8 __iomem *port, const u8 *buf, + unsigned int len) +{ + unsigned int i; + + for (i = 0; i < len; i++) + out_8(port, *buf++); +} + +static inline void raw_insw(volatile u16 *port, u16 *buf, unsigned int nr) +{ + unsigned int i; + + for (i = 0; i < nr; i++) + *buf++ = raw_inw(port); +} + +static inline void raw_outsw(volatile u16 *port, const u16 *buf, + unsigned int nr) +{ + unsigned int i; + + for (i = 0; i < nr; i++, buf++) + raw_outw(*buf, port); +} + +static inline void raw_insl(volatile u32 *port, u32 *buf, unsigned int nr) +{ + unsigned int i; + + for (i = 0; i < nr; i++) + *buf++ = raw_inl(port); +} + +static inline void raw_outsl(volatile u32 *port, const u32 *buf, + unsigned int nr) +{ + unsigned int i; + + for (i = 0; i < nr; i++, buf++) + raw_outl(*buf, port); +} + +static inline void raw_insw_swapw(volatile u16 *port, u16 *buf, + unsigned int nr) +{ +#ifdef UNDEF + unsigned int i; + + for (i = 0; i < nr; i++) + *buf++ = in_le16(port); +#endif +} + +static inline void raw_outsw_swapw(volatile u16 __iomem *port, const u16 *buf, + unsigned int nr) +{ +#ifdef UNDEF + unsigned int i; + + for (i = 0; i < nr; i++, buf++) + out_le16(port, *buf); +#endif +} + +#endif /* __KERNEL__ */ + +#endif /* __CF_RAW_IO__ */ --- /dev/null +++ b/arch/m68k/include/asm/cf_tlbflush.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ +#ifndef M68K_CF_TLBFLUSH_H +#define M68K_CF_TLBFLUSH_H + +#include + +/* Flush all userspace mappings. */ +static inline void flush_tlb_all(void) +{ + preempt_disable(); + *MMUOR = MMUOR_CNL; + preempt_enable(); +} + +/* Clear user TLB entries within the context named in mm */ +static inline void flush_tlb_mm(struct mm_struct *mm) +{ + preempt_disable(); + *MMUOR = MMUOR_CNL; + preempt_enable(); +} + +/* Flush a single TLB page. */ +static inline void flush_tlb_page(struct vm_area_struct *vma, + unsigned long addr) +{ + preempt_disable(); + *MMUOR = MMUOR_CNL; + preempt_enable(); +} +/* Flush a range of pages from TLB. */ + +static inline void flush_tlb_range(struct vm_area_struct *mm, + unsigned long start, unsigned long end) +{ + preempt_disable(); + *MMUOR = MMUOR_CNL; + preempt_enable(); +} + +/* Flush kernel page from TLB. */ +static inline void flush_tlb_kernel_page(void *addr) +{ + preempt_disable(); + *MMUOR = MMUOR_CNL; + preempt_enable(); +} + +static inline void flush_tlb_kernel_range(unsigned long start, + unsigned long end) +{ + flush_tlb_all(); +} + +extern inline void flush_tlb_pgtables(struct mm_struct *mm, + unsigned long start, unsigned long end) +{ +} + +#endif /* M68K_CF_TLBFLUSH_H */ --- /dev/null +++ b/arch/m68k/include/asm/cf_uaccess.h @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ +#ifndef __M68K_CF_UACCESS_H +#define __M68K_CF_UACCESS_H + +/* + * User space memory access functions + */ + +/* The "moves" command is not available in the CF instruction set. */ +#include +#include +#include +#include +#include + +#define VERIFY_READ 0 +#define VERIFY_WRITE 1 + +/* We let the MMU do all checking */ +#define access_ok(type, addr, size) 1 + +/* + * The exception table consists of pairs of addresses: the first is the + * address of an instruction that is allowed to fault, and the second is + * the address at which the program should continue. No registers are + * modified, so it is entirely up to the continuation code to figure out + * what to do. + * + * All the routines below use bits of fixup code that are out of line + * with the main instruction path. This means when everything is well, + * we don't even have to jump over them. Further, they do not intrude + * on our cache or tlb entries. + */ + +struct exception_table_entry { + unsigned long insn, fixup; +}; + +extern int __put_user_bad(void); +extern int __get_user_bad(void); + +#define __put_user_asm(res, x, ptr, bwl, reg, err) \ +asm volatile ("\n" \ + "1: move."#bwl" %2,%1\n" \ + "2:\n" \ + " .section .fixup,\"ax\"\n" \ + " .even\n" \ + "10: moveq.l %3,%0\n" \ + " jra 2b\n" \ + " .previous\n" \ + "\n" \ + " .section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 1b,10b\n" \ + " .long 2b,10b\n" \ + " .previous" \ + : "+d" (res), "=m" (*(ptr)) \ + : #reg(x), "i" (err)) + +/* + * These are the main single-value transfer routines. They automatically + * use the right size if we just have the right pointer type. + */ + +#define __put_user(x, ptr) \ +({ \ + typeof(*(ptr)) __pu_val = (x); \ + int __pu_err = 0; \ + __chk_user_ptr(ptr); \ + switch (sizeof(*(ptr))) { \ + case 1: \ + __put_user_asm(__pu_err, __pu_val, ptr, b, d, -EFAULT); \ + break; \ + case 2: \ + __put_user_asm(__pu_err, __pu_val, ptr, w, d, -EFAULT); \ + break; \ + case 4: \ + __put_user_asm(__pu_err, __pu_val, ptr, l, r, -EFAULT); \ + break; \ + case 8: \ + { \ + const void __user *__pu_ptr = (ptr); \ + asm volatile ("\n" \ + "1: move.l %2,(%1)+\n" \ + "2: move.l %R2,(%1)\n" \ + "3:\n" \ + " .section .fixup,\"ax\"\n" \ + " .even\n" \ + "10: movel %3,%0\n" \ + " jra 3b\n" \ + " .previous\n" \ + "\n" \ + " .section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 1b,10b\n" \ + " .long 2b,10b\n" \ + " .long 3b,10b\n" \ + " .previous" \ + : "+d" (__pu_err), "+a" (__pu_ptr) \ + : "r" (__pu_val), "i" (-EFAULT) \ + : "memory"); \ + break; \ + } \ + default: \ + __pu_err = __put_user_bad(); \ + break; \ + } \ + __pu_err; \ +}) +#define put_user(x, ptr) __put_user(x, ptr) + + +#define __get_user_asm(res, x, ptr, type, bwl, reg, err) ({ \ + type __gu_val; \ + asm volatile ("\n" \ + "1: move."#bwl" %2,%1\n" \ + "2:\n" \ + " .section .fixup,\"ax\"\n" \ + " .even\n" \ + "10: move.l %3,%0\n" \ + " subl %1,%1\n" \ + " jra 2b\n" \ + " .previous\n" \ + "\n" \ + " .section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 1b,10b\n" \ + " .previous" \ + : "+d" (res), "=&" #reg(__gu_val) \ + : "m" (*(ptr)), "i" (err)); \ + (x) = (typeof(*(ptr)))(unsigned long)__gu_val; \ +}) + +#define __get_user(x, ptr) \ +({ \ + int __gu_err = 0; \ + __chk_user_ptr(ptr); \ + switch (sizeof(*(ptr))) { \ + case 1: \ + __get_user_asm(__gu_err, x, ptr, u8, b, d, -EFAULT); \ + break; \ + case 2: \ + __get_user_asm(__gu_err, x, ptr, u16, w, d, -EFAULT); \ + break; \ + case 4: \ + __get_user_asm(__gu_err, x, ptr, u32, l, r, -EFAULT); \ + break; \ +/* case 8: disabled because gcc-4.1 has a broken typeof \ + { \ + const void *__gu_ptr = (ptr); \ + u64 __gu_val; \ + asm volatile ("\n" \ + "1: move.l (%2)+,%1\n" \ + "2: move.l (%2),%R1\n" \ + "3:\n" \ + " .section .fixup,\"ax\"\n" \ + " .even\n" \ + "10: move.l %3,%0\n" \ + " subl %1,%1\n" \ + " subl %R1,%R1\n" \ + " jra 3b\n" \ + " .previous\n" \ + "\n" \ + " .section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 1b,10b\n" \ + " .long 2b,10b\n" \ + " .previous" \ + : "+d" (__gu_err), "=&r" (__gu_val), \ + "+a" (__gu_ptr) \ + : "i" (-EFAULT) \ + : "memory"); \ + (x) = (typeof(*(ptr)))__gu_val; \ + break; \ + } */ \ + default : \ + __gu_err = __get_user_bad(); \ + break; \ + } \ + __gu_err; \ +}) +#define get_user(x, ptr) __get_user(x, ptr) + +unsigned long __generic_copy_from_user(void *to, const void __user *from, + unsigned long n); +unsigned long __generic_copy_to_user(void __user *to, const void *from, + unsigned long n); + +#define __constant_copy_from_user_asm(res, to, from, tmp, n, s1, s2, s3)\ + asm volatile ("\n" \ + "1: move."#s1" (%2)+,%3\n" \ + " move."#s1" %3,(%1)+\n" \ + "2: move."#s2" (%2)+,%3\n" \ + " move."#s2" %3,(%1)+\n" \ + " .ifnc \""#s3"\",\"\"\n" \ + "3: move."#s3" (%2)+,%3\n" \ + " move."#s3" %3,(%1)+\n" \ + " .endif\n" \ + "4:\n" \ + " .section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 1b,10f\n" \ + " .long 2b,20f\n" \ + " .ifnc \""#s3"\",\"\"\n" \ + " .long 3b,30f\n" \ + " .endif\n" \ + " .previous\n" \ + "\n" \ + " .section .fixup,\"ax\"\n" \ + " .even\n" \ + "10: clr."#s1" (%1)+\n" \ + "20: clr."#s2" (%1)+\n" \ + " .ifnc \""#s3"\",\"\"\n" \ + "30: clr."#s3" (%1)+\n" \ + " .endif\n" \ + " moveq.l #"#n",%0\n" \ + " jra 4b\n" \ + " .previous\n" \ + : "+d" (res), "+&a" (to), "+a" (from), "=&d" (tmp) \ + : : "memory") + +#define __constant_copy_to_user_asm(res, to, from, tmp, n, s1, s2, s3) \ + asm volatile ("\n" \ + " move."#s1" (%2)+,%3\n" \ + "11: move."#s1" %3,(%1)+\n" \ + "12: move."#s2" (%2)+,%3\n" \ + "21: move."#s2" %3,(%1)+\n" \ + "22:\n" \ + " .ifnc \""#s3"\",\"\"\n" \ + " move."#s3" (%2)+,%3\n" \ + "31: move."#s3" %3,(%1)+\n" \ + "32:\n" \ + " .endif\n" \ + "4:\n" \ + "\n" \ + " .section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 11b,5f\n" \ + " .long 12b,5f\n" \ + " .long 21b,5f\n" \ + " .long 22b,5f\n" \ + " .ifnc \""#s3"\",\"\"\n" \ + " .long 31b,5f\n" \ + " .long 32b,5f\n" \ + " .endif\n" \ + " .previous\n" \ + "\n" \ + " .section .fixup,\"ax\"\n" \ + " .even\n" \ + "5: moveq.l #"#n",%0\n" \ + " jra 4b\n" \ + " .previous\n" \ + : "+d" (res), "+a" (to), "+a" (from), "=&d" (tmp) \ + : : "memory") + +#endif /* _M68K_CF_UACCESS_H */ --- /dev/null +++ b/arch/m68k/include/asm/cf_virtconvert.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ +#ifndef __CF_VIRTCONVERT__ +#define __CF_VIRTCONVERT__ + +/* + * Macros used for converting between virtual and physical mappings. + * + * Coldfire Specific + */ + +#ifdef __KERNEL__ + +#include +#include +#include +#include + +/* + * Change virtual addresses to physical addresses and vv. + */ +static inline unsigned long virt_to_phys(void *address) +{ + return __pa(address); +} + +static inline void *phys_to_virt(unsigned long address) +{ + return __va(address); +} + +/* Permanent address of a page. */ +#ifdef CONFIG_SINGLE_MEMORY_CHUNK +#define page_to_phys(page) \ + __pa(PAGE_OFFSET + \ + (((page) - pg_data_map[0].node_mem_map) << PAGE_SHIFT)) +#else +#define page_to_phys(_page) ({ \ + struct page *__page = _page; \ + struct pglist_data *pgdat; \ + pgdat = pg_data_table[page_to_nid(__page)]; \ + page_to_pfn(__page) << PAGE_SHIFT; \ +}) +#endif + +/* + * IO bus memory addresses are 1:1 with the physical address, + */ +#ifdef CONFIG_PCI +#define virt_to_bus(a) (a + PCI_DMA_BASE) +#define bus_to_virt(a) (a - PCI_DMA_BASE) +#else +#define virt_to_bus(a) (a) +#define bus_to_virt(a) (a) +#endif + +#endif /* __KERNEL__ */ +#endif /* __CF_VIRTCONVERT__ */ --- /dev/null +++ b/arch/m68k/include/asm/cfcache.h @@ -0,0 +1,146 @@ +/* + * include/asm-m68k/cfcache.h - Coldfire Cache Controller + * + * Kurt Mahan kmahan@freescale.com + * + * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * 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 CF_CFCACHE_H +#define CF_CFCACHE_H + +/* + * CACR Cache Control Register + */ +#define CF_CACR_DEC (0x80000000) /* Data Cache Enable */ +#define CF_CACR_DW (0x40000000) /* Data default Write-protect */ +#define CF_CACR_DESB (0x20000000) /* Data Enable Store Buffer */ +#define CF_CACR_DPI (0x10000000) /* Data Disable CPUSHL Invalidate */ +#define CF_CACR_DHLCK (0x08000000) /* 1/2 Data Cache Lock Mode */ +#define CF_CACR_DDCM_00 (0x00000000) /* Cacheable writethrough imprecise */ +#define CF_CACR_DDCM_01 (0x02000000) /* Cacheable copyback */ +#define CF_CACR_DDCM_10 (0x04000000) /* Noncacheable precise */ +#define CF_CACR_DDCM_11 (0x06000000) /* Noncacheable imprecise */ +#define CF_CACR_DCINVA (0x01000000) /* Data Cache Invalidate All */ +#define CF_CACR_DDSP (0x00800000) /* Data default supervisor-protect */ +#define CF_CACR_IVO (0x00100000) /* Invalidate only */ +#define CF_CACR_BEC (0x00080000) /* Branch Cache Enable */ +#define CF_CACR_BCINVA (0x00040000) /* Branch Cache Invalidate All */ +#define CF_CACR_IEC (0x00008000) /* Instruction Cache Enable */ +#define CF_CACR_SPA (0x00004000) /* Search by Physical Address */ +#define CF_CACR_DNFB (0x00002000) /* Default cache-inhibited fill buf */ +#define CF_CACR_IDPI (0x00001000) /* Instr Disable CPUSHL Invalidate */ +#define CF_CACR_IHLCK (0x00000800) /* 1/2 Instruction Cache Lock Mode */ +#define CF_CACR_IDCM (0x00000400) /* Noncacheable Instr default mode */ +#define CF_CACR_ICINVA (0x00000100) /* Instr Cache Invalidate All */ +#define CF_CACR_IDSP (0x00000080) /* Ins default supervisor-protect */ +#define CF_CACR_EUSP (0x00000020) /* Switch stacks in user mode */ + +#ifdef CONFIG_M5445X +/* + * M5445x Cache Configuration + * - cache line size is 16 bytes + * - cache is 4-way set associative + * - each cache has 256 sets (64k / 16bytes / 4way) + * - I-Cache size is 16KB + * - D-Cache size is 16KB + */ +#define ICACHE_SIZE 0x4000 /* instruction - 16k */ +#define DCACHE_SIZE 0x4000 /* data - 16k */ + +#define CACHE_LINE_SIZE 0x0010 /* 16 bytes */ +#define CACHE_SETS 0x0100 /* 256 sets */ +#define CACHE_WAYS 0x0004 /* 4 way */ + +#define CACHE_DISABLE_MODE (CF_CACR_DCINVA+ \ + CF_CACR_BCINVA+ \ + CF_CACR_ICINVA) + +#ifndef CONFIG_M5445X_DISABLE_CACHE +#define CACHE_INITIAL_MODE (CF_CACR_DEC+ \ + CF_CACR_BEC+ \ + CF_CACR_IEC+ \ + CF_CACR_DESB+ \ + CF_CACR_EUSP) +#else +/* cache disabled for testing */ +#define CACHE_INITIAL_MODE (CF_CACR_EUSP) +#endif /* CONFIG_M5445X_DISABLE_CACHE */ + +#elif defined(CONFIG_M547X_8X) +/* + * * M547x/M548x Cache Configuration + * * - cache line size is 16 bytes + * * - cache is 4-way set associative + * * - each cache has 512 sets (128k / 16bytes / 4way) + * * - I-Cache size is 32KB + * * - D-Cache size is 32KB + * */ +#define ICACHE_SIZE 0x8000 /* instruction - 32k */ +#define DCACHE_SIZE 0x8000 /* data - 32k */ + +#define CACHE_LINE_SIZE 0x0010 /* 16 bytes */ +#define CACHE_SETS 0x0200 /* 512 sets */ +#define CACHE_WAYS 0x0004 /* 4 way */ + +/* in for the old cpushl caching code */ +#define _DCACHE_SET_MASK ((DCACHE_SIZE/64-1)< + +#ifndef __CF_MMU_H__ +#define __CF_MMU_H__ + + +#if defined(CONFIG_M5445X) || defined(CONFIG_M547X_8X) +#define MMU_BASE 0xE8000000 +#elif defined(CONFIG_M5441X) +#define MMU_BASE 0xD8000000 +#endif + +#define MMUCR (MMU_BASE+0x00) +#define MMUCR_ASMN 1 +#define MMUCR_ASM (1< - /* * Copyright (C) 1994 Hamish Macdonald * + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + * * Delay routines, using a pre-computed "loops_per_jiffy" value. */ +#ifndef _M68K_DELAY_H +#define _M68K_DELAY_H + +#include + static inline void __delay(unsigned long loops) { +#if defined(CONFIG_COLDFIRE) + /* The coldfire runs this loop at significantly different speeds + * depending upon long word alignment or not. We'll pad it to + * long word alignment which is the faster version. + * The 0x4a8e is of course a 'tstl %fp' instruction. This is better + * than using a NOP (0x4e71) instruction because it executes in one + * cycle not three and doesn't allow for an arbitary delay waiting + * for bus cycles to finish. Also fp/a6 isn't likely to cause a + * stall waiting for the register to become valid if such is added + * to the coldfire at some stage. + */ + __asm__ __volatile__ (".balignw 4, 0x4a8e\n\t" + "1: subql #1, %0\n\t" + "jcc 1b" + : "=d" (loops) : "0" (loops)); +#else __asm__ __volatile__ ("1: subql #1,%0; jcc 1b" : "=d" (loops) : "0" (loops)); +#endif } extern void __bad_udelay(void); @@ -26,12 +49,17 @@ extern void __bad_udelay(void); */ static inline void __const_udelay(unsigned long xloops) { +#if defined(CONFIG_COLDFIRE) + + __delay(((((unsigned long long) xloops * loops_per_jiffy))>>32)*HZ); +#else unsigned long tmp; __asm__ ("mulul %2,%0:%1" : "=d" (xloops), "=d" (tmp) : "d" (xloops), "1" (loops_per_jiffy)); __delay(xloops * HZ); +#endif } static inline void __udelay(unsigned long usecs) @@ -46,12 +74,16 @@ static inline void __udelay(unsigned lon static inline unsigned long muldiv(unsigned long a, unsigned long b, unsigned long c) { +#if defined(CONFIG_COLDFIRE) + return (long)(((unsigned long long)a * b)/c); +#else unsigned long tmp; __asm__ ("mulul %2,%0:%1; divul %3,%0:%1" : "=d" (tmp), "=d" (a) : "d" (b), "d" (c), "1" (a)); return a; +#endif } #endif /* defined(_M68K_DELAY_H) */ --- a/arch/m68k/include/asm/div64.h +++ b/arch/m68k/include/asm/div64.h @@ -1,12 +1,17 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ #ifndef _M68K_DIV64_H #define _M68K_DIV64_H -#ifdef CONFIG_MMU - +#if defined(CONFIG_MMU) && !defined(CONFIG_COLDFIRE) #include /* n = n / base; return rem; */ - #define do_div(n, base) ({ \ union { \ unsigned long n32[2]; \ --- a/arch/m68k/include/asm/dma.h +++ b/arch/m68k/include/asm/dma.h @@ -1,7 +1,10 @@ -#ifndef _M68K_DMA_H -#define _M68K_DMA_H 1 - -#ifdef CONFIG_COLDFIRE +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ /* * ColdFire DMA Model: * ColdFire DMA supports two forms of DMA: Single and Dual address. Single @@ -25,6 +28,11 @@ * Arthur Shipkowski (art@videon-central.com) */ +#ifndef _M68K_DMA_H +#define _M68K_DMA_H 1 + +#ifdef CONFIG_COLDFIRE + #include #include #include @@ -479,13 +487,106 @@ static __inline__ int get_dma_residue(un /* it's useless on the m68k, but unfortunately needed by the new bootmem allocator (but this should do it for this) */ +#if defined(CONFIG_M5445X) || defined(CONFIG_M547X_8X) +#define MAX_DMA_ADDRESS 0xefffffff +#elif defined(CONFIG_M5441X) +#define MAX_DMA_ADDRESS 0xdfffffff +#else #define MAX_DMA_ADDRESS PAGE_OFFSET +#endif +#ifndef CONFIG_COLDFIRE #define MAX_DMA_CHANNELS 8 extern int request_dma(unsigned int dmanr, const char * device_id); /* reserve a DMA channel */ extern void free_dma(unsigned int dmanr); /* release it again */ +#else /* not (defined(CONFIG_MCF5474) || defined(CONFIG_MCF5484) + || defined(CONFIG_MCF5475) || defined(CONFIG_MCF5485)) */ +/************************************************ + * Multichannel DMA definitions * + ************************************************/ +#ifdef CONFIG_MCD_DMA +#include +#include + +struct scatterlist; + +#define MAX_DMA_CHANNELS NCHANNELS +/* + * identifiers for each initiator/requestor + */ +#define DMA_ALWAYS (0) +#define DMA_DSPI_RX (1) +#define DMA_DSPI_TX (2) +#define DMA_DREQ0 (3) +#define DMA_PSC0_RX (4) +#define DMA_PSC0_TX (5) +#define DMA_USBEP0 (6) +#define DMA_USBEP1 (7) +#define DMA_USBEP2 (8) +#define DMA_USBEP3 (9) +#define DMA_PCI_TX (10) +#define DMA_PCI_RX (11) +#define DMA_PSC1_RX (12) +#define DMA_PSC1_TX (13) +#define DMA_I2C_RX (14) +#define DMA_I2C_TX (15) +#define DMA_FEC0_RX (16) +#define DMA_FEC0_TX (17) +#define DMA_FEC1_RX (18) +#define DMA_FEC1_TX (19) +#define DMA_DREQ1 (20) +#define DMA_CTM0 (21) +#define DMA_CTM1 (22) +#define DMA_CTM2 (23) +#define DMA_CTM3 (24) +#define DMA_CTM4 (25) +#define DMA_CTM5 (26) +#define DMA_CTM6 (27) +#define DMA_CTM7 (28) +#define DMA_USBEP4 (29) +#define DMA_USBEP5 (30) +#define DMA_USBEP6 (31) +#define DMA_PSC2_RX (32) +#define DMA_PSC2_TX (33) +#define DMA_PSC3_RX (34) +#define DMA_PSC3_TX (35) +#define DMA_FEC_RX(x) ((x == 0) ? DMA_FEC0_RX : DMA_FEC1_RX) +#define DMA_FEC_TX(x) ((x == 0) ? DMA_FEC0_TX : DMA_FEC1_TX) + +int dma_set_initiator(int); +unsigned int dma_get_initiator(int); +void dma_remove_initiator(int); +int dma_set_channel(int); +int dma_get_channel(int); +void dma_remove_channel(int); +int dma_set_channel_fec(int requestor); +int dma_connect(int channel, int address); +int dma_disconnect(int channel); +void dma_remove_channel_by_number(int channel); +int dma_init(void); +#endif + +extern spinlock_t dma_spin_lock; + +static inline unsigned long claim_dma_lock(void) +{ + unsigned long flags; + spin_lock_irqsave(&dma_spin_lock, flags); + return flags; +} + +static inline void release_dma_lock(unsigned long flags) +{ + spin_unlock_irqrestore(&dma_spin_lock, flags); +} +#endif + +#ifdef CONFIG_PCI +extern int isa_dma_bridge_buggy; +#else #define isa_dma_bridge_buggy (0) +#endif #endif /* _M68K_DMA_H */ --- a/arch/m68k/include/asm/elf.h +++ b/arch/m68k/include/asm/elf.h @@ -1,10 +1,17 @@ -#ifndef __ASMm68k_ELF_H -#define __ASMm68k_ELF_H - +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ /* * ELF register definitions.. */ +#ifndef __ASMm68k_ELF_H +#define __ASMm68k_ELF_H + #include #include @@ -34,6 +41,26 @@ #define R_68K_GLOB_DAT 20 #define R_68K_JMP_SLOT 21 #define R_68K_RELATIVE 22 +/* TLS static relocations */ +#define R_68K_TLS_GD32 25 +#define R_68K_TLS_GD16 26 +#define R_68K_TLS_GD8 27 +#define R_68K_TLS_LDM32 28 +#define R_68K_TLS_LDM16 29 +#define R_68K_TLS_LDM8 30 +#define R_68K_TLS_LDO32 31 +#define R_68K_TLS_LDO16 32 +#define R_68K_TLS_LDO8 33 +#define R_68K_TLS_IE32 34 +#define R_68K_TLS_IE16 35 +#define R_68K_TLS_IE8 36 +#define R_68K_TLS_LE32 37 +#define R_68K_TLS_LE16 38 +#define R_68K_TLS_LE8 39 +/* TLS dynamic relocations */ +#define R_68K_TLS_DTPMOD32 40 +#define R_68K_TLS_DTPREL32 41 +#define R_68K_TLS_TPREL32 42 typedef unsigned long elf_greg_t; @@ -59,7 +86,7 @@ typedef struct user_m68kfp_struct elf_fp is actually used on ASV. */ #define ELF_PLAT_INIT(_r, load_addr) _r->a1 = 0 -#ifndef CONFIG_SUN3 +#if !defined(CONFIG_SUN3) && !defined(CONFIG_COLDFIRE) #define ELF_EXEC_PAGESIZE 4096 #else #define ELF_EXEC_PAGESIZE 8192 @@ -70,8 +97,10 @@ typedef struct user_m68kfp_struct elf_fp 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. */ -#ifndef CONFIG_SUN3 +#if !defined(CONFIG_SUN3) && !defined(CONFIG_COLDFIRE) #define ELF_ET_DYN_BASE 0xD0000000UL +#elif defined(CONFIG_COLDFIRE) +#define ELF_ET_DYN_BASE (TASK_UNMAPPED_BASE + 0x10000000) #else #define ELF_ET_DYN_BASE 0x0D800000UL #endif @@ -115,4 +144,35 @@ typedef struct user_m68kfp_struct elf_fp #define SET_PERSONALITY(ex) set_personality(PER_LINUX) +/* + * VDSO + */ +#ifdef CONFIG_VDSO +extern unsigned int vdso_enabled; + +#define VDSO_BASE ((unsigned long)current->mm->context.vdso) +#define VDSO_SYM(x) (VDSO_BASE + (unsigned long)(x)) + +#define VDSO_AUX_ENT \ + if (vdso_enabled) \ + NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_BASE); + +/* additional pages */ +#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1 + +struct linux_binprm; +extern int arch_setup_additional_pages(struct linux_binprm *bprm, + int executable_stack); + +#else +/* no VDSO_AUX_ENT */ +#define VDSO_AUX_ENT +#endif + +#define ARCH_DLINFO \ +do { \ + /* vdso entry */ \ + VDSO_AUX_ENT; \ +} while (0); + #endif --- a/arch/m68k/include/asm/io_mm.h +++ b/arch/m68k/include/asm/io_mm.h @@ -1,23 +1,36 @@ /* * linux/include/asm-m68k/io.h * + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + * * 4/1/00 RZ: - rewritten to avoid clashes between ISA/PCI and other * IO access * - added Q40 support * - added skeleton for GG-II and Amiga PCMCIA * 2/3/01 RZ: - moved a few more defs into raw_io.h * - * inX/outX should not be used by any driver unless it does - * ISA access. Other drivers should use function defined in raw_io.h + * inX/outX/readX/writeX should not be used by any driver unless it does + * ISA or PCI access. Other drivers should use function defined in raw_io.h * or define its own macros on top of these. * - * inX(),outX() are for ISA I/O + * inX(),outX() are for PCI and ISA I/O + * readX(),writeX() are for PCI memory * isa_readX(),isa_writeX() are for ISA memory + * + * moved mem{cpy,set}_*io inside CONFIG_PCI */ #ifndef _IO_H #define _IO_H +#ifdef CONFIG_COLDFIRE +#include +#else + #ifdef __KERNEL__ #include @@ -49,6 +62,27 @@ #define MULTI_ISA 0 #endif /* Q40 */ +/* GG-II Zorro to ISA bridge */ +#ifdef CONFIG_GG2 + +extern unsigned long gg2_isa_base; +#define GG2_ISA_IO_B(ioaddr) \ + (gg2_isa_base + 1 + ((unsigned long)(ioaddr) * 4)) +#define GG2_ISA_IO_W(ioaddr) \ + (gg2_isa_base + ((unsigned long)(ioaddr) * 4)) +#define GG2_ISA_MEM_B(madr) \ + (gg2_isa_base + 1 + (((unsigned long)(madr) * 4) & 0xfffff)) +#define GG2_ISA_MEM_W(madr) \ + (gg2_isa_base + (((unsigned long)(madr) * 4) & 0xfffff)) + +#ifndef MULTI_ISA +#define MULTI_ISA 0 +#else +#undef MULTI_ISA +#define MULTI_ISA 1 +#endif +#endif /* GG2 */ + #ifdef CONFIG_AMIGA_PCMCIA #include @@ -71,17 +105,22 @@ #undef MULTI_ISA #endif -#define ISA_TYPE_Q40 (1) -#define ISA_TYPE_AG (2) +#define Q40_ISA (1) +#define GG2_ISA (2) +#define AG_ISA (3) #if defined(CONFIG_Q40) && !defined(MULTI_ISA) -#define ISA_TYPE ISA_TYPE_Q40 +#define ISA_TYPE Q40_ISA #define ISA_SEX 0 #endif #if defined(CONFIG_AMIGA_PCMCIA) && !defined(MULTI_ISA) -#define ISA_TYPE ISA_TYPE_AG +#define ISA_TYPE AG_ISA #define ISA_SEX 1 #endif +#if defined(CONFIG_GG2) && !defined(MULTI_ISA) +#define ISA_TYPE GG2_ISA +#define ISA_SEX 0 +#endif #ifdef MULTI_ISA extern int isa_type; @@ -98,65 +137,72 @@ extern int isa_sex; static inline u8 __iomem *isa_itb(unsigned long addr) { - switch(ISA_TYPE) - { + switch (ISA_TYPE) { #ifdef CONFIG_Q40 - case ISA_TYPE_Q40: return (u8 __iomem *)Q40_ISA_IO_B(addr); + case Q40_ISA: return (u8 __iomem *)Q40_ISA_IO_B(addr); +#endif +#ifdef CONFIG_GG2 + case GG2_ISA: return (u8 __iomem *)GG2_ISA_IO_B(addr); #endif #ifdef CONFIG_AMIGA_PCMCIA - case ISA_TYPE_AG: return (u8 __iomem *)AG_ISA_IO_B(addr); + case AG_ISA: return (u8 __iomem *)AG_ISA_IO_B(addr); #endif - default: return NULL; /* avoid warnings, just in case */ - } + default: return NULL; /* avoid warnings, just in case */ + } } static inline u16 __iomem *isa_itw(unsigned long addr) { - switch(ISA_TYPE) - { + switch (ISA_TYPE) { #ifdef CONFIG_Q40 - case ISA_TYPE_Q40: return (u16 __iomem *)Q40_ISA_IO_W(addr); + case Q40_ISA: return (u16 __iomem *)Q40_ISA_IO_W(addr); +#endif +#ifdef CONFIG_GG2 + case GG2_ISA: return (u16 __iomem *)GG2_ISA_IO_W(addr); #endif #ifdef CONFIG_AMIGA_PCMCIA - case ISA_TYPE_AG: return (u16 __iomem *)AG_ISA_IO_W(addr); + case AG_ISA: return (u16 __iomem *)AG_ISA_IO_W(addr); #endif - default: return NULL; /* avoid warnings, just in case */ - } + default: return NULL; /* avoid warnings, just in case */ + } } static inline u32 __iomem *isa_itl(unsigned long addr) { - switch(ISA_TYPE) - { + switch (ISA_TYPE) { #ifdef CONFIG_AMIGA_PCMCIA - case ISA_TYPE_AG: return (u32 __iomem *)AG_ISA_IO_W(addr); + case AG_ISA: return (u32 __iomem *)AG_ISA_IO_W(addr); #endif - default: return 0; /* avoid warnings, just in case */ - } + default: return 0; /* avoid warnings, just in case */ + } } static inline u8 __iomem *isa_mtb(unsigned long addr) { - switch(ISA_TYPE) - { + switch (ISA_TYPE) { #ifdef CONFIG_Q40 - case ISA_TYPE_Q40: return (u8 __iomem *)Q40_ISA_MEM_B(addr); + case Q40_ISA: return (u8 __iomem *)Q40_ISA_MEM_B(addr); +#endif +#ifdef CONFIG_GG2 + case GG2_ISA: return (u8 __iomem *)GG2_ISA_MEM_B(addr); #endif #ifdef CONFIG_AMIGA_PCMCIA - case ISA_TYPE_AG: return (u8 __iomem *)addr; + case AG_ISA: return (u8 __iomem *)addr; #endif - default: return NULL; /* avoid warnings, just in case */ - } + default: return NULL; /* avoid warnings, just in case */ + } } static inline u16 __iomem *isa_mtw(unsigned long addr) { - switch(ISA_TYPE) - { + switch (ISA_TYPE) { #ifdef CONFIG_Q40 - case ISA_TYPE_Q40: return (u16 __iomem *)Q40_ISA_MEM_W(addr); + case Q40_ISA: return (u16 __iomem *)Q40_ISA_MEM_W(addr); +#endif +#ifdef CONFIG_GG2 + case GG2_ISA: return (u16 __iomem *)GG2_ISA_MEM_W(addr); #endif #ifdef CONFIG_AMIGA_PCMCIA - case ISA_TYPE_AG: return (u16 __iomem *)addr; + case AG_ISA: return (u16 __iomem *)addr; #endif - default: return NULL; /* avoid warnings, just in case */ - } + default: return NULL; /* avoid warnings, just in case */ + } } @@ -167,27 +213,30 @@ static inline u16 __iomem *isa_mtw(unsig #define isa_outw(val,port) (ISA_SEX ? out_be16(isa_itw(port),(val)) : out_le16(isa_itw(port),(val))) #define isa_outl(val,port) (ISA_SEX ? out_be32(isa_itl(port),(val)) : out_le32(isa_itl(port),(val))) -#define isa_readb(p) in_8(isa_mtb((unsigned long)(p))) -#define isa_readw(p) \ - (ISA_SEX ? in_be16(isa_mtw((unsigned long)(p))) \ - : in_le16(isa_mtw((unsigned long)(p)))) -#define isa_writeb(val,p) out_8(isa_mtb((unsigned long)(p)),(val)) -#define isa_writew(val,p) \ - (ISA_SEX ? out_be16(isa_mtw((unsigned long)(p)),(val)) \ - : out_le16(isa_mtw((unsigned long)(p)),(val))) - +#define isa_readb(p) in_8(isa_mtb(p)) +#define isa_readw(p) (ISA_SEX ? in_be16(isa_mtw(p)) : in_le16(isa_mtw(p))) +#define isa_writeb(val, p) out_8(isa_mtb(p), (val)) +#define isa_writew(val, p) \ + (ISA_SEX ? out_be16(isa_mtw(p), (val)) : out_le16(isa_mtw(p), (val))) static inline void isa_delay(void) { - switch(ISA_TYPE) - { + switch (ISA_TYPE) { #ifdef CONFIG_Q40 - case ISA_TYPE_Q40: isa_outb(0,0x80); break; + case Q40_ISA: + isa_outb(0, 0x80); + break; +#endif +#ifdef CONFIG_GG2 + case GG2_ISA: + break; #endif #ifdef CONFIG_AMIGA_PCMCIA - case ISA_TYPE_AG: break; + case AG_ISA: + break; #endif - default: break; /* avoid warnings */ - } + default: + break; /* avoid warnings */ + } } #define isa_inb_p(p) ({u8 v=isa_inb(p);isa_delay();v;}) @@ -216,7 +265,10 @@ static inline void isa_delay(void) (ISA_SEX ? raw_outsl(isa_itl(port), (u32 *)(buf), (nr)) : \ raw_outsw_swapw(isa_itw(port), (u16 *)(buf), (nr)<<1)) +#endif /* CONFIG_ISA */ + +#if defined(CONFIG_ISA) && !defined(CONFIG_PCI) #define inb isa_inb #define inb_p isa_inb_p #define outb isa_outb @@ -239,9 +291,80 @@ static inline void isa_delay(void) #define readw isa_readw #define writeb isa_writeb #define writew isa_writew +#endif /* CONFIG_ISA */ + +#if defined(CONFIG_PCI) + +#define readl(addr) in_le32(addr) +#define writel(val, addr) out_le32((addr), (val)) + +/* those can be defined for both ISA and PCI - it won't work though */ +#define readb(addr) in_8(addr) +#define readw(addr) in_le16(addr) +#define writeb(val, addr) out_8((addr), (val)) +#define writew(val, addr) out_le16((addr), (val)) + +#define readb_relaxed(addr) readb(addr) +#define readw_relaxed(addr) readw(addr) +#define readl_relaxed(addr) readl(addr) + +#ifndef CONFIG_ISA +#define inb(port) in_8(port) +#define outb(val, port) out_8((port), (val)) +#define inw(port) in_le16(port) +#define outw(val, port) out_le16((port), (val)) +#define inl(port) in_le32(port) +#define outl(val, port) out_le32((port), (val)) +#define insb(port, buf, nr) \ + raw_insb((u8 *)(port), (u8 *)(buf), (nr)) +#define outsb(port, buf, nr) \ + raw_outsb((u8 *)(port), (u8 *)(buf), (nr)) +#define insw(port, buf, nr) \ + raw_insw_swapw((u16 *)(port), (u16 *)(buf), (nr)) +#define outsw(port, buf, nr) \ + raw_outsw_swapw((u16 *)(port), (u16 *)(buf), (nr)) +#define insl(port, buf, nr) \ + raw_insw_swapw((u16 *)(port), (u16 *)(buf), (nr)<<1) +#define outsl(port, buf, nr) \ + raw_outsw_swapw((u16 *)(port), (u16 *)(buf), (nr)<<1) + +#define __raw_readb readb +#define __raw_readw readw +#define __raw_readl readl +#define __raw_writeb writeb +#define __raw_writew writew +#define __raw_writel writel -#else /* CONFIG_ISA */ +#else +/* + * kernel with both ISA and PCI compiled in, those have + * conflicting defs for in/out. Simply consider port < 1024 + * ISA and everything else PCI. read,write not defined + * in this case + */ +#define inb(port) ((port) < 1024 ? isa_inb(port) : in_8(port)) +#define inb_p(port) ((port) < 1024 ? isa_inb_p(port) : in_8(port)) +#define inw(port) ((port) < 1024 ? isa_inw(port) : in_le16(port)) +#define inw_p(port) ((port) < 1024 ? isa_inw_p(port) : in_le16(port)) +#define inl(port) ((port) < 1024 ? isa_inl(port) : in_le32(port)) +#define inl_p(port) ((port) < 1024 ? isa_inl_p(port) : in_le32(port)) + +#define outb(val, port) (((port) < 1024) ? isa_outb((val), (port)) + : out_8((port), (val))) +#define outb_p(val, port) (((port) < 1024) ? isa_outb_p((val), (port)) + : out_8((port), (val))) +#define outw(val, port) (((port) < 1024) ? isa_outw((val), (port)) + : out_le16((port), (val))) +#define outw_p(val, port) (((port) < 1024) ? isa_outw_p((val), (port)) + : out_le16((port), (val))) +#define outl(val, port) (((port) < 1024) ? isa_outl((val), (port)) + : out_le32((port), (val))) +#define outl_p(val, port) (((port) < 1024) ? isa_outl_p((val), (port)) + : out_le32((port), (val))) +#endif +#endif /* CONFIG_PCI */ +#if !defined(CONFIG_ISA) && !defined(CONFIG_PCI) /* * We need to define dummy functions for GENERIC_IOMAP support. */ @@ -272,11 +395,11 @@ static inline void isa_delay(void) #define writeb(val,addr) out_8((addr),(val)) #define readw(addr) in_le16(addr) #define writew(val,addr) out_le16((addr),(val)) - -#endif /* CONFIG_ISA */ - +#endif +#if !defined(CONFIG_PCI) #define readl(addr) in_le32(addr) #define writel(val,addr) out_le32((addr),(val)) +#endif #define mmiowb() @@ -333,4 +456,5 @@ static inline void memcpy_toio(volatile */ #define xlate_dev_kmem_ptr(p) p +#endif /* CONFIG_COLDFIRE */ #endif /* _IO_H */ --- a/arch/m68k/include/asm/irq.h +++ b/arch/m68k/include/asm/irq.h @@ -1,14 +1,20 @@ -#ifndef _M68K_IRQ_H_ -#define _M68K_IRQ_H_ - /* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + * * This should be the same as the max(NUM_X_SOURCES) for all the * different m68k hosts compiled into the kernel. * Currently the Atari has 72 and the Amiga 24, but if both are * supported in the kernel it is better to make room for 72. */ +#ifndef _M68K_IRQ_H_ +#define _M68K_IRQ_H_ #if defined(CONFIG_COLDFIRE) -#define NR_IRQS 256 +#define SYS_IRQS 256 +#define NR_IRQS SYS_IRQS #elif defined(CONFIG_VME) || defined(CONFIG_SUN3) || defined(CONFIG_SUN3X) #define NR_IRQS 200 #elif defined(CONFIG_ATARI) || defined(CONFIG_MAC) --- a/arch/m68k/include/asm/machdep.h +++ b/arch/m68k/include/asm/machdep.h @@ -1,6 +1,12 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ #ifndef _M68K_MACHDEP_H #define _M68K_MACHDEP_H - #include #include @@ -42,4 +48,11 @@ extern irqreturn_t arch_timer_interrupt( extern void config_BSP(char *command, int len); extern void do_IRQ(int irq, struct pt_regs *fp); +#ifdef CONFIG_COLDFIRE +extern void __init config_coldfire(void); +extern void __init mmu_context_init(void); +extern irq_handler_t mach_default_handler; +extern void (*mach_tick)(void); +#endif + #endif /* _M68K_MACHDEP_H */ --- /dev/null +++ b/arch/m68k/include/asm/mcfdspi.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Author: Andrey Butok + * + * This file is based on mcfqspi.h + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + *************************************************************************** + * Changes: + * v0.001 25 March 2008 Andrey Butok + * Initial Release - developed on uClinux with 2.6.23 kernel. + * + */ + +#ifndef MCFDSPI_H_ +#define MCFDSPI_H_ + +struct coldfire_dspi_chip { + u8 mode; + u8 bits_per_word; + u16 void_write_data; + /* Only used in master mode */ + u8 dbr; /* Double baud rate */ + u8 pbr; /* Baud rate prescaler */ + u8 br; /* Baud rate scaler */ + u8 pcssck; /* PCS to SCK delay prescaler */ + u8 pasc; /* After SCK delay prescaler */ + u8 pdt; /* Delay after transfer prescaler */ + u8 cssck; /* PCS to SCK delay scaler */ + u8 asc; /* After SCK delay scaler */ + u8 dt; /* Delay after transfer scaler */ +}; + +struct coldfire_spi_master { + u16 bus_num; + u16 num_chipselect; + u8 irq_source; + u32 irq_vector; + u32 irq_mask; + u8 irq_lp; + u8 par_val; + u16 par_val16; + u32 *irq_list; + void (*cs_control)(u8 cs, u8 command); +}; +#endif /*MCFDSPI_H_*/ --- a/arch/m68k/include/asm/mcfsim.h +++ b/arch/m68k/include/asm/mcfsim.h @@ -5,6 +5,12 @@ * * (C) Copyright 1999-2003, Greg Ungerer (gerg@snapgear.com) * (C) Copyright 2000, Lineo Inc. (www.lineo.com) + * + * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. */ /****************************************************************************/ @@ -45,5 +51,120 @@ #include #endif +#if defined(CONFIG_COLDFIRE) +#include +#endif + +#if defined(CONFIG_M5445X) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#elif defined(CONFIG_M547X_8X) +#include +#include +#include +#elif defined(CONFIG_M5441X) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +/* + * Define the base address of the SIM within the MBAR address space. + */ +#define MCFSIM_BASE 0x0 /* Base address of SIM */ + + +/* + * Bit definitions for the ICR family of registers. + */ +#define MCFSIM_ICR_AUTOVEC 0x80 /* Auto-vectored intr */ +#define MCFSIM_ICR_LEVEL0 0x00 /* Level 0 intr */ +#define MCFSIM_ICR_LEVEL1 0x04 /* Level 1 intr */ +#define MCFSIM_ICR_LEVEL2 0x08 /* Level 2 intr */ +#define MCFSIM_ICR_LEVEL3 0x0c /* Level 3 intr */ +#define MCFSIM_ICR_LEVEL4 0x10 /* Level 4 intr */ +#define MCFSIM_ICR_LEVEL5 0x14 /* Level 5 intr */ +#define MCFSIM_ICR_LEVEL6 0x18 /* Level 6 intr */ +#define MCFSIM_ICR_LEVEL7 0x1c /* Level 7 intr */ + +#define MCFSIM_ICR_PRI0 0x00 /* Priority 0 intr */ +#define MCFSIM_ICR_PRI1 0x01 /* Priority 1 intr */ +#define MCFSIM_ICR_PRI2 0x02 /* Priority 2 intr */ +#define MCFSIM_ICR_PRI3 0x03 /* Priority 3 intr */ + +/* + * Bit definitions for the Interrupt Mask register (IMR). + */ +#define MCFSIM_IMR_EINT1 0x0002 /* External intr # 1 */ +#define MCFSIM_IMR_EINT2 0x0004 /* External intr # 2 */ +#define MCFSIM_IMR_EINT3 0x0008 /* External intr # 3 */ +#define MCFSIM_IMR_EINT4 0x0010 /* External intr # 4 */ +#define MCFSIM_IMR_EINT5 0x0020 /* External intr # 5 */ +#define MCFSIM_IMR_EINT6 0x0040 /* External intr # 6 */ +#define MCFSIM_IMR_EINT7 0x0080 /* External intr # 7 */ + +#define MCFSIM_IMR_SWD 0x0100 /* Software Watchdog intr */ +#define MCFSIM_IMR_TIMER1 0x0200 /* TIMER 1 intr */ +#define MCFSIM_IMR_TIMER2 0x0400 /* TIMER 2 intr */ +#define MCFSIM_IMR_MBUS 0x0800 /* MBUS intr */ +#define MCFSIM_IMR_UART1 0x1000 /* UART 1 intr */ +#define MCFSIM_IMR_UART2 0x2000 /* UART 2 intr */ + +#if defined(CONFIG_M5206e) +#define MCFSIM_IMR_DMA1 0x4000 /* DMA 1 intr */ +#define MCFSIM_IMR_DMA2 0x8000 /* DMA 2 intr */ +#elif defined(CONFIG_M5249) || defined(CONFIG_M5307) +#define MCFSIM_IMR_DMA0 0x4000 /* DMA 0 intr */ +#define MCFSIM_IMR_DMA1 0x8000 /* DMA 1 intr */ +#define MCFSIM_IMR_DMA2 0x10000 /* DMA 2 intr */ +#define MCFSIM_IMR_DMA3 0x20000 /* DMA 3 intr */ +#endif + +/* + * Mask for all of the SIM devices. Some parts have more or less + * SIM devices. This is a catchall for the sandard set. + */ +#ifndef MCFSIM_IMR_MASKALL +#define MCFSIM_IMR_MASKALL 0x3ffe /* All intr sources */ +#endif + + +/* + * PIT interrupt settings, if not found in mXXXXsim.h file. + */ +#ifndef ICR_INTRCONF +#define ICR_INTRCONF 0x2b /* PIT1 level 5, priority 3 */ +#endif +#ifndef MCFPIT_IMR +#define MCFPIT_IMR MCFINTC_IMRH +#endif +#ifndef MCFPIT_IMR_IBIT +#define MCFPIT_IMR_IBIT (1 << (MCFINT_PIT1 - 32)) +#endif + + +#ifndef __ASSEMBLY__ +/* + * Definition for the interrupt auto-vectoring support. + */ +extern void mcf_autovector(unsigned int vec); +#endif /* __ASSEMBLY__ */ + /****************************************************************************/ #endif /* mcfsim_h */ --- a/arch/m68k/include/asm/mcfuart.h +++ b/arch/m68k/include/asm/mcfuart.h @@ -5,6 +5,11 @@ * * (C) Copyright 1999-2003, Greg Ungerer (gerg@snapgear.com) * (C) Copyright 2000, Lineo Inc. (www.lineo.com) + * Copyright (C) 2009-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. */ /****************************************************************************/ @@ -12,6 +17,59 @@ #define mcfuart_h /****************************************************************************/ +#if defined(CONFIG_M5445X) +#include +#define MCFUART_BASE1 0xfc060000 /* Base address of UART1 */ +#define MCFUART_BASE2 0xfc064000 /* Base address of UART2 */ +#define MCFUART_BASE3 0xfc068000 /* Base address of UART3 */ +#define MCFINT_VECBASE 64 +#define MCFINT_UART0 26 +#define MCFINT_UART1 27 +#elif defined(CONFIG_M547X_8X) +#define MCFUART_BASE1 0x8600 /* Base address of UART1 */ +#define MCFUART_BASE2 0x8700 /* Base address of UART2 */ +#define MCFUART_BASE3 0x8800 /* Base address of UART3 */ +#define MCFUART_BASE4 0x8900 /* Base address of UART4 */ +#define MCFINT_VECBASE 64 +#define MCFINT_UART0 35 +#define MCFINT_UART1 34 +#define MCFINT_UART2 33 +#define MCFINT_UART3 32 +#elif defined(CONFIG_M5441X) +#define MCFUART_BASE0 0xfc060000 /* Base address of UART1 */ +#define MCFUART_BASE1 0xfc064000 /* Base address of UART2 */ +#define MCFUART_BASE2 0xfc068000 /* Base address of UART3 */ +#define MCFUART_BASE3 0xfc06C000 /* Base address of UART4 */ +#define MCFUART_BASE4 0xec060000 +#define MCFUART_BASE5 0xec064000 +#define MCFUART_BASE6 0xec068000 +#define MCFUART_BASE7 0xec06C000 +#define MCFUART_BASE8 0xec070000 +#define MCFUART_BASE9 0xec074000 + +#define MCFINT0_VECBASE 64 +#define MCFINT1_VECBASE (64 + 64) +#define MCFINT_UART0 26 +#define MCFINT_UART1 27 +#define MCFINT_UART2 28 +#define MCFINT_UART3 29 +#define MCFINT_UART4 48 +#define MCFINT_UART5 49 +#define MCFINT_UART6 50 +#define MCFINT_UART7 51 +#define MCFINT_UART8 52 +#define MCFINT_UART9 53 +#endif + +#if defined(CONFIG_M5441X) +#define MAX_PORT_NUM 10 +#elif defined(CONFIG_M547X_8X) +#define MAX_PORT_NUM 4 +#else +#define MAX_PORT_NUM 3 +#endif + +#ifndef __ASSEMBLY__ #include #include @@ -21,6 +79,7 @@ struct mcf_platform_uart { unsigned int irq; /* Interrupt vector */ unsigned int uartclk; /* UART clock rate */ }; +#endif /* * Define the ColdFire UART register set addresses. @@ -94,6 +153,11 @@ struct mcf_platform_uart { #define MCFUART_USR_RXFULL 0x02 /* Receiver full */ #define MCFUART_USR_RXREADY 0x01 /* Receiver ready */ +#if defined(CONFIG_M547X_8X) +#define MCFUART_USR_TXREADY_BN 0x0a +#define MCFUART_USR_TXEMPTY_BN 0x0b +#endif + #define MCFUART_USR_RXERR (MCFUART_USR_RXBREAK | MCFUART_USR_RXFRAMING | \ MCFUART_USR_RXPARITY | MCFUART_USR_RXOVERRUN) --- a/arch/m68k/include/asm/mmu.h +++ b/arch/m68k/include/asm/mmu.h @@ -1,9 +1,22 @@ +/* + * Copyright (C) 2009-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ #ifndef __MMU_H #define __MMU_H - #ifdef CONFIG_MMU +#ifdef CONFIG_VDSO +typedef struct { + unsigned long id; + void *vdso; +} mm_context_t; +#else /* Default "unsigned long" context */ typedef unsigned long mm_context_t; +#endif #else typedef struct { unsigned long end_brk; --- a/arch/m68k/include/asm/mmu_context.h +++ b/arch/m68k/include/asm/mmu_context.h @@ -1,14 +1,21 @@ +/* + * Copyright (C) 2009-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ #ifndef __M68K_MMU_CONTEXT_H #define __M68K_MMU_CONTEXT_H - #include +#include static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) { } #ifdef CONFIG_MMU -#ifndef CONFIG_SUN3 +#if !defined(CONFIG_SUN3) && !defined(CONFIG_COLDFIRE) #include #include @@ -103,7 +110,7 @@ static inline void activate_mm(struct mm switch_mm_0460(next_mm); } -#else /* CONFIG_SUN3 */ +#elif defined(CONFIG_SUN3) #include #include @@ -151,7 +158,178 @@ static inline void activate_mm(struct mm activate_context(next_mm); } +#else /* CONFIG_COLDFIRE */ + +#include +#include +#include +#include + +#define NO_CONTEXT 256 +#define LAST_CONTEXT 255 +#define FIRST_CONTEXT 1 + +#ifdef CONFIG_VDSO +#define cpu_context(mm) ((mm)->context.id) +#else +#define cpu_context(mm) ((mm)->context) +#endif + +#ifdef CONFIG_VDSO +extern void set_context(unsigned long context, pgd_t *pgd); +#else +extern void set_context(mm_context_t context, pgd_t *pgd); #endif +extern unsigned long context_map[]; +#ifdef CONFIG_VDSO +extern unsigned long next_mmu_context; +#else +extern mm_context_t next_mmu_context; +#endif + +extern atomic_t nr_free_contexts; +extern struct mm_struct *context_mm[LAST_CONTEXT+1]; +extern void steal_context(void); + +static inline void get_mmu_context(struct mm_struct *mm) +{ +#ifdef CONFIG_VDSO + unsigned long ctx; +#else + mm_context_t ctx; +#endif + + if (cpu_context(mm) != NO_CONTEXT) + return; + while (atomic_dec_and_test_lt(&nr_free_contexts)) { + atomic_inc(&nr_free_contexts); + steal_context(); + } + ctx = next_mmu_context; + while (test_and_set_bit(ctx, context_map)) { + ctx = find_next_zero_bit(context_map, LAST_CONTEXT+1, ctx); + if (ctx > LAST_CONTEXT) + ctx = 0; + } + next_mmu_context = (ctx + 1) & LAST_CONTEXT; + cpu_context(mm) = ctx; + context_mm[ctx] = mm; +} + +/* + * Set up the context for a new address space. + */ +#define init_new_context(tsk, mm) ((cpu_context(mm) = NO_CONTEXT), 0) +/* #define init_new_context(tsk, mm) (((mm)->context = NO_CONTEXT), 0) */ + +/* + * We're finished using the context for an address space. + */ +static inline void destroy_context(struct mm_struct *mm) +{ + if (cpu_context(mm) != NO_CONTEXT) { + clear_bit(cpu_context(mm), context_map); + cpu_context(mm) = NO_CONTEXT; + atomic_inc(&nr_free_contexts); + } +} + +static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, + struct task_struct *tsk) +{ + get_mmu_context(tsk->mm); + set_context(cpu_context(tsk->mm), next->pgd); +} + +/* + * After we have set current->mm to a new value, this activates + * the context for the new mm so we see the new mappings. + */ +static inline void activate_mm(struct mm_struct *active_mm, + struct mm_struct *mm) +{ + get_mmu_context(mm); + set_context(cpu_context(mm), mm->pgd); +} + +#define deactivate_mm(tsk, mm) do { } while (0) + +extern void mmu_context_init(void); +#if defined(CONFIG_M547X_8X) +#define prepare_arch_switch(next) load_ksp_mmu(next) + +static inline void load_ksp_mmu(struct task_struct *task) +{ + unsigned long flags; + struct mm_struct *mm; + int asid; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + unsigned long mmuar; + + local_irq_save(flags); + mmuar = task->thread.ksp; + + /* Search for a valid TLB entry, if one is found, don't remap */ + *MMUAR = mmuar; + *MMUOR = MMUOR_STLB | MMUOR_ADR; + if ((*MMUSR) & MMUSR_HIT) + goto end; + + if (mmuar >= PAGE_OFFSET) { + mm = &init_mm; + } else { + printk(KERN_INFO "load_ksp_mmu: non-kernel" + " mm found: 0x%08x\n", + (unsigned int) task->mm); + mm = task->mm; + } + + if (!mm) + goto bug; + + pgd = pgd_offset(mm, mmuar); + if (pgd_none(*pgd)) + goto bug; + + pmd = pmd_offset(pgd, mmuar); + if (pmd_none(*pmd)) + goto bug; + + pte = (mmuar >= PAGE_OFFSET) ? pte_offset_kernel(pmd, mmuar) + : pte_offset_map(pmd, mmuar); + if (pte_none(*pte) || !pte_present(*pte)) + goto bug; + + set_pte(pte, pte_mkyoung(*pte)); + asid = cpu_context(mm) & 0xff; + if (!pte_dirty(*pte) && mmuar <= PAGE_OFFSET) + set_pte(pte, pte_wrprotect(*pte)); + + *MMUTR = (mmuar & PAGE_MASK) | (asid << CF_ASID_MMU_SHIFT) + | (((int)(pte->pte) & (int)CF_PAGE_MMUTR_MASK) + >> CF_PAGE_MMUTR_SHIFT) + | MMUTR_V; + + *MMUDR = (pte_val(*pte) & PAGE_MASK) + | ((pte->pte) & CF_PAGE_MMUDR_MASK) + | MMUDR_SZ8K | MMUDR_X; + + *MMUOR = MMUOR_ACC | MMUOR_UAA; + asm ("nop"); + + goto end; + +bug: + printk(KERN_ERR "ksp load failed: mm=0x%08x ksp=0x%08x\n", + (unsigned int) mm, (unsigned int) mmuar); +end: + local_irq_restore(flags); +} +#endif /* CONFIG_M547X_8X */ +#endif /* CONFIG_COLDFIRE */ + #else /* !CONFIG_MMU */ static inline int init_new_context(struct task_struct *tsk, struct mm_struct *mm) --- a/arch/m68k/include/asm/page.h +++ b/arch/m68k/include/asm/page.h @@ -1,12 +1,18 @@ +/* + * Copyright (C) 2009-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ #ifndef _M68K_PAGE_H #define _M68K_PAGE_H - #include #include #include /* PAGE_SHIFT determines the page size */ -#ifndef CONFIG_SUN3 +#if !defined(CONFIG_SUN3) && !defined(CONFIG_COLDFIRE) #define PAGE_SHIFT (12) #else #define PAGE_SHIFT (13) --- a/arch/m68k/include/asm/page_mm.h +++ b/arch/m68k/include/asm/page_mm.h @@ -1,5 +1,17 @@ +/* + * Copyright (C) 2009-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ #ifndef _M68K_PAGE_MM_H #define _M68K_PAGE_MM_H +#if PAGE_SHIFT < 13 +#define THREAD_SIZE (8192) +#else +#define THREAD_SIZE PAGE_SIZE +#endif #ifndef __ASSEMBLY__ @@ -70,6 +82,49 @@ extern unsigned long m68k_memoffset; #define WANT_PAGE_VIRTUAL +#if defined(CONFIG_COLDFIRE) +extern unsigned long cf_dma_base; +extern unsigned long cf_dma_end; + +static inline unsigned long ___pa(void *vaddr) +{ +#if CONFIG_SDRAM_BASE != PAGE_OFFSET + return ((unsigned long)vaddr & 0x0fffffff) + CONFIG_SDRAM_BASE; +#else + if ((unsigned long)vaddr >= CONFIG_DMA_BASE && + (unsigned long)vaddr < (CONFIG_DMA_BASE + CONFIG_DMA_SIZE)) { + /* address is in carved out DMA range */ + return ((unsigned long)vaddr - CONFIG_DMA_BASE) + + CONFIG_SDRAM_BASE; + } else if ((unsigned long)vaddr >= PAGE_OFFSET && + (unsigned long)vaddr < (PAGE_OFFSET + CONFIG_SDRAM_SIZE)) { + /* normal mapping */ + return ((unsigned long)vaddr - PAGE_OFFSET) + CONFIG_SDRAM_BASE; + } + + return (unsigned long)vaddr; +#endif +} +#define __pa(vaddr) ___pa((void *)(vaddr)) + +static inline void *__va(unsigned long paddr) +{ +#if CONFIG_SDRAM_BASE != PAGE_OFFSET + return (void *)((paddr & 0x0fffffff) + PAGE_OFFSET); +#else + if (paddr >= cf_dma_base && paddr <= cf_dma_end) { + /* mapped address for DMA */ + return (void *)((paddr - CONFIG_SDRAM_BASE) + CONFIG_DMA_BASE); + } else if (paddr >= cf_dma_end && + paddr < (CONFIG_SDRAM_BASE + CONFIG_SDRAM_SIZE)) { + /* normal mapping */ + return (void *)((paddr - CONFIG_SDRAM_BASE) + PAGE_OFFSET); + } + return (void *)paddr; +#endif +} + +#else static inline unsigned long ___pa(void *vaddr) { unsigned long paddr; @@ -91,6 +146,7 @@ static inline void *__va(unsigned long p : "0" (paddr), "i" (m68k_fixup_memoffset)); return vaddr; } +#endif #else /* !CONFIG_SUN3 */ /* This #define is a horrible hack to suppress lots of warnings. --m */ @@ -176,4 +232,9 @@ static inline __attribute_const__ int __ #define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) +#ifdef CONFIG_VDSO +/* vDSO support */ +#define __HAVE_ARCH_GATE_AREA +#endif + #endif /* _M68K_PAGE_MM_H */ --- a/arch/m68k/include/asm/page_offset.h +++ b/arch/m68k/include/asm/page_offset.h @@ -1,10 +1,21 @@ -/* This handles the memory map.. */ - +/* + * Page and physical memory maps. + * + * Copyright (C) 2009-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ #ifdef CONFIG_MMU -#ifndef CONFIG_SUN3 -#define PAGE_OFFSET_RAW 0x00000000 -#else +#if defined(CONFIG_SUN3) #define PAGE_OFFSET_RAW 0x0E000000 +#elif defined(CONFIG_M5445X) || defined(CONFIG_M547X_8X) \ + || defined(CONFIG_M5441X) +#define PHYS_OFFSET CONFIG_SDRAM_BASE +#define PAGE_OFFSET_RAW (PHYS_OFFSET) +#else +#define PAGE_OFFSET_RAW 0x00000000 #endif #else #define PAGE_OFFSET_RAW CONFIG_RAMBASE --- a/arch/m68k/include/asm/pgalloc.h +++ b/arch/m68k/include/asm/pgalloc.h @@ -1,14 +1,22 @@ +/* + * Copyright (C) 2009-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ #ifndef M68K_PGALLOC_H #define M68K_PGALLOC_H - #include #include #include #ifdef CONFIG_MMU #include -#ifdef CONFIG_SUN3 +#if defined(CONFIG_SUN3) #include +#elif defined(CONFIG_COLDFIRE) +#include #else #include #endif --- a/arch/m68k/include/asm/pgtable_mm.h +++ b/arch/m68k/include/asm/pgtable_mm.h @@ -1,6 +1,12 @@ +/* + * Copyright (C) 2009-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ #ifndef _M68K_PGTABLE_H #define _M68K_PGTABLE_H - #include #include @@ -40,6 +46,8 @@ /* PGDIR_SHIFT determines what a third-level page table entry can map */ #ifdef CONFIG_SUN3 #define PGDIR_SHIFT 17 +#elif defined(CONFIG_COLDFIRE) +#define PGDIR_SHIFT 22 #else #define PGDIR_SHIFT 25 #endif @@ -54,6 +62,10 @@ #define PTRS_PER_PTE 16 #define PTRS_PER_PMD 1 #define PTRS_PER_PGD 2048 +#elif defined(CONFIG_COLDFIRE) +#define PTRS_PER_PTE 512 +#define PTRS_PER_PMD 1 +#define PTRS_PER_PGD 1024 #else #define PTRS_PER_PTE 1024 #define PTRS_PER_PMD 8 @@ -66,6 +78,18 @@ #ifdef CONFIG_SUN3 #define KMAP_START 0x0DC00000 #define KMAP_END 0x0E000000 +#elif defined(CONFIG_COLDFIRE) +#if defined(CONFIG_M5445X) || defined(CONFIG_M547X_8X) +#define VMALLOC_START 0xc0000000 +#define VMALLOC_END 0xcfffffff +#define KMAP_START (VMALLOC_END + 1) +#define KMAP_END (0xe8000000 - 1) +#elif defined(CONFIG_M5441X) +#define VMALLOC_START 0xc0000000 +#define VMALLOC_END 0xcfffffff +#define KMAP_START (VMALLOC_END + 1) +#define KMAP_END (0xd8000000 - 1) +#endif #else #define KMAP_START 0xd0000000 #define KMAP_END 0xf0000000 @@ -79,9 +103,11 @@ * The vmalloc() routines leaves a hole of 4kB between each vmalloced * area for the same reason. ;) */ +#if !defined(CONFIG_COLDFIRE) #define VMALLOC_OFFSET (8*1024*1024) #define VMALLOC_START (((unsigned long) high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) #define VMALLOC_END KMAP_START +#endif #else extern unsigned long m68k_vmalloc_end; #define VMALLOC_START 0x0f800000 @@ -130,6 +156,8 @@ static inline void update_mmu_cache(stru #ifdef CONFIG_SUN3 #include +#elif defined(CONFIG_COLDFIRE) +#include #else #include #endif @@ -143,6 +171,10 @@ static inline void update_mmu_cache(stru #else # define __SUN3_PAGE_NOCACHE 0 #endif + +#ifdef CONFIG_COLDFIRE +# define pgprot_noncached(prot) (__pgprot(pgprot_val(prot) | CF_PAGE_NOCACHE)) +#else /* CONFIG_COLDFIRE */ #define pgprot_noncached(prot) \ (MMU_IS_SUN3 \ ? (__pgprot(pgprot_val(prot) | __SUN3_PAGE_NOCACHE)) \ @@ -151,7 +183,7 @@ static inline void update_mmu_cache(stru : (MMU_IS_040 || MMU_IS_060) \ ? (__pgprot((pgprot_val(prot) & _CACHEMASK040) | _PAGE_NOCACHE_S)) \ : (prot))) - +#endif /* CONFIG_COLDFIRE */ #include #endif /* !__ASSEMBLY__ */ --- a/arch/m68k/include/asm/processor.h +++ b/arch/m68k/include/asm/processor.h @@ -2,6 +2,11 @@ * include/asm-m68k/processor.h * * Copyright (C) 1995 Hamish Macdonald + * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. */ #ifndef __ASM_M68K_PROCESSOR_H @@ -23,6 +28,10 @@ static inline unsigned long rdusp(void) #ifdef CONFIG_COLDFIRE_SW_A7 extern unsigned int sw_usp; return sw_usp; +#elif defined(CONFIG_COLDFIRE) + unsigned long usp; + __asm__ __volatile__("movel %/usp,%0" : "=a" (usp)); + return usp; #else register unsigned long usp __asm__("a0"); /* move %usp,%a0 */ @@ -36,6 +45,8 @@ static inline void wrusp(unsigned long u #ifdef CONFIG_COLDFIRE_SW_A7 extern unsigned int sw_usp; sw_usp = usp; +#elif defined(CONFIG_COLDFIRE) + __asm__ __volatile__("movel %0,%/usp" : : "a" (usp)); #else register unsigned long a0 __asm__("a0") = usp; /* move %a0,%usp */ @@ -48,11 +59,17 @@ static inline void wrusp(unsigned long u * so don't change it unless you know what you are doing. */ #ifdef CONFIG_MMU -#ifndef CONFIG_SUN3 +#if !defined(CONFIG_SUN3) && !defined(CONFIG_COLDFIRE) #define TASK_SIZE (0xF0000000UL) +#elif defined(CONFIG_COLDFIRE) +#define TASK_SIZE (0xC0000000UL) +#else /* CONFIG_SUN3 */ +#ifdef __ASSEMBLY__ +#define TASK_SIZE (0x0E000000) #else #define TASK_SIZE (0x0E000000UL) #endif +#endif #else #define TASK_SIZE (0xFFFFFFFFUL) #endif @@ -66,8 +83,10 @@ static inline void wrusp(unsigned long u * space during mmap's. */ #ifdef CONFIG_MMU -#ifndef CONFIG_SUN3 +#if !defined(CONFIG_SUN3) && !defined(CONFIG_COLDFIRE) #define TASK_UNMAPPED_BASE 0xC0000000UL +#elif defined(CONFIG_COLDFIRE) +#define TASK_UNMAPPED_BASE 0x60000000UL #else #define TASK_UNMAPPED_BASE 0x0A000000UL #endif @@ -80,7 +99,11 @@ struct thread_struct { unsigned long ksp; /* kernel stack pointer */ unsigned long usp; /* user stack pointer */ unsigned short sr; /* saved status register */ +#ifndef CONFIG_COLDFIRE unsigned short fs; /* saved fs (sfc, dfc) */ +#else + mm_segment_t fs; +#endif unsigned long crp[2]; /* cpu root pointer */ unsigned long esp0; /* points to SR of stack frame */ unsigned long faddr; /* info about last fault */ @@ -102,6 +125,7 @@ struct thread_struct { /* * Do necessary setup to start up a newly executed thread. */ +#ifndef CONFIG_COLDFIRE static inline void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long usp) { @@ -112,7 +136,24 @@ static inline void start_thread(struct p regs->sr &= ~0x2000; wrusp(usp); } +#else +/* + * Do necessary setup to start up a newly executed thread. + * + * pass the data segment into user programs if it exists, + * it can't hurt anything as far as I can tell + */ +#define start_thread(_regs, _pc, _usp) \ +do { \ + set_fs(USER_DS); /* reads from user space */ \ + (_regs)->pc = (_pc); \ + if (current->mm) \ + (_regs)->d5 = current->mm->start_data; \ + (_regs)->sr &= ~0x2000; \ + wrusp(_usp); \ +} while (0) +#endif #else /* --- a/arch/m68k/include/asm/ptrace.h +++ b/arch/m68k/include/asm/ptrace.h @@ -1,3 +1,10 @@ +/* + * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ #ifndef _M68K_PTRACE_H #define _M68K_PTRACE_H @@ -27,27 +34,38 @@ stack during a system call. */ struct pt_regs { - long d1; - long d2; - long d3; - long d4; - long d5; - long a0; - long a1; - long a2; - long d0; - long orig_d0; - long stkadj; + long d1; + long d2; + long d3; + long d4; + long d5; + long a0; + long a1; + long a2; + long d0; + long orig_d0; + long stkadj; #ifdef CONFIG_COLDFIRE +#if 0 unsigned format : 4; /* frame format specifier */ unsigned vector : 12; /* vector offset */ unsigned short sr; unsigned long pc; +#endif +/*FROM BSP*/ + unsigned long mmuar; + unsigned long mmusr; + unsigned format:4; /* frame format specifier */ + unsigned fs2:2; + unsigned vector:8; + unsigned fs1:2; + unsigned short sr; + unsigned long pc; #else - unsigned short sr; - unsigned long pc; - unsigned format : 4; /* frame format specifier */ - unsigned vector : 12; /* vector offset */ + unsigned short sr; + unsigned long pc; + unsigned format:4; /* frame format specifier */ + unsigned vector:12; /* vector offset */ #endif }; --- a/arch/m68k/include/asm/raw_io.h +++ b/arch/m68k/include/asm/raw_io.h @@ -3,11 +3,19 @@ * * 10/20/00 RZ: - created from bits of io.h and ide.h to cleanup namespace * + * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. */ - #ifndef _RAW_IO_H #define _RAW_IO_H +#ifdef CONFIG_COLDFIRE +#include +#else + #ifdef __KERNEL__ #include @@ -60,6 +68,9 @@ extern void __iounmap(void *addr, unsign #define __raw_writew(val,addr) out_be16((addr),(val)) #define __raw_writel(val,addr) out_be32((addr),(val)) +#define swap_inw(port) in_le16((port)) +#define swap_outw(val, port) out_le16((port), (val)) + static inline void raw_insb(volatile u8 __iomem *port, u8 *buf, unsigned int len) { unsigned int i; @@ -344,4 +355,6 @@ static inline void raw_outsw_swapw(volat #endif /* __KERNEL__ */ +#endif /* CONFIG_COLDFIRE */ + #endif /* _RAW_IO_H */ --- a/arch/m68k/include/asm/segment.h +++ b/arch/m68k/include/asm/segment.h @@ -1,3 +1,10 @@ +/* + * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ #ifndef _M68K_SEGMENT_H #define _M68K_SEGMENT_H @@ -29,6 +36,7 @@ typedef struct { * Get/set the SFC/DFC registers for MOVES instructions */ +#ifndef CONFIG_COLDFIRE static inline mm_segment_t get_fs(void) { #ifdef CONFIG_MMU @@ -56,6 +64,15 @@ static inline void set_fs(mm_segment_t v #endif } +#else /* CONFIG_COLDFIRE */ + +#include +#define get_fs() (current->thread.fs) +#define set_fs(val) (current->thread.fs = (val)) +#define get_ds() (KERNEL_DS) + +#endif /* CONFIG_COLDFIRE */ + #define segment_eq(a,b) ((a).seg == (b).seg) #endif /* __ASSEMBLY__ */ --- a/arch/m68k/include/asm/setup.h +++ b/arch/m68k/include/asm/setup.h @@ -2,6 +2,7 @@ ** asm/setup.h -- Definition of the Linux/m68k setup information ** ** Copyright 1992 by Greg Harp + * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved. ** ** This file is subject to the terms and conditions of the GNU General Public ** License. See the file COPYING in the main directory of this archive @@ -40,6 +41,7 @@ #define MACH_HP300 9 #define MACH_Q40 10 #define MACH_SUN3X 11 +#define MACH_CFMMU 12 #define COMMAND_LINE_SIZE 256 @@ -189,6 +191,14 @@ extern unsigned long m68k_machtype; # define MACH_TYPE (MACH_SUN3X) #endif +#if !defined(CONFIG_COLDFIRE) +# define MACH_IS_COLDFIRE (0) +#else +# define CONFIG_COLDFIRE_ONLY +# define MACH_IS_COLDFIRE (1) +# define MACH_TYPE (MACH_CFMMU) +#endif + #ifndef MACH_TYPE # define MACH_TYPE (m68k_machtype) #endif @@ -211,23 +221,31 @@ extern unsigned long m68k_machtype; #define CPUB_68030 1 #define CPUB_68040 2 #define CPUB_68060 3 +#define CPUB_CFV4E 4 #define CPU_68020 (1< /* Avoid too many header ordering problems. */ @@ -150,7 +156,7 @@ typedef struct sigaltstack { #ifdef __KERNEL__ #include -#ifndef __uClinux__ +#ifndef CONFIG_COLDFIRE /*FIXME Jason*/ #define __HAVE_ARCH_SIG_BITOPS static inline void sigaddset(sigset_t *set, int _sig) --- a/arch/m68k/include/asm/string.h +++ b/arch/m68k/include/asm/string.h @@ -1,6 +1,12 @@ +/* + * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ #ifndef _M68K_STRING_H_ #define _M68K_STRING_H_ - #include #include @@ -81,6 +87,18 @@ static inline char *strncpy(char *dest, strcpy(__d + strlen(__d), (s)); \ }) +#define __HAVE_ARCH_STRCHR +static inline char *strchr(const char *s, int c) +{ + char sc, ch = c; + + for (; (sc = *s++) != ch; ) { + if (!sc) + return NULL; + } + return (char *)s - 1; +} + #ifndef CONFIG_COLDFIRE #define __HAVE_ARCH_STRCMP static inline int strcmp(const char *cs, const char *ct) --- a/arch/m68k/include/asm/swab.h +++ b/arch/m68k/include/asm/swab.h @@ -1,11 +1,18 @@ +/* + * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ #ifndef _M68K_SWAB_H #define _M68K_SWAB_H - #include #include #define __SWAB_64_THRU_32__ +#if defined(__GNUC__) #if defined (__mcfisaaplus__) || defined (__mcfisac__) static inline __attribute_const__ __u32 __arch_swab32(__u32 val) { @@ -23,5 +30,11 @@ static inline __attribute_const__ __u32 } #define __arch_swab32 __arch_swab32 #endif +#endif + +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) || defined(__KERNEL__) +# define __BYTEORDER_HAS_U64__ +# define __SWAB_64_THRU_32__ +#endif #endif /* _M68K_SWAB_H */ --- a/arch/m68k/include/asm/system_mm.h +++ b/arch/m68k/include/asm/system_mm.h @@ -1,14 +1,35 @@ +/* + * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ #ifndef _M68K_SYSTEM_H #define _M68K_SYSTEM_H - #include #include #include #include #include +#include #ifdef __KERNEL__ +#ifdef CONFIG_COLDFIRE +#define FLUSH_BC (0x00040000) + +#define finish_arch_switch(prev) do { \ + unsigned long tmpreg; \ + asm volatile ("move.l %2,%0\n" \ + "orl %1,%0\n" \ + "movec %0,%%cacr" \ + : "=&d" (tmpreg) \ + : "id" (FLUSH_BC), "m" (shadow_cacr)); \ + } while (0) + +#endif + /* * switch_to(n) should switch tasks to task ptr, first checking that * ptr isn't the current task, in which case it does nothing. This --- a/arch/m68k/include/asm/tlbflush.h +++ b/arch/m68k/include/asm/tlbflush.h @@ -1,8 +1,14 @@ +/* + * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ #ifndef _M68K_TLBFLUSH_H #define _M68K_TLBFLUSH_H - #ifdef CONFIG_MMU -#ifndef CONFIG_SUN3 +#if !defined(CONFIG_SUN3) && !defined(CONFIG_COLDFIRE) #include @@ -92,7 +98,12 @@ static inline void flush_tlb_kernel_rang flush_tlb_all(); } -#else +static inline void flush_tlb_pgtables(struct mm_struct *mm, + unsigned long start, unsigned long end) +{ +} + +#elif defined(CONFIG_SUN3) /* Reserved PMEGs. */ @@ -214,6 +225,13 @@ static inline void flush_tlb_kernel_page sun3_put_segmap (addr & ~(SUN3_PMEG_SIZE - 1), SUN3_INVALID_PMEG); } +static inline void flush_tlb_pgtables(struct mm_struct *mm, + unsigned long start, unsigned long end) +{ +} + +#else /* CONFIG_COLDFIRE */ +#include #endif #else /* !CONFIG_MMU */ --- a/arch/m68k/include/asm/uaccess_mm.h +++ b/arch/m68k/include/asm/uaccess_mm.h @@ -1,6 +1,15 @@ +/* + * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ #ifndef __M68K_UACCESS_H #define __M68K_UACCESS_H - +#ifdef CONFIG_COLDFIRE +#include +#else /* * User space memory access functions */ @@ -219,6 +228,41 @@ unsigned long __generic_copy_to_user(voi : "+d" (res), "+&a" (to), "+a" (from), "=&d" (tmp) \ : : "memory") +#define __constant_copy_to_user_asm(res, to, from, tmp, n, s1, s2, s3) \ + asm volatile ("\n" \ + " move."#s1" (%2)+,%3\n" \ + "11: moves."#s1" %3,(%1)+\n" \ + "12: move."#s2" (%2)+,%3\n" \ + "21: moves."#s2" %3,(%1)+\n" \ + "22:\n" \ + " .ifnc \""#s3"\",\"\"\n" \ + " move."#s3" (%2)+,%3\n" \ + "31: moves."#s3" %3,(%1)+\n" \ + "32:\n" \ + " .endif\n" \ + "4:\n" \ + "\n" \ + " .section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 11b,5f\n" \ + " .long 12b,5f\n" \ + " .long 21b,5f\n" \ + " .long 22b,5f\n" \ + " .ifnc \""#s3"\",\"\"\n" \ + " .long 31b,5f\n" \ + " .long 32b,5f\n" \ + " .endif\n" \ + " .previous\n" \ + "\n" \ + " .section .fixup,\"ax\"\n" \ + " .even\n" \ + "5: moveq.l #"#n",%0\n" \ + " jra 4b\n" \ + " .previous\n" \ + : "+d" (res), "+a" (to), "+a" (from), "=&d" (tmp) \ + : : "memory") + +#endif /* CONFIG_COLDFIRE */ static __always_inline unsigned long __constant_copy_from_user(void *to, const void __user *from, unsigned long n) { @@ -266,40 +310,6 @@ __constant_copy_from_user(void *to, cons return res; } -#define __constant_copy_to_user_asm(res, to, from, tmp, n, s1, s2, s3) \ - asm volatile ("\n" \ - " move."#s1" (%2)+,%3\n" \ - "11: moves."#s1" %3,(%1)+\n" \ - "12: move."#s2" (%2)+,%3\n" \ - "21: moves."#s2" %3,(%1)+\n" \ - "22:\n" \ - " .ifnc \""#s3"\",\"\"\n" \ - " move."#s3" (%2)+,%3\n" \ - "31: moves."#s3" %3,(%1)+\n" \ - "32:\n" \ - " .endif\n" \ - "4:\n" \ - "\n" \ - " .section __ex_table,\"a\"\n" \ - " .align 4\n" \ - " .long 11b,5f\n" \ - " .long 12b,5f\n" \ - " .long 21b,5f\n" \ - " .long 22b,5f\n" \ - " .ifnc \""#s3"\",\"\"\n" \ - " .long 31b,5f\n" \ - " .long 32b,5f\n" \ - " .endif\n" \ - " .previous\n" \ - "\n" \ - " .section .fixup,\"ax\"\n" \ - " .even\n" \ - "5: moveq.l #"#n",%0\n" \ - " jra 4b\n" \ - " .previous\n" \ - : "+d" (res), "+a" (to), "+a" (from), "=&d" (tmp) \ - : : "memory") - static __always_inline unsigned long __constant_copy_to_user(void __user *to, const void *from, unsigned long n) { --- a/arch/m68k/include/asm/unistd.h +++ b/arch/m68k/include/asm/unistd.h @@ -1,6 +1,12 @@ +/* + * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ #ifndef _ASM_M68K_UNISTD_H_ #define _ASM_M68K_UNISTD_H_ - /* * This file contains the system call numbers. */ @@ -343,10 +349,11 @@ #define __NR_fanotify_init 337 #define __NR_fanotify_mark 338 #define __NR_prlimit64 339 +#define __NR_recvmmsg 340 #ifdef __KERNEL__ -#define NR_syscalls 340 +#define NR_syscalls 341 #define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_OLD_READDIR --- a/arch/m68k/include/asm/virtconvert.h +++ b/arch/m68k/include/asm/virtconvert.h @@ -1,5 +1,15 @@ +/* + * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ #ifndef __VIRT_CONVERT__ #define __VIRT_CONVERT__ +#ifdef CONFIG_COLDFIRE +#include +#else /* * Macros used for converting between virtual and physical mappings. @@ -45,3 +55,4 @@ static inline void *phys_to_virt(unsigne #endif #endif +#endif --- a/arch/m68k/kernel/Makefile +++ b/arch/m68k/kernel/Makefile @@ -2,16 +2,27 @@ # Makefile for the linux kernel. # -ifndef CONFIG_SUN3 - extra-y := head.o +ifdef CONFIG_SUN3 + extra-y := sun3-head.o vmlinux.lds + obj-y := entry.o signal.o ints.o time.o else - extra-y := sun3-head.o +ifndef CONFIG_COLDFIRE + extra-y := head.o vmlinux.lds + obj-y := entry.o signal.o traps.o ints.o time.o +else # CONFIG_COLDFIRE + extra-y := vmlinux.lds + obj-y := time.o + ifdef CONFIG_M547X_8X + obj-$(CONFIG_PCI) += bios32_mcf548x.o + endif +endif endif -extra-y += vmlinux.lds -obj-y := entry.o process.o traps.o ints.o signal.o ptrace.o module.o \ - sys_m68k.o time.o setup.o m68k_ksyms.o devres.o +obj-y += process.o ptrace.o module.o \ + sys_m68k.o setup.o m68k_ksyms.o devres.o# semaphore.o devres-y = ../../../kernel/irq/devres.o obj-y$(CONFIG_MMU_SUN3) += dma.o # no, it's not a typo + +EXTRA_AFLAGS := -traditional --- a/arch/m68k/kernel/asm-offsets.c +++ b/arch/m68k/kernel/asm-offsets.c @@ -2,6 +2,15 @@ * This program is used to generate definitions needed by * assembly language modules. * + * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Jason Jin Jason.Jin@freescale.com + * Shrek Wu B16972@freescale.com + * Add Codlfire 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. + * * We use the technique used in the OSF Mach kernel code: * generate asm statements containing #defines, * compile this file to assembler, and then extract the @@ -22,6 +31,9 @@ int main(void) { /* offsets into the task struct */ + DEFINE(TASK_STATE, offsetof(struct task_struct, state)); + DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags)); + DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace)); DEFINE(TASK_THREAD, offsetof(struct task_struct, thread)); DEFINE(TASK_INFO, offsetof(struct task_struct, thread.info)); DEFINE(TASK_MM, offsetof(struct task_struct, mm)); @@ -43,6 +55,7 @@ int main(void) /* offsets into the thread_info struct */ DEFINE(TINFO_PREEMPT, offsetof(struct thread_info, preempt_count)); DEFINE(TINFO_FLAGS, offsetof(struct thread_info, flags)); + DEFINE(TINFO_TP_VALUE, offsetof(struct thread_info, tp_value)); /* offsets into the pt_regs */ DEFINE(PT_OFF_D0, offsetof(struct pt_regs, d0)); @@ -57,8 +70,23 @@ int main(void) DEFINE(PT_OFF_A2, offsetof(struct pt_regs, a2)); DEFINE(PT_OFF_PC, offsetof(struct pt_regs, pc)); DEFINE(PT_OFF_SR, offsetof(struct pt_regs, sr)); +#ifdef CONFIG_COLDFIRE + /* Need to get the context out of struct mm for ASID setting */ + DEFINE(MM_CONTEXT, offsetof(struct mm_struct, context)); + /* Coldfire exception frame has vector *before* pc */ + DEFINE(PT_VECTOR, offsetof(struct pt_regs, pc) - 4); +#else /* bitfields are a bit difficult */ DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, pc) + 4); +#endif + + /* offsets into the irq_handler struct */ + DEFINE(IRQ_HANDLER, offsetof(struct irq_node, handler)); + DEFINE(IRQ_DEVID, offsetof(struct irq_node, dev_id)); + DEFINE(IRQ_NEXT, offsetof(struct irq_node, next)); + + /* offsets into the kernel_stat struct */ + DEFINE(STAT_IRQ, offsetof(struct kernel_stat, irqs)); /* offsets into the irq_cpustat_t struct */ DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending)); --- a/arch/m68k/kernel/dma.c +++ b/arch/m68k/kernel/dma.c @@ -1,4 +1,7 @@ /* + * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Jason Jin Jason.Jin@freescale.com + * Shrek Wu B16972@freescale.com * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive * for more details. @@ -12,12 +15,25 @@ #include #include #include - +#include #include void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t flag) { +#if defined(CONFIG_M5445X) || defined(CONFIG_M547X_8X) || \ + defined(CONFIG_M5441X) + /* + * On the M5445x platform the memory allocated with GFP_DMA + * is guaranteed to be DMA'able. + */ + void *addr; + + size = PAGE_ALIGN(size); + addr = kmalloc(size, GFP_DMA); + *handle = virt_to_phys(addr); + return addr; +#else struct page *page, **map; pgprot_t pgprot; void *addr; @@ -56,6 +72,7 @@ void *dma_alloc_coherent(struct device * kfree(map); return addr; +#endif } EXPORT_SYMBOL(dma_alloc_coherent); @@ -63,7 +80,12 @@ void dma_free_coherent(struct device *de void *addr, dma_addr_t handle) { pr_debug("dma_free_coherent: %p, %x\n", addr, handle); +#if defined(CONFIG_M5445X) || defined(CONFIG_M547X_8X) || \ + defined(CONFIG_M5441X) + kfree((void *)handle); +#else vfree(addr); +#endif } EXPORT_SYMBOL(dma_free_coherent); @@ -77,6 +99,9 @@ void dma_sync_single_for_device(struct d case DMA_FROM_DEVICE: cache_clear(handle, size); break; + case PCI_DMA_BIDIRECTIONAL: + flush_dcache(); + break; default: if (printk_ratelimit()) printk("dma_sync_single_for_device: unsupported dir %u\n", dir); @@ -89,16 +114,23 @@ void dma_sync_sg_for_device(struct devic enum dma_data_direction dir) { int i; +#ifdef CONFIG_COLDFIRE + struct scatterlist *_sg; + for_each_sg(sg, _sg, nents, i) + dma_sync_single_for_device(dev, _sg->dma_address, + _sg->length, dir); +#else for (i = 0; i < nents; sg++, i++) dma_sync_single_for_device(dev, sg->dma_address, sg->length, dir); +#endif } EXPORT_SYMBOL(dma_sync_sg_for_device); dma_addr_t dma_map_single(struct device *dev, void *addr, size_t size, enum dma_data_direction dir) { - dma_addr_t handle = virt_to_bus(addr); + dma_addr_t handle = (dma_addr_t)virt_to_bus(addr); dma_sync_single_for_device(dev, handle, size, dir); return handle; @@ -120,10 +152,19 @@ int dma_map_sg(struct device *dev, struc enum dma_data_direction dir) { int i; - +#ifdef CONFIG_COLDFIRE + struct scatterlist *_sg; +#endif +#ifndef CONFIG_COLDFIRE for (i = 0; i < nents; sg++, i++) { sg->dma_address = sg_phys(sg); dma_sync_single_for_device(dev, sg->dma_address, sg->length, dir); +#else + for_each_sg(sg, _sg, nents, i) { + _sg->dma_address = sg_phys(_sg); + dma_sync_single_for_device(dev, _sg->dma_address, + _sg->length, dir); +#endif } return nents; } --- a/arch/m68k/kernel/process.c +++ b/arch/m68k/kernel/process.c @@ -4,6 +4,15 @@ * Copyright (C) 1995 Hamish Macdonald * * 68060 fixes by Jesper Skov + * + * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Kurt.Mahan@freescale.com + * Jason Jin Jason.Jin@freescale.com + * Shrek Wu B16972@freescale.com + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. */ /* @@ -185,12 +194,21 @@ EXPORT_SYMBOL(kernel_thread); void flush_thread(void) { unsigned long zero = 0; +#if !defined(CONFIG_COLDFIRE) set_fs(USER_DS); current->thread.fs = __USER_DS; if (!FPU_IS_EMU) asm volatile (".chip 68k/68881\n\t" "frestore %0@\n\t" ".chip 68k" : : "a" (&zero)); +#else + set_fs(USER_DS); + current->thread.fs = USER_DS; +#if defined(CONFIG_FPU) + if (!FPU_IS_EMU) + asm volatile ("frestore %0@\n\t" : : "a" (&zero)); +#endif +#endif } /* @@ -258,6 +276,7 @@ int copy_thread(unsigned long clone_flag * Must save the current SFC/DFC value, NOT the value when * the parent was last descheduled - RGH 10-08-96 */ +#if !defined(CONFIG_COLDFIRE) p->thread.fs = get_fs().seg; if (!FPU_IS_EMU) { @@ -269,9 +288,34 @@ int copy_thread(unsigned long clone_flag "fmoveml %/fpiar/%/fpcr/%/fpsr,%1" : : "m" (p->thread.fp[0]), "m" (p->thread.fpcntl[0]) : "memory"); +#else + p->thread.fs = get_fs(); + +#if defined(CONFIG_FPU) + if (!FPU_IS_EMU) { + /* Copy the current fpu state */ + asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) + : "memory"); + + if (p->thread.fpstate[0]) { + asm volatile ("fmovemd %/fp0-%/fp7,%0" + : : "m" (p->thread.fp[0]) + : "memory"); + asm volatile ("fmovel %/fpiar,%0" + : : "m" (p->thread.fpcntl[0]) + : "memory"); + asm volatile ("fmovel %/fpcr,%0" + : : "m" (p->thread.fpcntl[1]) + : "memory"); + asm volatile ("fmovel %/fpsr,%0" + : : "m" (p->thread.fpcntl[2]) + : "memory"); + } /* Restore the state in case the fpu was busy */ asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0])); } +#endif +#endif return 0; } @@ -280,7 +324,9 @@ int copy_thread(unsigned long clone_flag int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu) { +#if !defined(CONFIG_COLDFIRE) || defined(CONFIG_FPU) char fpustate[216]; +#endif if (FPU_IS_EMU) { int i; @@ -297,6 +343,7 @@ int dump_fpu (struct pt_regs *regs, stru } /* First dump the fpu context to avoid protocol violation. */ +#if !defined(CONFIG_COLDFIRE) asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory"); if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2]) return 0; @@ -307,6 +354,25 @@ int dump_fpu (struct pt_regs *regs, stru asm volatile ("fmovemx %/fp0-%/fp7,%0" :: "m" (fpu->fpregs[0]) : "memory"); +#elif defined(CONFIG_FPU) + asm volatile ("fsave %0" : : "m" (fpustate[0]) : "memory"); + if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2]) + return 0; + + asm volatile ("fmovel %/fpiar,%0" + : : "m" (fpu->fpcntl[0]) + : "memory"); + asm volatile ("fmovel %/fpcr,%0" + : : "m" (fpu->fpcntl[1]) + : "memory"); + asm volatile ("fmovel %/fpsr,%0" + : : "m" (fpu->fpcntl[2]) + : "memory"); + asm volatile ("fmovemd %/fp0-%/fp7,%0" + : : "m" (fpu->fpregs[0]) + : "memory"); +#endif + return 1; } EXPORT_SYMBOL(dump_fpu); --- a/arch/m68k/kernel/setup.c +++ b/arch/m68k/kernel/setup.c @@ -2,7 +2,14 @@ * linux/arch/m68k/kernel/setup.c * * Copyright (C) 1995 Hamish Macdonald - */ + * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Jason Jin Jason.Jin@freescale.com + * Shrek Wu B16972@freescale.com + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. +*/ /* * This file handles the architecture-dependent parts of system setup @@ -74,14 +81,26 @@ struct mem_info m68k_memory[NUM_MEMINFO] EXPORT_SYMBOL(m68k_memory); struct mem_info m68k_ramdisk; +EXPORT_SYMBOL(m68k_ramdisk); +#if !defined(CONFIG_COLDFIRE) static char m68k_command_line[CL_SIZE]; +#else +char m68k_command_line[CL_SIZE]; +unsigned long uboot_info_stk; +EXPORT_SYMBOL(uboot_info_stk); +#endif void (*mach_sched_init) (irq_handler_t handler) __initdata = NULL; /* machine dependent irq functions */ void (*mach_init_IRQ) (void) __initdata = NULL; void (*mach_get_model) (char *model); void (*mach_get_hardware_list) (struct seq_file *m); + +#ifdef CONFIG_COLDFIRE +void (*mach_tick)(void); +#endif + /* machine dependent timer functions */ unsigned long (*mach_gettimeoffset) (void); int (*mach_hwclk) (int, struct rtc_time*); @@ -137,13 +156,17 @@ extern void config_hp300(void); extern void config_q40(void); extern void config_sun3x(void); +#ifdef CONFIG_COLDFIRE +void coldfire_sort_memrec(void); +#endif + #define MASK_256K 0xfffc0000 extern void paging_init(void); static void __init m68k_parse_bootinfo(const struct bi_record *record) { - while (record->tag != BI_LAST) { + while ((record->tag != BI_LAST) && !(CONFIG_COLDFIRE)) { int unknown = 0; const unsigned long *data = record->data; @@ -203,6 +226,10 @@ static void __init m68k_parse_bootinfo(c record->size); } +#ifdef CONFIG_COLDFIRE + coldfire_sort_memrec(); +#endif + m68k_realnum_memory = m68k_num_memory; #ifdef CONFIG_SINGLE_MEMORY_CHUNK if (m68k_num_memory > 1) { @@ -215,7 +242,9 @@ static void __init m68k_parse_bootinfo(c void __init setup_arch(char **cmdline_p) { +#if !defined(CONFIG_SUN3) && !defined(CONFIG_COLDFIRE) int i; +#endif /* The bootinfo is located right after the kernel bss */ m68k_parse_bootinfo((const struct bi_record *)_end); @@ -230,9 +259,10 @@ void __init setup_arch(char **cmdline_p) * We should really do our own FPU check at startup. * [what do we do with buggy 68LC040s? if we have problems * with them, we should add a test to check_bugs() below] */ -#ifndef CONFIG_M68KFPU_EMU_ONLY +#if !defined(CONFIG_M68KFPU_EMU_ONLY) && defined(CONFIG_FPU) /* clear the fpu if we have one */ - if (m68k_fputype & (FPU_68881|FPU_68882|FPU_68040|FPU_68060)) { + if (m68k_fputype & (FPU_68881|FPU_68882|FPU_68040|FPU_68060| + FPU_CFV4E)) { volatile int zero = 0; asm volatile ("frestore %0" : : "m" (zero)); } @@ -320,16 +350,17 @@ void __init setup_arch(char **cmdline_p) config_sun3x(); break; #endif +#ifdef CONFIG_COLDFIRE + case MACH_CFMMU: + config_coldfire(); + break; +#endif default: panic("No configuration setup"); } paging_init(); -#ifndef CONFIG_SUN3 - for (i = 1; i < m68k_num_memory; i++) - free_bootmem_node(NODE_DATA(i), m68k_memory[i].addr, - m68k_memory[i].size); #ifdef CONFIG_BLK_DEV_INITRD if (m68k_ramdisk.size) { reserve_bootmem_node(__virt_to_node(phys_to_virt(m68k_ramdisk.addr)), @@ -341,6 +372,10 @@ void __init setup_arch(char **cmdline_p) } #endif +#if !defined(CONFIG_SUN3) && !defined(CONFIG_COLDFIRE) + for (i = 1; i < m68k_num_memory; i++) + free_bootmem_node(NODE_DATA(i), m68k_memory[i].addr, + m68k_memory[i].size); #ifdef CONFIG_ATARI if (MACH_IS_ATARI) atari_stram_reserve_pages((void *)availmem); @@ -353,12 +388,22 @@ void __init setup_arch(char **cmdline_p) #endif /* !CONFIG_SUN3 */ +#ifdef CONFIG_COLDFIRE + mmu_context_init(); +#endif + /* set ISA defs early as possible */ #if defined(CONFIG_ISA) && defined(MULTI_ISA) if (MACH_IS_Q40) { isa_type = ISA_TYPE_Q40; isa_sex = 0; } +#ifdef CONFIG_GG2 + if (MACH_IS_AMIGA && AMIGAHW_PRESENT(GG2_ISA)) { + isa_type = ISA_TYPE_GG2; + isa_sex = 0; + } +#endif #ifdef CONFIG_AMIGA_PCMCIA if (MACH_IS_AMIGA && AMIGAHW_PRESENT(PCMCIA)) { isa_type = ISA_TYPE_AG; @@ -377,6 +422,7 @@ static int show_cpuinfo(struct seq_file #define LOOP_CYCLES_68030 (8) #define LOOP_CYCLES_68040 (3) #define LOOP_CYCLES_68060 (1) +#define LOOP_CYCLES_COLDFIRE (2) if (CPU_IS_020) { cpu = "68020"; @@ -390,6 +436,9 @@ static int show_cpuinfo(struct seq_file } else if (CPU_IS_060) { cpu = "68060"; clockfactor = LOOP_CYCLES_68060; + } else if (CPU_IS_CFV4E) { + cpu = "ColdFire V4e"; + clockfactor = LOOP_CYCLES_COLDFIRE; } else { cpu = "680x0"; clockfactor = 0; @@ -408,6 +457,8 @@ static int show_cpuinfo(struct seq_file fpu = "68060"; else if (m68k_fputype & FPU_SUNFPA) fpu = "Sun FPA"; + else if (m68k_fputype & FPU_CFV4E) + fpu = "ColdFire V4e"; else fpu = "none"; #endif @@ -424,6 +475,8 @@ static int show_cpuinfo(struct seq_file mmu = "Sun-3"; else if (m68k_mmutype & MMU_APOLLO) mmu = "Apollo"; + else if (m68k_mmutype & MMU_CFV4E) + mmu = "ColdFire"; else mmu = "unknown"; @@ -506,7 +559,8 @@ module_init(proc_hardware_init); void check_bugs(void) { -#ifndef CONFIG_M68KFPU_EMU +#if !defined(CONFIG_M68KFPU_EMU) && !defined(CONFIG_M5445X) && \ + !defined(CONFIG_M5441X) if (m68k_fputype == 0) { printk(KERN_EMERG "*** YOU DO NOT HAVE A FLOATING POINT UNIT, " "WHICH IS REQUIRED BY LINUX/M68K ***\n"); --- a/arch/m68k/kernel/sys_m68k.c +++ b/arch/m68k/kernel/sys_m68k.c @@ -1,5 +1,12 @@ /* * linux/arch/m68k/kernel/sys_m68k.c + * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Jason Jin Jason.Jin@freescale.com + * Shrek Wu B16972@freescale.com + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. * * This file contains various random system calls that * have a non-standard calling sequence on the Linux/m68k @@ -29,6 +36,9 @@ #include #include #include +#ifdef CONFIG_COLDFIRE +#include +#endif asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address, unsigned long error_code); @@ -45,6 +55,59 @@ asmlinkage long sys_mmap2(unsigned long return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff); } +/* + * Perform the select(nd, in, out, ex, tv) and mmap() system + * calls. Linux/m68k cloned Linux/i386, which didn't use to be able to + * handle more than 4 system call parameters, so these system calls + * used a memory block for parameter passing.. + */ + +struct mmap_arg_struct { + unsigned long addr; + unsigned long len; + unsigned long prot; + unsigned long flags; + unsigned long fd; + unsigned long offset; +}; + +asmlinkage int old_mmap(struct mmap_arg_struct __user *arg) +{ + struct mmap_arg_struct a; + int error = -EFAULT; + + if (copy_from_user(&a, arg, sizeof(a))) + goto out; + + error = -EINVAL; + if (a.offset & ~PAGE_MASK) + goto out; + + a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + + error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, + a.fd, a.offset >> PAGE_SHIFT); +out: + return error; +} + +struct sel_arg_struct { + unsigned long n; + fd_set __user *inp, *outp, *exp; + struct timeval __user *tvp; +}; + +asmlinkage int old_select(struct sel_arg_struct __user *arg) +{ + struct sel_arg_struct a; + + if (copy_from_user(&a, arg, sizeof(a))) + return -EFAULT; + /* sys_select() does the appropriate kernel locking */ + return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); +} + +#ifndef CONFIG_COLDFIRE /* Convert virtual (user) address VADDR to physical address PADDR */ #define virt_to_phys_040(vaddr) \ ({ \ @@ -368,6 +431,7 @@ cache_flush_060 (unsigned long addr, int } return 0; } +#endif /* CONFIG_COLDFIRE */ /* sys_cacheflush -- flush (part of) the processor cache. */ asmlinkage int @@ -399,6 +463,7 @@ sys_cacheflush (unsigned long addr, int goto out; } +#ifndef CONFIG_COLDFIRE if (CPU_IS_020_OR_030) { if (scope == FLUSH_SCOPE_LINE && len < 256) { unsigned long cacr; @@ -443,6 +508,16 @@ sys_cacheflush (unsigned long addr, int ret = cache_flush_060 (addr, scope, cache, len); } } +#else /* CONFIG_COLDFIRE */ + if ((cache & FLUSH_CACHE_INSN) && (cache & FLUSH_CACHE_DATA)) + flush_bcache(); + else if (cache & FLUSH_CACHE_INSN) + flush_icache(); + else + flush_dcache(); + + ret = 0; +#endif /* CONFIG_COLDFIRE */ out: return ret; } @@ -474,9 +549,14 @@ asmlinkage unsigned long sys_get_thread_ return current_thread_info()->tp_value; } +extern void *_vdso_tp; + asmlinkage int sys_set_thread_area(unsigned long tp) { current_thread_info()->tp_value = tp; +#ifdef CONFIG_VDSO + *(unsigned long *)_vdso_tp = tp; +#endif return 0; } --- a/arch/m68k/kernel/time.c +++ b/arch/m68k/kernel/time.c @@ -2,6 +2,14 @@ * linux/arch/m68k/kernel/time.c * * Copyright (C) 1991, 1992, 1995 Linus Torvalds + * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Jason Jin Jason.Jin@freescale.com + * Shrek Wu B16972@freescale.com + * Alison Wang b18965@freescale.com + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. * * This file contains the m68k-specific time handling details. * Most of the stuff is located in the machine specific files. @@ -9,9 +17,12 @@ * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 * "A Kernel Model for Precision Timekeeping" by Dave Mills */ - +#include +#include +#include #include #include +#include #include #include #include @@ -27,6 +38,7 @@ #include #include #include +#include static inline int set_rtc_mmss(unsigned long nowtime) { @@ -35,12 +47,18 @@ static inline int set_rtc_mmss(unsigned return -1; } +#ifndef CONFIG_GENERIC_CLOCKEVENTS /* * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick */ static irqreturn_t timer_interrupt(int irq, void *dummy) { +#ifdef CONFIG_COLDFIRE + /* kick hardware timer if necessary */ + if (mach_tick) + mach_tick(); +#endif do_timer(1); update_process_times(user_mode(get_irq_regs())); profile_tick(CPU_PROFILING); @@ -91,11 +109,133 @@ void __init time_init(void) { mach_sched_init(timer_interrupt); } +#endif +#ifdef CONFIG_ARCH_USES_GETTIMEOFFSET u32 arch_gettimeoffset(void) { return mach_gettimeoffset() * 1000; } +#endif + +#ifdef CONFIG_GENERIC_CLOCKEVENTS + +extern unsigned long long sys_dtim2_read(void); +extern void sys_dtim2_init(void); +static int cfv4_set_next_event(unsigned long evt, + struct clock_event_device *dev); +static void cfv4_set_mode(enum clock_event_mode mode, + struct clock_event_device *dev); + +#if defined(CONFIG_M5445X) || defined(CONFIG_M5441X) +#define FREQ (MCF_BUSCLK / 16) +#else +#define FREQ (MCF_BUSCLK) +#endif + +/* + * Clock Evnt setup + */ +static struct clock_event_device clockevent_cfv4 = { + .name = "CFV4 timer2even", + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .rating = 200, + .shift = 20, + .set_mode = cfv4_set_mode, + .set_next_event = cfv4_set_next_event, +}; + +static int cfv4_set_next_event(unsigned long evt, + struct clock_event_device *dev) +{ + return 0; +} + +static void cfv4_set_mode(enum clock_event_mode mode, + struct clock_event_device *dev) +{ + if (mode != CLOCK_EVT_MODE_ONESHOT) + cfv4_set_next_event((FREQ / HZ), dev); +} + +static int __init cfv4_clockevent_init(void) +{ + clockevent_cfv4.mult = + div_sc(FREQ, NSEC_PER_SEC, + clockevent_cfv4.shift); + clockevent_cfv4.max_delta_ns = + clockevent_delta2ns((FREQ / HZ), + &clockevent_cfv4); + clockevent_cfv4.min_delta_ns = + clockevent_delta2ns(1, &clockevent_cfv4); + + clockevent_cfv4.cpumask = &cpumask_of_cpu(0); + + printk(KERN_INFO "timer: register clockevent\n"); + clockevents_register_device(&clockevent_cfv4); + + return 0; +} + +/* + * clocksource setup + */ + +struct clocksource clocksource_cfv4 = { + .name = "ColdfireV4", + .rating = 250, + .mask = CLOCKSOURCE_MASK(32), + .read = sys_dtim2_read, + .shift = 20, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +/* + * Initialize time subsystem. Called from linux/init/main.c + */ +void __init time_init(void) +{ + int ret; + + printk(KERN_INFO "Initializing time\n"); + + cfv4_clockevent_init(); + /* initialize the system timer */ + sys_dtim2_init(); + + /* JKM */ + clocksource_cfv4.mult = clocksource_hz2mult(FREQ, + clocksource_cfv4.shift); + + /* register our clocksource */ + ret = clocksource_register(&clocksource_cfv4); + if (ret) + printk(KERN_ERR "timer: unable to " + "register clocksource - %d\n", ret); +} + +/* + * sysfs pieces + */ + +static struct sysdev_class timer_class = { + .name = "timer", +}; + +static struct sys_device timer_device = { + .id = 0, + .cls = &timer_class, +}; + +static int __init timer_init_sysfs(void) +{ + int err = sysdev_class_register(&timer_class); + if (!err) + err = sysdev_register(&timer_device); + return err; +} +device_initcall(timer_init_sysfs); +#endif /* CONFIG_GENERIC_CLOCKEVENTS */ static int __init rtc_init(void) { --- /dev/null +++ b/arch/m68k/kernel/vmlinux-cf.lds @@ -0,0 +1,142 @@ +/* ld script to make m68k Coldfire Linux kernel + * + * Derived from arch/m68k/kernel/vmlinux-std.lds + * + * Updated 11/26/2007 for new CodeSourcery toolset + * by Kurt Mahan + * + * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Jason Jin Jason.Jin@freescale.com + * Shrek Wu B16972@freescale.com + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#define LOAD_OFFSET 0x00000000 + +#include +#include + +#define START_OFFSET 0x00020000 +#define IMAGE_START PAGE_OFFSET_RAW + START_OFFSET + +OUTPUT_FORMAT("elf32-m68k", "elf32-m68k", "elf32-m68k") +OUTPUT_ARCH(m68k) +ENTRY(_stext) +jiffies = jiffies_64 + 4; + +SECTIONS +{ + . = IMAGE_START; + .text.head : AT(ADDR(.text.head) - LOAD_OFFSET) { + _text = .; /* Text and read-only data */ + *(.text.head) + } :text = 0x4e75 + + .text : AT(ADDR(.text) - LOAD_OFFSET) { + TEXT_TEXT + SCHED_TEXT + LOCK_TEXT + *(.fixup) + *(.gnu.warning) + } :text = 0x4e75 + _etext = .; /* End of text section */ + + . = ALIGN(16); + __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { + __start___ex_table = .; + *(__ex_table) + __stop___ex_table = .; + } + + RODATA + + . = ALIGN(8192); + .data : AT(ADDR(.data) - LOAD_OFFSET) { /* Data */ + DATA_DATA + CONSTRUCTORS + } :data + + + . = ALIGN(16); + .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET ) { + *(.data.cacheline_aligned) + } :data + + _edata = .; /* End of data section */ + + NOTES /* support ld --build-id */ + + . = ALIGN(8192); /* Initrd */ + .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) { + __init_begin = .; + _sinittext = .; + *(.init.text) + _einittext = .; + } + + .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { + *(.init.data) + } + + . = ALIGN(16); + .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) { + __setup_start = .; + *(.init.setup) + __setup_end = .; + } + + .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) { + __initcall_start = .; + INITCALLS + __initcall_end = .; + } + + .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) { + __con_initcall_start = .; + *(.con_initcall.init) + __con_initcall_end = .; + } + + SECURITY_INIT + +#ifdef CONFIG_BLK_DEV_INITRD + . = ALIGN(8192); + .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { + __initramfs_start = .; + *(.init.ramfs) + __initramfs_end = .; + } +#endif + + . = ALIGN(8192); + __init_end = .; + + .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) { + *(.data.init_task) /* The initial task and kernel stack */ + } + + _sbss = .; + .bss : AT(ADDR(.bss) - LOAD_OFFSET) { /* BSS */ + *(.bss) + } + _ebss = .; + + _end = . ; + + __ctors_start = . ; + + __ctors_end = . ; + + /* Sections to be discarded */ + /DISCARD/ : { + *(.exit.text) + *(.exit.data) + *(.exitcall.exit) + } + + /* Stabs debugging sections. */ + STABS_DEBUG +} --- a/arch/m68k/kernel/vmlinux.lds.S +++ b/arch/m68k/kernel/vmlinux.lds.S @@ -1,10 +1,20 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ PHDRS { - text PT_LOAD FILEHDR PHDRS FLAGS (7); + headers PT_PHDR PHDRS ; + text PT_LOAD FILEHDR PHDRS FLAGS (5); data PT_LOAD FLAGS (7); } #ifdef CONFIG_SUN3 #include "vmlinux-sun3.lds" +#elif CONFIG_COLDFIRE +#include "vmlinux-cf.lds" #else #include "vmlinux-std.lds" #endif --- a/arch/m68k/lib/checksum.c +++ b/arch/m68k/lib/checksum.c @@ -30,6 +30,10 @@ * 1998/8/31 Andreas Schwab: * Zero out rest of buffer on exception in * csum_partial_copy_from_user. + * + * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Jason Jin Jason.Jin@freescale.com + * Shrek Wu B16972@freescale.com */ #include @@ -39,8 +43,132 @@ * computes a partial checksum, e.g. for TCP/UDP fragments */ +#ifdef CONFIG_COLDFIRE + +static inline unsigned short from32to16(unsigned long x) +{ + /* add up 16-bit and 16-bit for 16+c bit */ + x = (x & 0xffff) + (x >> 16); + /* add up carry.. */ + x = (x & 0xffff) + (x >> 16); + return x; +} + +static unsigned long do_csum(const unsigned char *buff, int len) +{ + int odd, count; + unsigned long result = 0; + + if (len <= 0) + goto out; + odd = 1 & (unsigned long) buff; + if (odd) { + result = *buff; + len--; + buff++; + } + count = len >> 1; /* nr of 16-bit words.. */ + if (count) { + if (2 & (unsigned long) buff) { + result += *(unsigned short *) buff; + count--; + len -= 2; + buff += 2; + } + count >>= 1; /* nr of 32-bit words.. */ + if (count) { + unsigned long carry = 0; + do { + unsigned long w = *(unsigned long *) buff; + count--; + buff += 4; + result += carry; + result += w; + carry = (w > result); + } while (count); + result += carry; + result = (result & 0xffff) + (result >> 16); + } + if (len & 2) { + result += *(unsigned short *) buff; + buff += 2; + } + } + if (len & 1) + result += (*buff << 8); + result = from32to16(result); + if (odd) + result = ((result >> 8) & 0xff) | ((result & 0xff) << 8); +out: + return result; +} + +/* + * This is a version of ip_compute_csum() optimized for IP headers, + * which always checksum on 4 octet boundaries. + */ +__sum16 ip_fast_csum(const void *iph, unsigned int ihl) +{ + return ~do_csum(iph, ihl*4); +} +EXPORT_SYMBOL(ip_fast_csum); + +/* + * 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 + */ __wsum csum_partial(const void *buff, int len, __wsum sum) { + unsigned int result = do_csum(buff, len); + + /* add in old sum, and carry.. */ + result += sum; + if (sum > result) + result += 1; + return result; +} +EXPORT_SYMBOL(csum_partial); + +/* + * copy from fs while checksumming, otherwise like csum_partial + */ + +__wsum +csum_partial_copy_from_user(const void __user *src, void *dst, int len, + __wsum sum, int *csum_err) +{ + if (csum_err) + *csum_err = 0; + memcpy(dst, src, len); + return csum_partial(dst, len, sum); +} +EXPORT_SYMBOL(csum_partial_copy_from_user); + +/* + * copy from ds while checksumming, otherwise like csum_partial + */ + +__wsum +csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum) +{ + memcpy(dst, src, len); + return csum_partial(dst, len, sum); +} +EXPORT_SYMBOL(csum_partial_copy_nocheck); + +#else /* !CONFIG_COLDFIRE */ + +unsigned int +csum_partial(const unsigned char *buff, int len, unsigned int sum) +{ unsigned long tmp1, tmp2; /* * Experiments with ethernet and slip connections show that buff @@ -423,3 +551,4 @@ csum_partial_copy_nocheck(const void *sr return(sum); } EXPORT_SYMBOL(csum_partial_copy_nocheck); +#endif /* CONFIG_COLDFIRE */ --- a/arch/m68k/lib/muldi3.c +++ b/arch/m68k/lib/muldi3.c @@ -1,6 +1,9 @@ /* muldi3.c extracted from gcc-2.7.2.3/libgcc2.c and gcc-2.7.2.3/longlong.h which is: */ /* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved. + Jason Jin Jason.Jin@freescale.com + Shrek Wu B16972@freescale.com This file is part of GNU CC. @@ -21,12 +24,22 @@ Boston, MA 02111-1307, USA. */ #define BITS_PER_UNIT 8 +#ifdef CONFIG_COLDFIRE +#define umul_ppmm(w1, w0, u, v) \ + do { \ + unsigned long long x; \ + x = (unsigned long long)u * v; \ + w0 = (unsigned long)(x & 0x00000000ffffffff); \ + w1 = (unsigned long)(x & 0xffffffff00000000) >> 32; \ + } while (0) +#else /* CONFIG_COLDFIRE */ #define umul_ppmm(w1, w0, u, v) \ __asm__ ("mulu%.l %3,%1:%0" \ : "=d" ((USItype)(w0)), \ "=d" ((USItype)(w1)) \ : "%0" ((USItype)(u)), \ "dmi" ((USItype)(v))) +#endif /* CONFIG_COLDFIRE */ #define __umulsidi3(u, v) \ ({DIunion __w; \ --- a/arch/m68k/lib/string.c +++ b/arch/m68k/lib/string.c @@ -1,4 +1,8 @@ /* + * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * * Jason Jin Jason.Jin@freescale.com + * Shrek Wu B16972@freescale.com + * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive * for more details. @@ -21,6 +25,7 @@ char *strcat(char *dest, const char *src } EXPORT_SYMBOL(strcat); +#ifndef CONFIG_COLDFIRE void *memset(void *s, int c, size_t count) { void *xs = s; @@ -149,6 +154,69 @@ void *memcpy(void *to, const void *from, } EXPORT_SYMBOL(memcpy); +#else /* CONFIG_COLDFIRE */ + +void *memset(void *s, int c, size_t count) +{ + unsigned long x; + void *originalTo = s; + + for (x = 0; x < count; x++) + *(unsigned char *)s++ = (unsigned char)c; + + return originalTo; +} +EXPORT_SYMBOL(memset); + +void *memcpy(void *to, const void *from, size_t n) +{ + void *xto = to; + size_t temp; + + if (!n) + return xto; + if ((long) to & 1) { + char *cto = to; + const char *cfrom = from; + *cto++ = *cfrom++; + to = cto; + from = cfrom; + n--; + } + if (n > 2 && (long) to & 2) { + short *sto = to; + const short *sfrom = from; + *sto++ = *sfrom++; + to = sto; + from = sfrom; + n -= 2; + } + temp = n >> 2; + if (temp) { + long *lto = to; + const long *lfrom = from; + for (; temp; temp--) + *lto++ = *lfrom++; + to = lto; + from = lfrom; + } + if (n & 2) { + short *sto = to; + const short *sfrom = from; + *sto++ = *sfrom++; + to = sto; + from = sfrom; + } + if (n & 1) { + char *cto = to; + const char *cfrom = from; + *cto = *cfrom; + } + return xto; +} +EXPORT_SYMBOL(memcpy); +#endif /* CONFIG_COLDFIRE */ + void *memmove(void *dest, const void *src, size_t n) { void *xdest = dest; --- a/arch/m68k/lib/uaccess.c +++ b/arch/m68k/lib/uaccess.c @@ -1,10 +1,15 @@ /* + * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Jason Jin Jason.Jin@freescale.com + * Shrek Wu B16972@freescale.com + * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive * for more details. */ #include +#ifndef CONFIG_COLDFIRE #include unsigned long __generic_copy_from_user(void *to, const void __user *from, @@ -220,3 +225,245 @@ unsigned long __clear_user(void __user * return res; } EXPORT_SYMBOL(__clear_user); + +#else /* CONFIG_COLDFIRE */ + +#include + +unsigned long __generic_copy_from_user(void *to, const void *from, + unsigned long n) +{ + unsigned long tmp; + __asm__ __volatile__ + (" tstl %2\n" + " jeq 2f\n" + "1: movel (%1)+,%3\n" + " movel %3,(%0)+\n" + " subql #1,%2\n" + " jne 1b\n" + "2: movel %4,%2\n" + " bclr #1,%2\n" + " jeq 4f\n" + "3: movew (%1)+,%3\n" + " movew %3,(%0)+\n" + "4: bclr #0,%2\n" + " jeq 6f\n" + "5: moveb (%1)+,%3\n" + " moveb %3,(%0)+\n" + "6:\n" + ".section .fixup,\"ax\"\n" + " .even\n" + "7: movel %2,%%d0\n" + "71:clrl (%0)+\n" + " subql #1,%%d0\n" + " jne 71b\n" + " lsll #2,%2\n" + " addl %4,%2\n" + " btst #1,%4\n" + " jne 81f\n" + " btst #0,%4\n" + " jne 91f\n" + " jra 6b\n" + "8: addql #2,%2\n" + "81:clrw (%0)+\n" + " btst #0,%4\n" + " jne 91f\n" + " jra 6b\n" + "9: addql #1,%2\n" + "91:clrb (%0)+\n" + " jra 6b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b,7b\n" + " .long 3b,8b\n" + " .long 5b,9b\n" + ".previous" + : "=a"(to), "=a"(from), "=d"(n), "=&d"(tmp) + : "d"(n & 3), "0"(to), "1"(from), "2"(n/4) + : "d0", "memory"); + return n; +} +EXPORT_SYMBOL(__generic_copy_from_user); + + +unsigned long __generic_copy_to_user(void *to, const void *from, + unsigned long n) +{ + unsigned long tmp; + __asm__ __volatile__ + (" tstl %2\n" + " jeq 3f\n" + "1: movel (%1)+,%3\n" + "22:movel %3,(%0)+\n" + "2: subql #1,%2\n" + " jne 1b\n" + "3: movel %4,%2\n" + " bclr #1,%2\n" + " jeq 4f\n" + " movew (%1)+,%3\n" + "24:movew %3,(%0)+\n" + "4: bclr #0,%2\n" + " jeq 5f\n" + " moveb (%1)+,%3\n" + "25:moveb %3,(%0)+\n" + "5:\n" + ".section .fixup,\"ax\"\n" + " .even\n" + "60:addql #1,%2\n" + "6: lsll #2,%2\n" + " addl %4,%2\n" + " jra 5b\n" + "7: addql #2,%2\n" + " jra 5b\n" + "8: addql #1,%2\n" + " jra 5b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b,60b\n" + " .long 22b,6b\n" + " .long 2b,6b\n" + " .long 24b,7b\n" + " .long 3b,60b\n" + " .long 4b,7b\n" + " .long 25b,8b\n" + " .long 5b,8b\n" + ".previous" + : "=a"(to), "=a"(from), "=d"(n), "=&d"(tmp) + : "r"(n & 3), "0"(to), "1"(from), "2"(n / 4) + : "memory"); + return n; +} +EXPORT_SYMBOL(__generic_copy_to_user); + +/* + * Copy a null terminated string from userspace. + */ + +long strncpy_from_user(char *dst, const char *src, long count) +{ + long res = -EFAULT; + if (!(access_ok(VERIFY_READ, src, 1))) /* --tym-- */ + return res; + if (count == 0) + return count; + __asm__ __volatile__ + ("1: moveb (%2)+,%%d0\n" + "12:moveb %%d0,(%1)+\n" + " jeq 2f\n" + " subql #1,%3\n" + " jne 1b\n" + "2: subl %3,%0\n" + "3:\n" + ".section .fixup,\"ax\"\n" + " .even\n" + "4: movel %4,%0\n" + " jra 3b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b,4b\n" + " .long 12b,4b\n" + ".previous" + : "=d"(res), "=a"(dst), "=a"(src), "=d"(count) + : "i"(-EFAULT), "0"(count), "1"(dst), "2"(src), "3"(count) + : "d0", "memory"); + return res; +} +EXPORT_SYMBOL(strncpy_from_user); + +/* + * Return the size of a string (including the ending 0) + * + * Return 0 on exception, a value greater than N if too long + */ +long strnlen_user(const char *src, long n) +{ + long res = -EFAULT; + if (!(access_ok(VERIFY_READ, src, 1))) /* --tym-- */ + return res; + + res = -(long)src; + __asm__ __volatile__ + ("1:\n" + " tstl %2\n" + " jeq 3f\n" + "2: moveb (%1)+,%%d0\n" + "22:\n" + " subql #1,%2\n" + " tstb %%d0\n" + " jne 1b\n" + " jra 4f\n" + "3:\n" + " addql #1,%0\n" + "4:\n" + " addl %1,%0\n" + "5:\n" + ".section .fixup,\"ax\"\n" + " .even\n" + "6: moveq %3,%0\n" + " jra 5b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 2b,6b\n" + " .long 22b,6b\n" + ".previous" + : "=d"(res), "=a"(src), "=d"(n) + : "i"(0), "0"(res), "1"(src), "2"(n) + : "d0"); + return res; +} +EXPORT_SYMBOL(strnlen_user); + + +/* + * Zero Userspace + */ + +unsigned long __clear_user(void *to, unsigned long n) +{ + __asm__ __volatile__ + (" tstl %1\n" + " jeq 3f\n" + "1: movel %3,(%0)+\n" + "2: subql #1,%1\n" + " jne 1b\n" + "3: movel %2,%1\n" + " bclr #1,%1\n" + " jeq 4f\n" + "24:movew %3,(%0)+\n" + "4: bclr #0,%1\n" + " jeq 5f\n" + "25:moveb %3,(%0)+\n" + "5:\n" + ".section .fixup,\"ax\"\n" + " .even\n" + "61:addql #1,%1\n" + "6: lsll #2,%1\n" + " addl %2,%1\n" + " jra 5b\n" + "7: addql #2,%1\n" + " jra 5b\n" + "8: addql #1,%1\n" + " jra 5b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b,61b\n" + " .long 2b,6b\n" + " .long 3b,61b\n" + " .long 24b,7b\n" + " .long 4b,7b\n" + " .long 25b,8b\n" + " .long 5b,8b\n" + ".previous" + : "=a"(to), "=d"(n) + : "r"(n & 3), "d"(0), "0"(to), "1"(n/4)); + return n; +} +EXPORT_SYMBOL(__clear_user); + +#endif /* CONFIG_COLDFIRE */ + --- a/arch/m68k/mm/Makefile +++ b/arch/m68k/mm/Makefile @@ -6,3 +6,5 @@ obj-y := cache.o init.o fault.o hwtest. obj-$(CONFIG_MMU_MOTOROLA) += kmap.o memory.o motorola.o obj-$(CONFIG_MMU_SUN3) += sun3kmap.o sun3mmu.o +obj-$(CONFIG_MMU_CFV4E) += cf-mmu.o kmap.o memory.o +obj-$(CONFIG_SRAM) += cf-sram.o --- a/arch/m68k/mm/cache.c +++ b/arch/m68k/mm/cache.c @@ -4,13 +4,24 @@ * Instruction cache handling * * Copyright (C) 1995 Hamish Macdonald + * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Jason Jin Jason.Jin@freescale.com + * Shrek Wu B16972@freescale.com + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. */ #include #include #include +#ifdef CONFIG_COLDFIRE +#include +#endif /* CONFIG_COLDFIRE */ +#ifndef CONFIG_COLDFIRE static unsigned long virt_to_phys_slow(unsigned long vaddr) { if (CPU_IS_060) { @@ -69,11 +80,16 @@ static unsigned long virt_to_phys_slow(u } return 0; } +#endif /* CONFIG_COLDFIRE */ + /* Push n pages at kernel virtual address and clear the icache */ /* RZ: use cpush %bc instead of cpush %dc, cinv %ic */ void flush_icache_range(unsigned long address, unsigned long endaddr) { +#ifdef CONFIG_COLDFIRE + flush_icache(); +#else /* !CONFIG_COLDFIRE */ if (CPU_IS_040_OR_060) { address &= PAGE_MASK; @@ -94,9 +110,11 @@ void flush_icache_range(unsigned long ad : "=&d" (tmp) : "di" (FLUSH_I)); } +#endif /* CONFIG_COLDFIRE */ } EXPORT_SYMBOL(flush_icache_range); +#ifndef CONFIG_COLDFIRE void flush_icache_user_range(struct vm_area_struct *vma, struct page *page, unsigned long addr, int len) { @@ -115,4 +133,5 @@ void flush_icache_user_range(struct vm_a : "di" (FLUSH_I)); } } +#endif /* CONFIG_COLDFIRE */ --- /dev/null +++ b/arch/m68k/mm/cf-mmu.c @@ -0,0 +1,311 @@ +/* + * linux/arch/m68k/mm/cf-mmu.c + * + * Based upon linux/arch/m68k/mm/sun3mmu.c + * Based upon linux/arch/ppc/mm/mmu_context.c + * + * Implementations of mm routines specific to the Coldfire MMU. + * + * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Jason Jin Jason.Jin@freescale.com + * Shrek Wu B16972@freescale.com + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_BLK_DEV_RAM +#include +#endif +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define KMAPAREA(x) ((x >= VMALLOC_START) && (x < KMAP_END)) + +#undef DEBUG + +#ifdef CONFIG_VDSO +unsigned long next_mmu_context; +#else +mm_context_t next_mmu_context; +#endif + +unsigned long context_map[LAST_CONTEXT / BITS_PER_LONG + 1]; + +atomic_t nr_free_contexts; +struct mm_struct *context_mm[LAST_CONTEXT+1]; +const char bad_pmd_string[] = "Bad pmd in pte_alloc: %08lx\n"; + +extern unsigned long num_pages; +EXPORT_SYMBOL(num_pages); +/* + * Free memory used for system initialization. + */ +void free_initmem(void) +{ +#if 0 + unsigned long addr; + unsigned long start = (unsigned long)&__init_begin; + unsigned long end = (unsigned long)&__init_end; + + printk(KERN_INFO "free_initmem: __init_begin = 0x%lx" + " __init_end = 0x%lx\n", start, end); + + addr = (unsigned long)&__init_begin; + for (; addr < (unsigned long)&__init_end; addr += PAGE_SIZE) { + /* not currently used */ + virt_to_page(addr)->flags &= ~(1 << PG_reserved); + init_page_count(virt_to_page(addr)); + free_page(addr); + totalram_pages++; + } +#endif +} + +/* + * Initialize the paging system. + */ +void __init paging_init(void) +{ + pgd_t *pg_dir; + pte_t *pg_table; + int i; + unsigned long address; + unsigned long next_pgtable; + unsigned long zones_size[MAX_NR_ZONES]; + unsigned long size; + enum zone_type zone; + + /* allocate zero page */ + empty_zero_page = (void *)alloc_bootmem_pages(PAGE_SIZE); + memset((void *)empty_zero_page, 0, PAGE_SIZE); + + /* zero kernel page directory */ + pg_dir = swapper_pg_dir; + memset(swapper_pg_dir, 0, sizeof(swapper_pg_dir)); + /* + * setup page tables for PHYSRAM + */ + + /* starting loc in page directory */ + pg_dir += PAGE_OFFSET >> PGDIR_SHIFT; + + /* allocate page tables */ + size = num_pages * sizeof(pte_t); + size = (size + PAGE_SIZE) & ~(PAGE_SIZE-1); + next_pgtable = (unsigned long)alloc_bootmem_pages(size); + address = PAGE_OFFSET; + while (address < (unsigned long)high_memory) { + /* setup page table in page directory */ + pg_table = (pte_t *)next_pgtable; + next_pgtable += PTRS_PER_PTE * sizeof(pte_t); + pgd_val(*pg_dir) = (unsigned long)pg_table; + pg_dir++; + + /* create PTEs in page table */ + for (i = 0; i < PTRS_PER_PTE; ++i, ++pg_table) { + pte_t pte = pfn_pte(virt_to_pfn(address), PAGE_INIT); + if (address >= (unsigned long)high_memory) + pte_val(pte) = 0; + + set_pte(pg_table, pte); + address += PAGE_SIZE; + } + } + + /* + * setup page tables for DMA area + */ + + /* starting loc in page directory */ + pg_dir = swapper_pg_dir; + pg_dir += CONFIG_DMA_BASE >> PGDIR_SHIFT; + + /* allocate page tables */ + size = (CONFIG_DMA_SIZE >> PAGE_SHIFT) * sizeof(pte_t); + size = (size + PAGE_SIZE) & ~(PAGE_SIZE-1); + next_pgtable = (unsigned long)alloc_bootmem_pages(size); + address = CONFIG_DMA_BASE; + while (address < (CONFIG_DMA_BASE + CONFIG_DMA_SIZE)) { + /* setup page table in page directory */ + pg_table = (pte_t *)next_pgtable; + next_pgtable += PTRS_PER_PTE * sizeof(pte_t); + pgd_val(*pg_dir) = (unsigned long)pg_table; + pg_dir++; + + /* create PTEs in page table */ + for (i = 0; i < PTRS_PER_PTE; ++i, ++pg_table) { + pte_t pte = pfn_pte(virt_to_pfn(address), PAGE_INIT); + if (address >= (CONFIG_DMA_BASE + CONFIG_DMA_SIZE)) + pte_val(pte) = 0; + + set_pte(pg_table, pte); + address += PAGE_SIZE; + } + } + + /* + * setup zones + */ + + current->mm = NULL; + + /* clear zones */ + for (zone = 0; zone < MAX_NR_ZONES; zone++) + zones_size[zone] = 0x0; + + zones_size[ZONE_DMA] = CONFIG_DMA_SIZE >> PAGE_SHIFT; + zones_size[ZONE_NORMAL] = (((unsigned long)high_memory - + PAGE_OFFSET) >> PAGE_SHIFT) - + zones_size[ZONE_DMA]; + + free_area_init(zones_size); +} +/* + * Handle a missed TLB + */ +int cf_tlb_miss(struct pt_regs *regs, int write, int dtlb, int extension_word) +{ + struct mm_struct *mm; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + unsigned long mmuar; + int asid; + unsigned long flags; + + local_save_flags(flags); + local_irq_disable(); + + mmuar = (dtlb) ? regs->mmuar + : regs->pc + (extension_word * sizeof(long)); + + mm = (!user_mode(regs) && KMAPAREA(mmuar)) ? &init_mm : current->mm; + + if (!mm) { + local_irq_restore(flags); + return -1; + } + + pgd = pgd_offset(mm, mmuar); + if (pgd_none(*pgd)) { + local_irq_restore(flags); + return -1; + } + + pmd = pmd_offset(pgd, mmuar); + if (pmd_none(*pmd)) { + local_irq_restore(flags); + return -1; + } + + pte = (KMAPAREA(mmuar)) ? pte_offset_kernel(pmd, mmuar) + : pte_offset_map(pmd, mmuar); + if (pte_none(*pte) || !pte_present(*pte)) { + local_irq_restore(flags); + return -1; + } + + if (write) { + if (!pte_write(*pte)) { + local_irq_restore(flags); + return -1; + } + set_pte(pte, pte_mkdirty(*pte)); + } + + set_pte(pte, pte_mkyoung(*pte)); + asid = cpu_context(mm) & 0xff; + if (!pte_dirty(*pte) && !KMAPAREA(mmuar)) + set_pte(pte, pte_wrprotect(*pte)); + + *MMUTR = (mmuar & PAGE_MASK) | (asid << CF_ASID_MMU_SHIFT) + | (((int)(pte->pte) & (int)CF_PAGE_MMUTR_MASK) + >> CF_PAGE_MMUTR_SHIFT) | MMUTR_V; + + *MMUDR = (pte_val(*pte) & PAGE_MASK) + | ((pte->pte) & CF_PAGE_MMUDR_MASK) + | MMUDR_SZ8K | MMUDR_X; + + if (dtlb) + *MMUOR = MMUOR_ACC | MMUOR_UAA; + else + *MMUOR = MMUOR_ITLB | MMUOR_ACC | MMUOR_UAA; + + asm("nop"); + +#ifdef DEBUG + printk(KERN_INFO "cf_tlb_miss: va=%lx, pa=%lx\n", (mmuar & PAGE_MASK), + (pte_val(*pte) & PAGE_MASK)); +#endif + local_irq_restore(flags); + return 0; +} + + +/* + * Context Management + * + * Based on arch/ppc/mmu_context.c + */ + +/* + * Initialize the context management system. + */ +void __init mmu_context_init(void) +{ + /* + * Some processors have too few contexts to reserve one for + * init_mm, and require using context 0 for a normal task. + * Other processors reserve the use of context zero for the kernel. + * This code assumes FIRST_CONTEXT < 32. + */ + context_map[0] = (1 << FIRST_CONTEXT) - 1; + next_mmu_context = FIRST_CONTEXT; + atomic_set(&nr_free_contexts, LAST_CONTEXT - FIRST_CONTEXT + 1); +} + +/* + * Steal a context from a task that has one at the moment. + * This is only used on 8xx and 4xx and we presently assume that + * they don't do SMP. If they do then thicfpgalloc.hs will have to check + * whether the MM we steal is in use. + * We also assume that this is only used on systems that don't + * use an MMU hash table - this is true for 8xx and 4xx. + * This isn't an LRU system, it just frees up each context in + * turn (sort-of pseudo-random replacement :). This would be the + * place to implement an LRU scheme if anyone was motivated to do it. + * -- paulus + */ +void steal_context(void) +{ + struct mm_struct *mm; + /* free up context `next_mmu_context' */ + /* if we shouldn't free context 0, don't... */ + if (next_mmu_context < FIRST_CONTEXT) + next_mmu_context = FIRST_CONTEXT; + mm = context_mm[next_mmu_context]; + flush_tlb_mm(mm); + destroy_context(mm); +} --- /dev/null +++ b/arch/m68k/mm/cf-sram.c @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2009-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Author: Lanttor.Guo@freescale.com + * + * Providing on-chip SRAM allocation and free APIs to kernel + * The implemention uses gen_pool_alloc/gen_pool_free interface + * + * 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 +#include +#include +#include + +/* sram memory min allocation size per once */ +static long blk_size = CONFIG_SRAM_ALLOC_GRANULARITY; +static struct gen_pool *sram_pool; + +/* + * Set up memory pools to manage on-chip sram. + * @ start the start address of SRAM + * @ size the size of SRAM + * return return 0 express success + */ +int declare_sram_pool(void *start, size_t size) +{ + int status = 0; + + pr_debug("%s %p %d\n", __func__, start, size); + + sram_pool = gen_pool_create(ilog2(blk_size), -1); + if (!sram_pool) { + printk(KERN_ERR "gen_pool_creat faile at %s()\n", __func__); + status = -ENOMEM; + } + + status = gen_pool_add(sram_pool, (unsigned long)start, size, -1); + if (status < 0) + printk(KERN_ERR "gen_pool_add failed at %s()\n", __func__); + + return status; + +} + +/* + * Allocate memory from sram pool + * @ len the size of allocated memory + * return return the start addr of allocated memory + */ +void *sram_alloc(size_t len) +{ + unsigned long vaddr; + + if (!len) { + printk(KERN_ERR "the len parameter of sram_alloc() is zero\n"); + return NULL; + } + + vaddr = gen_pool_alloc(sram_pool, len); + if (!vaddr) + return NULL; + + return (void *)vaddr; +} +EXPORT_SYMBOL(sram_alloc); + +/* + * Free memory to sram pool + * @ addr the addr of allocated memory + * @ len the size of allocated memory + */ +void sram_free(void *addr, size_t len) +{ + gen_pool_free(sram_pool, (unsigned long)addr, len); +} +EXPORT_SYMBOL(sram_free); --- a/arch/m68k/mm/hwtest.c +++ b/arch/m68k/mm/hwtest.c @@ -12,6 +12,14 @@ * them here complete with the comments from the original atari * config.c... * -- PMM , 05/1998 + * + * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Jason Jin Jason.Jin@freescale.com + * Shrek Wu B16972@freescale.com + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. */ /* This function tests for the presence of an address, specially a @@ -25,6 +33,7 @@ #include +#ifndef CONFIG_COLDFIRE int hwreg_present( volatile void *regp ) { int ret = 0; @@ -82,4 +91,5 @@ int hwreg_write( volatile void *regp, un return( ret ); } EXPORT_SYMBOL(hwreg_write); +#endif --- a/arch/m68k/mm/init.c +++ b/arch/m68k/mm/init.c @@ -2,6 +2,13 @@ * linux/arch/m68k/mm/init.c * * Copyright (C) 1995 Hamish Macdonald + * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Jason Jin Jason.Jin@freescale.com + * Shrek Wu B16972@freescale.com + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. * * Contains common initialization routines, specific init code moved * to motorola.c and sun3mmu.c @@ -32,6 +39,7 @@ #include #include + DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); pg_data_t pg_data_map[MAX_NUMNODES]; @@ -113,7 +121,7 @@ void __init mem_init(void) } } -#ifndef CONFIG_SUN3 +#if !defined(CONFIG_SUN3) && !defined(CONFIG_COLDFIRE) /* insert pointer tables allocated so far into the tablelist */ init_pointer_table((unsigned long)kernel_pg_dir); for (i = 0; i < PTRS_PER_PGD; i++) { @@ -132,6 +140,11 @@ void __init mem_init(void) codepages << (PAGE_SHIFT-10), datapages << (PAGE_SHIFT-10), initpages << (PAGE_SHIFT-10)); + +#ifdef CONFIG_VDSO + /* init the vdso page */ + vdso_init(); +#endif } #ifdef CONFIG_BLK_DEV_INITRD --- a/arch/m68k/mm/kmap.c +++ b/arch/m68k/mm/kmap.c @@ -2,6 +2,13 @@ * linux/arch/m68k/mm/kmap.c * * Copyright (C) 1997 Roman Hodek + * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Jason Jin Jason.Jin@freescale.com + * Shrek Wu B16972@freescale.com + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. * * 10/01/99 cleaned up the code and changing to the same interface * used by other architectures /Roman Zippel @@ -24,7 +31,11 @@ #undef DEBUG +#ifndef CONFIG_COLDFIRE #define PTRTREESIZE (256*1024) +#else +#define PTRTREESIZE PAGE_SIZE +#endif /* * For 040/060 we can use the virtual memory area like other architectures, @@ -50,7 +61,11 @@ static inline void free_io_area(void *ad #else +#ifdef CONFIG_COLDFIRE +#define IO_SIZE PAGE_SIZE +#else #define IO_SIZE (256*1024) +#endif static struct vm_struct *iolist; @@ -126,8 +141,58 @@ void __iomem *__ioremap(unsigned long ph } #endif +#ifdef CONFIG_M5445X + if (physaddr >= 0xf0000000) { + /* + * On the M5445x processors an ACR is setup to map + * the 0xF0000000 range into kernel memory as + * non-cacheable. + */ + return (void __iomem *)physaddr; + } + if ((physaddr >= KMAP_START) && (physaddr <= KMAP_END)) { + /* if physaddr belongs to virtual address range for ioremap, + * then return physaddr because it has been ioremapped + */ + return (void __iomem *)physaddr; + } +#endif +#ifdef CONFIG_M547X_8X + if (physaddr >= 0xf0000000) { + /* + * On the M547x/M548x processors an ACR is setup to map + * the 0xF0000000 range into kernel memory as + * non-cacheable. + */ + return (void __iomem *)physaddr; + } + + if ((physaddr >= 0xd0000000) && (physaddr + size < 0xd800ffff)) { + printk(KERN_ERR "ioremap:PCI 0x%lx,0x%lx(%d)" + " - PCI area hit\n", physaddr, size, cacheflag); + return (void *)physaddr; + } +#endif +#ifdef CONFIG_M5441X + if (physaddr >= 0xe0000000) { + /* + * On the M5441x processors an ACR is setup to map + * the 0xe0000000 range into kernel memory as + * non-cacheable. + */ + return (void __iomem *)physaddr; + } + if ((physaddr >= KMAP_START) && (physaddr <= KMAP_END)) { + /* if physaddr belongs to virtual address range for ioremap, + * then return physaddr because it has been ioremapped + */ + return (void __iomem *)physaddr; + } +#endif + #ifdef DEBUG - printk("ioremap: 0x%lx,0x%lx(%d) - ", physaddr, size, cacheflag); + printk(KERN_ERR "ioremap: paddr=0x%lx,size=0x%lx(%d) - ", + physaddr, size, cacheflag); #endif /* * Mappings have to be aligned @@ -146,7 +211,8 @@ void __iomem *__ioremap(unsigned long ph virtaddr = (unsigned long)area->addr; retaddr = virtaddr + offset; #ifdef DEBUG - printk("0x%lx,0x%lx,0x%lx", physaddr, virtaddr, retaddr); + printk(KERN_ERR " paddr=0x%lx,vaddr=0x%lx,retaddr=0x%lx", + physaddr, virtaddr, retaddr); #endif /* @@ -171,7 +237,12 @@ void __iomem *__ioremap(unsigned long ph break; } } else { +#ifndef CONFIG_COLDFIRE physaddr |= (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY); +#else + physaddr |= (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY | \ + _PAGE_READWRITE); +#endif switch (cacheflag) { case IOMAP_NOCACHE_SER: case IOMAP_NOCACHE_NONSER: @@ -251,6 +322,13 @@ void __iounmap(void *addr, unsigned long pmd_t *pmd_dir; pte_t *pte_dir; +#ifdef CONFIG_M547X_8X + if ((addr >= (void *)0xd0000000) + && (addr + size < (void *)0xd800ffff)) { + printk(KERN_ERR "%s: PCI address\n", __func__); + return; + } +#endif while ((long)size > 0) { pgd_dir = pgd_offset_k(virtaddr); if (pgd_bad(*pgd_dir)) { --- a/arch/m68k/mm/memory.c +++ b/arch/m68k/mm/memory.c @@ -2,6 +2,13 @@ * linux/arch/m68k/mm/memory.c * * Copyright (C) 1995 Hamish Macdonald + * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Jason Jin Jason.Jin@freescale.com + * Shrek Wu B16972@freescale.com + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. */ #include @@ -127,6 +134,7 @@ int free_pointer_table (pmd_t *ptable) return 0; } +#ifndef CONFIG_COLDFIRE /* invalidate page in both caches */ static inline void clear040(unsigned long paddr) { @@ -173,6 +181,7 @@ static inline void pushcl040(unsigned lo clear040(paddr); local_irq_restore(flags); } +#endif /* CONFIG_COLDFIRE */ /* * 040: Hit every page containing an address in the range paddr..paddr+len-1. @@ -203,6 +212,9 @@ static inline void pushcl040(unsigned lo void cache_clear (unsigned long paddr, int len) { +#ifdef CONFIG_COLDFIRE + flush_bcache(); +#else if (CPU_IS_040_OR_060) { int tmp; @@ -237,6 +249,7 @@ void cache_clear (unsigned long paddr, i if(mach_l2_flush) mach_l2_flush(0); #endif +#endif /* CONFIG_COLDFIRE */ } EXPORT_SYMBOL(cache_clear); @@ -250,6 +263,9 @@ EXPORT_SYMBOL(cache_clear); void cache_push (unsigned long paddr, int len) { +#ifdef CONFIG_COLDFIRE + flush_bcache(); +#else if (CPU_IS_040_OR_060) { int tmp = PAGE_SIZE; @@ -290,6 +306,7 @@ void cache_push (unsigned long paddr, in if(mach_l2_flush) mach_l2_flush(1); #endif +#endif /* CONFIG_COLDFIRE */ } EXPORT_SYMBOL(cache_push); --- a/fs/namespace.c +++ b/fs/namespace.c @@ -3,6 +3,10 @@ * * (C) Copyright Al Viro 2000, 2001 * Released under GPL v2. + * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Change to align on page size for coldfire + * Jason Jin Jason.Jin@freescale.com + * Shrek Wu B16972@freescale.com * * Based on code from fs/super.c, copyright Linus Torvalds and others. * Heavily rewritten. @@ -2161,7 +2165,11 @@ int copy_mount_options(const void __user /* copy_from_user cannot cross TASK_SIZE ! */ size = TASK_SIZE - (unsigned long)data; if (size > PAGE_SIZE) +#ifndef CONFIG_COLDFIRE size = PAGE_SIZE; +#else + size = PAGE_SIZE - ((unsigned long)data & ~PAGE_MASK); +#endif i = size - exact_copy_from_user((void *)page, data, size); if (!i) { --- a/include/linux/fsl_devices.h +++ b/include/linux/fsl_devices.h @@ -6,7 +6,7 @@ * * Maintainer: Kumar Gala * - * Copyright 2004 Freescale Semiconductor, Inc + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights Reserved. * * 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 @@ -18,7 +18,7 @@ #define _FSL_DEVICE_H_ #include - +#include /* * Some conventions on how we handle peripherals on Freescale chips * @@ -119,4 +119,14 @@ int fsl_deep_sleep(void); static inline int fsl_deep_sleep(void) { return 0; } #endif +struct fsl_ata_platform_data { +#ifdef CONFIG_FSL_PATA_USE_DMA + int udma_mask; /* UDMA modes h/w can handle */ + int fifo_alarm; /* value for fifo_alarm reg */ + int max_sg; /* longest sglist h/w can handle */ +#endif + int (*init)(struct platform_device *pdev); + void (*exit)(void); + int (*get_clk_rate)(void); +}; #endif /* _FSL_DEVICE_H_ */