Merge branches 'sh/compressors' and 'sh/stable-updates'
authorPaul Mundt <lethal@linux-sh.org>
Tue, 21 Jul 2009 08:37:18 +0000 (17:37 +0900)
committerPaul Mundt <lethal@linux-sh.org>
Tue, 21 Jul 2009 08:37:18 +0000 (17:37 +0900)
56 files changed:
arch/sh/Kconfig
arch/sh/Kconfig.debug
arch/sh/Makefile
arch/sh/boards/mach-se/7724/setup.c
arch/sh/boot/.gitignore
arch/sh/boot/Makefile
arch/sh/boot/compressed/.gitignore [new file with mode: 0644]
arch/sh/boot/compressed/Makefile
arch/sh/boot/compressed/misc.c [new file with mode: 0644]
arch/sh/boot/compressed/misc_32.c [deleted file]
arch/sh/boot/compressed/misc_64.c [deleted file]
arch/sh/boot/compressed/piggy.S [deleted file]
arch/sh/boot/compressed/vmlinux.scr [new file with mode: 0644]
arch/sh/include/asm/ftrace.h
arch/sh/include/asm/hwblk.h [new file with mode: 0644]
arch/sh/include/asm/lmb.h [new file with mode: 0644]
arch/sh/include/asm/suspend.h
arch/sh/include/asm/syscall_32.h
arch/sh/include/asm/thread_info.h
arch/sh/include/cpu-sh4/cpu/sh7722.h
arch/sh/include/cpu-sh4/cpu/sh7723.h
arch/sh/kernel/Makefile_32
arch/sh/kernel/asm-offsets.c
arch/sh/kernel/cpu/Makefile
arch/sh/kernel/cpu/hwblk.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh4a/Makefile
arch/sh/kernel/cpu/sh4a/clock-sh7722.c
arch/sh/kernel/cpu/sh4a/clock-sh7723.c
arch/sh/kernel/cpu/sh4a/hwblk-sh7722.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh4a/hwblk-sh7723.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh4a/setup-sh7366.c
arch/sh/kernel/cpu/sh4a/setup-sh7723.c
arch/sh/kernel/cpu/shmobile/Makefile
arch/sh/kernel/cpu/shmobile/cpuidle.c [new file with mode: 0644]
arch/sh/kernel/cpu/shmobile/pm.c
arch/sh/kernel/entry-common.S
arch/sh/kernel/ftrace.c
arch/sh/kernel/irq.c
arch/sh/kernel/process_32.c
arch/sh/kernel/ptrace_32.c
arch/sh/kernel/setup.c
arch/sh/kernel/sh_ksyms_32.c
arch/sh/kernel/time.c
arch/sh/kernel/vmlinux.lds.S
arch/sh/lib/Makefile
arch/sh/lib/mcount.S
arch/sh/mm/fault_32.c
arch/sh/mm/numa.c
drivers/usb/gadget/m66592-udc.c
drivers/usb/gadget/m66592-udc.h
drivers/usb/host/Kconfig
drivers/usb/host/r8a66597-hcd.c
drivers/usb/host/r8a66597.h
drivers/video/Kconfig
drivers/video/sh_mobile_lcdcfb.c
include/linux/usb/r8a66597.h

index e2bdd7b..c4a955d 100644 (file)
@@ -10,12 +10,16 @@ config SUPERH
        select EMBEDDED
        select HAVE_CLK
        select HAVE_IDE
+       select HAVE_LMB
        select HAVE_OPROFILE
        select HAVE_GENERIC_DMA_COHERENT
        select HAVE_IOREMAP_PROT if MMU
        select HAVE_ARCH_TRACEHOOK
        select HAVE_DMA_API_DEBUG
        select HAVE_PERF_COUNTERS
+       select HAVE_KERNEL_GZIP
+       select HAVE_KERNEL_BZIP2
+       select HAVE_KERNEL_LZMA
        select RTC_LIB
        select GENERIC_ATOMIC64
        help
@@ -31,6 +35,9 @@ config SUPERH32
        select HAVE_FUNCTION_TRACER
        select HAVE_FTRACE_MCOUNT_RECORD
        select HAVE_DYNAMIC_FTRACE
+       select HAVE_FUNCTION_TRACE_MCOUNT_TEST
+       select HAVE_FTRACE_SYSCALLS
+       select HAVE_FUNCTION_GRAPH_TRACER
        select HAVE_ARCH_KGDB
        select ARCH_HIBERNATION_POSSIBLE if MMU
 
index 39224b5..b440fd9 100644 (file)
@@ -61,12 +61,14 @@ config EARLY_PRINTK
          select both the EARLY_SCIF_CONSOLE and SH_STANDARD_BIOS, using
          the kernel command line option to toggle back and forth.
 
-config DEBUG_STACKOVERFLOW
+config STACK_DEBUG
        bool "Check for stack overflows"
        depends on DEBUG_KERNEL && SUPERH32
        help
          This option will cause messages to be printed if free stack space
-         drops below a certain limit.
+         drops below a certain limit. Saying Y here will add overhead to
+         every function call and will therefore incur a major
+         performance hit. Most users should say N.
 
 config DEBUG_STACK_USAGE
        bool "Stack utilization instrumentation"
@@ -123,4 +125,9 @@ config SH64_SR_WATCH
        bool "Debug: set SR.WATCH to enable hardware watchpoints and trace"
        depends on SUPERH64
 
+config MCOUNT
+       def_bool y
+       depends on SUPERH32
+       depends on STACK_DEBUG || FUNCTION_TRACER
+
 endmenu
index 75d049b..34ad114 100644 (file)
@@ -186,17 +186,23 @@ KBUILD_CFLAGS             += -pipe $(cflags-y)
 KBUILD_CPPFLAGS                += $(cflags-y)
 KBUILD_AFLAGS          += $(cflags-y)
 
+ifeq ($(CONFIG_MCOUNT),y)
+  KBUILD_CFLAGS += -pg
+endif
+
 libs-$(CONFIG_SUPERH32)                := arch/sh/lib/ $(libs-y)
 libs-$(CONFIG_SUPERH64)                := arch/sh/lib64/ $(libs-y)
 
-PHONY += maketools FORCE
+BOOT_TARGETS = uImage uImage.bz2 uImage.gz uImage.lzma uImage.srec \
+              zImage vmlinux.srec
+PHONY += maketools $(BOOT_TARGETS) FORCE
 
 maketools:  include/linux/version.h FORCE
        $(Q)$(MAKE) $(build)=arch/sh/tools include/asm-sh/machtypes.h
 
 all: $(KBUILD_IMAGE)
 
-zImage uImage uImage.srec vmlinux.srec: vmlinux
+$(BOOT_TARGETS): vmlinux
        $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
 
 compressed: zImage
@@ -208,10 +214,13 @@ archclean:
        $(Q)$(MAKE) $(clean)=arch/sh/kernel/vsyscall
 
 define archhelp
-       @echo '* zImage                    - Compressed kernel image'
+       @echo '  zImage                    - Compressed kernel image'
        @echo '  vmlinux.srec              - Create an ELF S-record'
-       @echo '  uImage                    - Create a bootable image for U-Boot'
-       @echo '  uImage.srec               - Create an S-record for U-Boot'
+       @echo '* uImage                    - Alias to bootable U-Boot image'
+       @echo '  uImage.srec               - Create an S-record for U-Boot'
+       @echo '* uImage.gz                 - Kernel-only image for U-Boot (gzip)'
+       @echo '  uImage.bz2                - Kernel-only image for U-Boot (bzip2)'
+       @echo '  uImage.lzma               - Kernel-only image for U-Boot (lzma)'
 endef
 
 CLEAN_FILES += include/asm-sh/machtypes.h
index 8fed45a..4fb7e48 100644 (file)
@@ -304,6 +304,7 @@ static struct platform_device sh_eth_device = {
 };
 
 static struct r8a66597_platdata sh7724_usb0_host_data = {
+       .on_chip = 1,
 };
 
 static struct resource sh7724_usb0_host_resources[] = {
index aad5edd..541087d 100644 (file)
@@ -1,4 +1,3 @@
 zImage
-vmlinux.srec
-uImage
-uImage.srec
+vmlinux*
+uImage*
index 78efb04..dd2a852 100644 (file)
@@ -20,7 +20,12 @@ CONFIG_BOOT_LINK_OFFSET      ?= 0x00800000
 CONFIG_ZERO_PAGE_OFFSET        ?= 0x00001000
 CONFIG_ENTRY_OFFSET    ?= 0x00001000
 
-targets := zImage vmlinux.srec uImage uImage.srec
+suffix-$(CONFIG_KERNEL_GZIP)  := gz
+suffix-$(CONFIG_KERNEL_BZIP2) := bz2
+suffix-$(CONFIG_KERNEL_LZMA)  := lzma
+
+targets := zImage vmlinux.srec uImage uImage.srec uImage.gz uImage.bz2 uImage.lzma
+extra-y += vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma
 subdir- := compressed
 
 $(obj)/zImage: $(obj)/compressed/vmlinux FORCE
@@ -40,9 +45,6 @@ KERNEL_MEMORY := $(shell /bin/bash -c 'printf "0x%08x" \
                     $$[$(CONFIG_MEMORY_START)]')
 endif
 
-export CONFIG_PAGE_OFFSET CONFIG_MEMORY_START CONFIG_BOOT_LINK_OFFSET \
-       CONFIG_ZERO_PAGE_OFFSET CONFIG_ENTRY_OFFSET KERNEL_MEMORY
-
 KERNEL_LOAD    := $(shell /bin/bash -c 'printf "0x%08x" \
                     $$[$(CONFIG_PAGE_OFFSET)  + \
                        $(KERNEL_MEMORY) + \
@@ -55,19 +57,30 @@ KERNEL_ENTRY        := $(shell /bin/bash -c 'printf "0x%08x" \
 
 quiet_cmd_uimage = UIMAGE  $@
       cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A sh -O linux -T kernel \
-                  -C gzip -a $(KERNEL_LOAD) -e $(KERNEL_ENTRY) \
+                  -C $(2) -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)
 
+$(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin FORCE
+       $(call if_changed,bzip2)
+
+$(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin FORCE
+       $(call if_changed,lzma)
+
+$(obj)/uImage.bz2: $(obj)/vmlinux.bin.bz2
+       $(call if_changed,uimage,bzip2)
+
+$(obj)/uImage.gz: $(obj)/vmlinux.bin.gz
+       $(call if_changed,uimage,gzip)
+
+$(obj)/uImage.lzma: $(obj)/vmlinux.bin.lzma
+       $(call if_changed,uimage,lzma)
+
 OBJCOPYFLAGS_vmlinux.srec := -I binary -O srec
 $(obj)/vmlinux.srec: $(obj)/compressed/vmlinux
        $(call if_changed,objcopy)
@@ -76,5 +89,9 @@ OBJCOPYFLAGS_uImage.srec := -I binary -O srec
 $(obj)/uImage.srec: $(obj)/uImage
        $(call if_changed,objcopy)
 
-clean-files    += uImage uImage.srec vmlinux.srec \
-                  vmlinux.bin vmlinux.bin.gz
+$(obj)/uImage: $(obj)/uImage.$(suffix-y)
+       @ln -sf $(notdir $<) $@
+       @echo '  Image $@ is ready'
+
+export CONFIG_PAGE_OFFSET CONFIG_MEMORY_START CONFIG_BOOT_LINK_OFFSET \
+       CONFIG_ZERO_PAGE_OFFSET CONFIG_ENTRY_OFFSET KERNEL_MEMORY suffix-y
diff --git a/arch/sh/boot/compressed/.gitignore b/arch/sh/boot/compressed/.gitignore
new file mode 100644 (file)
index 0000000..2374a83
--- /dev/null
@@ -0,0 +1 @@
+vmlinux.bin.*
index 9531bf1..6182eca 100644 (file)
@@ -5,9 +5,10 @@
 #
 
 targets                := vmlinux vmlinux.bin vmlinux.bin.gz \
-                  head_$(BITS).o misc_$(BITS).o piggy.o
+                  vmlinux.bin.bz2 vmlinux.bin.lzma \
+                  head_$(BITS).o misc.o piggy.o
 
-OBJECTS = $(obj)/head_$(BITS).o $(obj)/misc_$(BITS).o $(obj)/cache.o
+OBJECTS = $(obj)/head_$(BITS).o $(obj)/misc.o $(obj)/cache.o
 
 ifdef CONFIG_SH_STANDARD_BIOS
 OBJECTS += $(obj)/../../kernel/sh_bios.o
@@ -23,7 +24,7 @@ IMAGE_OFFSET  := $(shell /bin/bash -c 'printf "0x%08x" \
 
 LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
 
-ifeq ($(CONFIG_FUNCTION_TRACER),y)
+ifeq ($(CONFIG_MCOUNT),y)
 ORIG_CFLAGS := $(KBUILD_CFLAGS)
 KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CFLAGS))
 endif
@@ -38,10 +39,18 @@ $(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o $(LIBGCC) FORCE
 $(obj)/vmlinux.bin: vmlinux FORCE
        $(call if_changed,objcopy)
 
-$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
+vmlinux.bin.all-y := $(obj)/vmlinux.bin
+
+$(obj)/vmlinux.bin.gz: $(vmlinux.bin.all-y) FORCE
        $(call if_changed,gzip)
+$(obj)/vmlinux.bin.bz2: $(vmlinux.bin.all-y) FORCE
+       $(call if_changed,bzip2)
+$(obj)/vmlinux.bin.lzma: $(vmlinux.bin.all-y) FORCE
+       $(call if_changed,lzma)
 
 OBJCOPYFLAGS += -R .empty_zero_page
 
-$(obj)/piggy.o: $(obj)/piggy.S $(obj)/vmlinux.bin.gz FORCE
-       $(call if_changed,as_o_S)
+LDFLAGS_piggy.o := -r --format binary --oformat $(ld-bfd) -T
+
+$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.$(suffix-y) FORCE
+       $(call if_changed,ld)
diff --git a/arch/sh/boot/compressed/misc.c b/arch/sh/boot/compressed/misc.c
new file mode 100644 (file)
index 0000000..fd56a71
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * arch/sh/boot/compressed/misc.c
+ *
+ * This is a collection of several routines from gzip-1.0.3
+ * adapted for Linux.
+ *
+ * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
+ *
+ * Adapted for SH by Stuart Menefy, Aug 1999
+ *
+ * Modified to use standard LinuxSH BIOS by Greg Banks 7Jul2000
+ */
+
+#include <asm/uaccess.h>
+#include <asm/addrspace.h>
+#include <asm/page.h>
+#include <asm/sh_bios.h>
+
+/*
+ * gzip declarations
+ */
+
+#define STATIC static
+
+#undef memset
+#undef memcpy
+#define memzero(s, n)     memset ((s), 0, (n))
+
+/* cache.c */
+#define CACHE_ENABLE      0
+#define CACHE_DISABLE     1
+int cache_control(unsigned int command);
+
+extern char input_data[];
+extern int input_len;
+static unsigned char *output;
+
+static void error(char *m);
+
+int puts(const char *);
+
+extern int _text;              /* Defined in vmlinux.lds.S */
+extern int _end;
+static unsigned long free_mem_ptr;
+static unsigned long free_mem_end_ptr;
+
+#ifdef CONFIG_HAVE_KERNEL_BZIP2
+#define HEAP_SIZE      0x400000
+#else
+#define HEAP_SIZE      0x10000
+#endif
+
+#ifdef CONFIG_KERNEL_GZIP
+#include "../../../../lib/decompress_inflate.c"
+#endif
+
+#ifdef CONFIG_KERNEL_BZIP2
+#include "../../../../lib/decompress_bunzip2.c"
+#endif
+
+#ifdef CONFIG_KERNEL_LZMA
+#include "../../../../lib/decompress_unlzma.c"
+#endif
+
+#ifdef CONFIG_SH_STANDARD_BIOS
+size_t strlen(const char *s)
+{
+       int i = 0;
+
+       while (*s++)
+               i++;
+       return i;
+}
+
+int puts(const char *s)
+{
+       int len = strlen(s);
+       sh_bios_console_write(s, len);
+       return len;
+}
+#else
+int puts(const char *s)
+{
+       /* This should be updated to use the sh-sci routines */
+       return 0;
+}
+#endif
+
+void* memset(void* s, int c, size_t n)
+{
+       int i;
+       char *ss = (char*)s;
+
+       for (i=0;i<n;i++) ss[i] = c;
+       return s;
+}
+
+void* memcpy(void* __dest, __const void* __src,
+                           size_t __n)
+{
+       int i;
+       char *d = (char *)__dest, *s = (char *)__src;
+
+       for (i=0;i<__n;i++) d[i] = s[i];
+       return __dest;
+}
+
+static void error(char *x)
+{
+       puts("\n\n");
+       puts(x);
+       puts("\n\n -- System halted");
+
+       while(1);       /* Halt */
+}
+
+#ifdef CONFIG_SUPERH64
+#define stackalign     8
+#else
+#define stackalign     4
+#endif
+
+#define STACK_SIZE (4096)
+long __attribute__ ((aligned(stackalign))) user_stack[STACK_SIZE];
+long *stack_start = &user_stack[STACK_SIZE];
+
+void decompress_kernel(void)
+{
+       unsigned long output_addr;
+
+#ifdef CONFIG_SUPERH64
+       output_addr = (CONFIG_MEMORY_START + 0x2000);
+#else
+       output_addr = PHYSADDR((unsigned long)&_text+PAGE_SIZE);
+#ifdef CONFIG_29BIT
+       output_addr |= P2SEG;
+#endif
+#endif
+
+       output = (unsigned char *)output_addr;
+       free_mem_ptr = (unsigned long)&_end;
+       free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
+
+       puts("Uncompressing Linux... ");
+       cache_control(CACHE_ENABLE);
+       decompress(input_data, input_len, NULL, NULL, output, NULL, error);
+       cache_control(CACHE_DISABLE);
+       puts("Ok, booting the kernel.\n");
+}
diff --git a/arch/sh/boot/compressed/misc_32.c b/arch/sh/boot/compressed/misc_32.c
deleted file mode 100644 (file)
index efdba6b..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * arch/sh/boot/compressed/misc.c
- *
- * This is a collection of several routines from gzip-1.0.3
- * adapted for Linux.
- *
- * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
- *
- * Adapted for SH by Stuart Menefy, Aug 1999
- *
- * Modified to use standard LinuxSH BIOS by Greg Banks 7Jul2000
- */
-
-#include <asm/uaccess.h>
-#include <asm/addrspace.h>
-#include <asm/page.h>
-#ifdef CONFIG_SH_STANDARD_BIOS
-#include <asm/sh_bios.h>
-#endif
-
-/*
- * gzip declarations
- */
-
-#define OF(args)  args
-#define STATIC static
-
-#undef memset
-#undef memcpy
-#define memzero(s, n)     memset ((s), 0, (n))
-
-typedef unsigned char  uch;
-typedef unsigned short ush;
-typedef unsigned long  ulg;
-
-#define WSIZE 0x8000           /* Window size must be at least 32k, */
-                               /* and a power of two */
-
-static uch *inbuf;          /* input buffer */
-static uch window[WSIZE];    /* Sliding window buffer */
-
-static unsigned insize = 0;  /* valid bytes in inbuf */
-static unsigned inptr = 0;   /* index of next byte to be processed in inbuf */
-static unsigned outcnt = 0;  /* bytes in output buffer */
-
-/* gzip flag byte */
-#define ASCII_FLAG   0x01 /* bit 0 set: file probably ASCII text */
-#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
-#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
-#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
-#define COMMENT      0x10 /* bit 4 set: file comment present */
-#define ENCRYPTED    0x20 /* bit 5 set: file is encrypted */
-#define RESERVED     0xC0 /* bit 6,7:   reserved */
-
-#define get_byte()  (inptr < insize ? inbuf[inptr++] : fill_inbuf())
-
-/* Diagnostic functions */
-#ifdef DEBUG
-#  define Assert(cond,msg) {if(!(cond)) error(msg);}
-#  define Trace(x) fprintf x
-#  define Tracev(x) {if (verbose) fprintf x ;}
-#  define Tracevv(x) {if (verbose>1) fprintf x ;}
-#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
-#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
-#else
-#  define Assert(cond,msg)
-#  define Trace(x)
-#  define Tracev(x)
-#  define Tracevv(x)
-#  define Tracec(c,x)
-#  define Tracecv(c,x)
-#endif
-
-static int  fill_inbuf(void);
-static void flush_window(void);
-static void error(char *m);
-
-extern char input_data[];
-extern int input_len;
-
-static long bytes_out = 0;
-static uch *output_data;
-static unsigned long output_ptr = 0;
-
-static void error(char *m);
-
-int puts(const char *);
-
-extern int _text;              /* Defined in vmlinux.lds.S */
-extern int _end;
-static unsigned long free_mem_ptr;
-static unsigned long free_mem_end_ptr;
-
-#define HEAP_SIZE             0x10000
-
-#include "../../../../lib/inflate.c"
-
-#ifdef CONFIG_SH_STANDARD_BIOS
-size_t strlen(const char *s)
-{
-       int i = 0;
-
-       while (*s++)
-               i++;
-       return i;
-}
-
-int puts(const char *s)
-{
-       int len = strlen(s);
-       sh_bios_console_write(s, len);
-       return len;
-}
-#else
-int puts(const char *s)
-{
-       /* This should be updated to use the sh-sci routines */
-       return 0;
-}
-#endif
-
-void* memset(void* s, int c, size_t n)
-{
-       int i;
-       char *ss = (char*)s;
-
-       for (i=0;i<n;i++) ss[i] = c;
-       return s;
-}
-
-void* memcpy(void* __dest, __const void* __src,
-                           size_t __n)
-{
-       int i;
-       char *d = (char *)__dest, *s = (char *)__src;
-
-       for (i=0;i<__n;i++) d[i] = s[i];
-       return __dest;
-}
-
-/* ===========================================================================
- * Fill the input buffer. This is called only when the buffer is empty
- * and at least one byte is really needed.
- */
-static int fill_inbuf(void)
-{
-       if (insize != 0) {
-               error("ran out of input data");
-       }
-
-       inbuf = input_data;
-       insize = input_len;
-       inptr = 1;
-       return inbuf[0];
-}
-
-/* ===========================================================================
- * Write the output window window[0..outcnt-1] and update crc and bytes_out.
- * (Used for the decompressed data only.)
- */
-static void flush_window(void)
-{
-    ulg c = crc;         /* temporary variable */
-    unsigned n;
-    uch *in, *out, ch;
-
-    in = window;
-    out = &output_data[output_ptr];
-    for (n = 0; n < outcnt; n++) {
-           ch = *out++ = *in++;
-           c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
-    }
-    crc = c;
-    bytes_out += (ulg)outcnt;
-    output_ptr += (ulg)outcnt;
-    outcnt = 0;
-}
-
-static void error(char *x)
-{
-       puts("\n\n");
-       puts(x);
-       puts("\n\n -- System halted");
-
-       while(1);       /* Halt */
-}
-
-#define STACK_SIZE (4096)
-long user_stack [STACK_SIZE];
-long* stack_start = &user_stack[STACK_SIZE];
-
-void decompress_kernel(void)
-{
-       output_data = NULL;
-       output_ptr = PHYSADDR((unsigned long)&_text+PAGE_SIZE);
-#ifdef CONFIG_29BIT
-       output_ptr |= P2SEG;
-#endif
-       free_mem_ptr = (unsigned long)&_end;
-       free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
-
-       makecrc();
-       puts("Uncompressing Linux... ");
-       gunzip();
-       puts("Ok, booting the kernel.\n");
-}
diff --git a/arch/sh/boot/compressed/misc_64.c b/arch/sh/boot/compressed/misc_64.c
deleted file mode 100644 (file)
index 2941657..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * arch/sh/boot/compressed/misc_64.c
- *
- * This is a collection of several routines from gzip-1.0.3
- * adapted for Linux.
- *
- * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
- *
- * Adapted for SHmedia from sh by Stuart Menefy, May 2002
- */
-
-#include <asm/uaccess.h>
-
-/* cache.c */
-#define CACHE_ENABLE      0
-#define CACHE_DISABLE     1
-int cache_control(unsigned int command);
-
-/*
- * gzip declarations
- */
-
-#define OF(args)  args
-#define STATIC static
-
-#undef memset
-#undef memcpy
-#define memzero(s, n)     memset ((s), 0, (n))
-
-typedef unsigned char uch;
-typedef unsigned short ush;
-typedef unsigned long ulg;
-
-#define WSIZE 0x8000           /* Window size must be at least 32k, */
-                               /* and a power of two */
-
-static uch *inbuf;             /* input buffer */
-static uch window[WSIZE];      /* Sliding window buffer */
-
-static unsigned insize = 0;    /* valid bytes in inbuf */
-static unsigned inptr = 0;     /* index of next byte to be processed in inbuf */
-static unsigned outcnt = 0;    /* bytes in output buffer */
-
-/* gzip flag byte */
-#define ASCII_FLAG   0x01      /* bit 0 set: file probably ASCII text */
-#define CONTINUATION 0x02      /* bit 1 set: continuation of multi-part gzip file */
-#define EXTRA_FIELD  0x04      /* bit 2 set: extra field present */
-#define ORIG_NAME    0x08      /* bit 3 set: original file name present */
-#define COMMENT      0x10      /* bit 4 set: file comment present */
-#define ENCRYPTED    0x20      /* bit 5 set: file is encrypted */
-#define RESERVED     0xC0      /* bit 6,7:   reserved */
-
-#define get_byte()  (inptr < insize ? inbuf[inptr++] : fill_inbuf())
-
-/* Diagnostic functions */
-#ifdef DEBUG
-#  define Assert(cond,msg) {if(!(cond)) error(msg);}
-#  define Trace(x) fprintf x
-#  define Tracev(x) {if (verbose) fprintf x ;}
-#  define Tracevv(x) {if (verbose>1) fprintf x ;}
-#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
-#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
-#else
-#  define Assert(cond,msg)
-#  define Trace(x)
-#  define Tracev(x)
-#  define Tracevv(x)
-#  define Tracec(c,x)
-#  define Tracecv(c,x)
-#endif
-
-static int fill_inbuf(void);
-static void flush_window(void);
-static void error(char *m);
-
-extern char input_data[];
-extern int input_len;
-
-static long bytes_out = 0;
-static uch *output_data;
-static unsigned long output_ptr = 0;
-
-static void error(char *m);
-
-static void puts(const char *);
-
-extern int _text;              /* Defined in vmlinux.lds.S */
-extern int _end;
-static unsigned long free_mem_ptr;
-static unsigned long free_mem_end_ptr;
-
-#define HEAP_SIZE             0x10000
-
-#include "../../../../lib/inflate.c"
-
-void puts(const char *s)
-{
-}
-
-void *memset(void *s, int c, size_t n)
-{
-       int i;
-       char *ss = (char *) s;
-
-       for (i = 0; i < n; i++)
-               ss[i] = c;
-       return s;
-}
-
-void *memcpy(void *__dest, __const void *__src, size_t __n)
-{
-       int i;
-       char *d = (char *) __dest, *s = (char *) __src;
-
-       for (i = 0; i < __n; i++)
-               d[i] = s[i];
-       return __dest;
-}
-
-/* ===========================================================================
- * Fill the input buffer. This is called only when the buffer is empty
- * and at least one byte is really needed.
- */
-static int fill_inbuf(void)
-{
-       if (insize != 0) {
-               error("ran out of input data\n");
-       }
-
-       inbuf = input_data;
-       insize = input_len;
-       inptr = 1;
-       return inbuf[0];
-}
-
-/* ===========================================================================
- * Write the output window window[0..outcnt-1] and update crc and bytes_out.
- * (Used for the decompressed data only.)
- */
-static void flush_window(void)
-{
-       ulg c = crc;            /* temporary variable */
-       unsigned n;
-       uch *in, *out, ch;
-
-       in = window;
-       out = &output_data[output_ptr];
-       for (n = 0; n < outcnt; n++) {
-               ch = *out++ = *in++;
-               c = crc_32_tab[((int) c ^ ch) & 0xff] ^ (c >> 8);
-       }
-       crc = c;
-       bytes_out += (ulg) outcnt;
-       output_ptr += (ulg) outcnt;
-       outcnt = 0;
-       puts(".");
-}
-
-static void error(char *x)
-{
-       puts("\n\n");
-       puts(x);
-       puts("\n\n -- System halted");
-
-       while (1) ;             /* Halt */
-}
-
-#define STACK_SIZE (4096)
-long __attribute__ ((aligned(8))) user_stack[STACK_SIZE];
-long *stack_start = &user_stack[STACK_SIZE];
-
-void decompress_kernel(void)
-{
-       output_data = (uch *) (CONFIG_MEMORY_START + 0x2000);
-       free_mem_ptr = (unsigned long) &_end;
-       free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
-
-       makecrc();
-       puts("Uncompressing Linux... ");
-       cache_control(CACHE_ENABLE);
-       gunzip();
-       puts("\n");
-
-#if 0
-       /* When booting from ROM may want to do something like this if the
-        * boot loader doesn't.
-        */
-
-       /* Set up the parameters and command line */
-       {
-               volatile unsigned int *parambase =
-                   (int *) (CONFIG_MEMORY_START + 0x1000);
-
-               parambase[0] = 0x1;     /* MOUNT_ROOT_RDONLY */
-               parambase[1] = 0x0;     /* RAMDISK_FLAGS */
-               parambase[2] = 0x0200;  /* ORIG_ROOT_DEV */
-               parambase[3] = 0x0;     /* LOADER_TYPE */
-               parambase[4] = 0x0;     /* INITRD_START */
-               parambase[5] = 0x0;     /* INITRD_SIZE */
-               parambase[6] = 0;
-
-               strcpy((char *) ((int) parambase + 0x100),
-                      "console=ttySC0,38400");
-       }
-#endif
-
-       puts("Ok, booting the kernel.\n");
-
-       cache_control(CACHE_DISABLE);
-}
diff --git a/arch/sh/boot/compressed/piggy.S b/arch/sh/boot/compressed/piggy.S
deleted file mode 100644 (file)
index 5660719..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-       .global input_len, input_data
-       .data
-input_len:
-       .long   input_data_end - input_data
-input_data:
-       .incbin "arch/sh/boot/compressed/vmlinux.bin.gz"
-input_data_end:
-       .end
diff --git a/arch/sh/boot/compressed/vmlinux.scr b/arch/sh/boot/compressed/vmlinux.scr
new file mode 100644 (file)
index 0000000..f02382a
--- /dev/null
@@ -0,0 +1,10 @@
+SECTIONS
+{
+  .rodata.compressed : {
+       input_len = .;
+       LONG(input_data_end - input_data) input_data = .;
+       *(.data)
+       output_len = . - 4;
+       input_data_end = .;
+       }
+}
index 8fea7d8..7e0bcc4 100644 (file)
@@ -11,10 +11,13 @@ extern void mcount(void);
 #define MCOUNT_ADDR            ((long)(mcount))
 
 #ifdef CONFIG_DYNAMIC_FTRACE
-#define CALLER_ADDR            ((long)(ftrace_caller))
+#define CALL_ADDR              ((long)(ftrace_call))
 #define STUB_ADDR              ((long)(ftrace_stub))
+#define GRAPH_ADDR             ((long)(ftrace_graph_call))
+#define CALLER_ADDR            ((long)(ftrace_caller))
 
-#define MCOUNT_INSN_OFFSET     ((STUB_ADDR - CALLER_ADDR) >> 1)
+#define MCOUNT_INSN_OFFSET     ((STUB_ADDR - CALL_ADDR) - 4)
+#define GRAPH_INSN_OFFSET      ((CALLER_ADDR - GRAPH_ADDR) - 4)
 
 struct dyn_arch_ftrace {
        /* No extra data needed on sh */
diff --git a/arch/sh/include/asm/hwblk.h b/arch/sh/include/asm/hwblk.h
new file mode 100644 (file)
index 0000000..c01d72c
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef __ASM_SH_HWBLK_H
+#define __ASM_SH_HWBLK_H
+
+#include <asm/clock.h>
+#include <asm/io.h>
+
+#define HWBLK_CNT_USAGE 0
+#define HWBLK_CNT_NR 1
+
+#define HWBLK_AREA_FLAG_PARENT (1 << 0) /* valid parent */
+
+#define HWBLK_AREA(_flags, _parent)            \
+{                                              \
+       .flags = _flags,                        \
+       .parent = _parent,                      \
+}
+
+struct hwblk_area {
+       int cnt[HWBLK_CNT_NR];
+       unsigned char parent;
+       unsigned char flags;
+};
+
+#define HWBLK(_mstp, _bit, _area)              \
+{                                              \
+       .mstp = (void __iomem *)_mstp,          \
+       .bit = _bit,                            \
+       .area = _area,                          \
+}
+
+struct hwblk {
+       void __iomem *mstp;
+       unsigned char bit;
+       unsigned char area;
+       int cnt[HWBLK_CNT_NR];
+};
+
+struct hwblk_info {
+       struct hwblk_area *areas;
+       int nr_areas;
+       struct hwblk *hwblks;
+       int nr_hwblks;
+};
+
+/* Should be defined by processor-specific code */
+int arch_hwblk_init(void);
+int arch_hwblk_sleep_mode(void);
+
+int hwblk_register(struct hwblk_info *info);
+int hwblk_init(void);
+
+void hwblk_enable(struct hwblk_info *info, int hwblk);
+void hwblk_disable(struct hwblk_info *info, int hwblk);
+
+void hwblk_cnt_inc(struct hwblk_info *info, int hwblk, int cnt);
+void hwblk_cnt_dec(struct hwblk_info *info, int hwblk, int cnt);
+
+/* allow clocks to enable and disable hardware blocks */
+#define SH_HWBLK_CLK(_name, _id, _parent, _hwblk, _flags)      \
+{                                                      \
+       .name           = _name,                        \
+       .id             = _id,                          \
+       .parent         = _parent,                      \
+       .arch_flags     = _hwblk,                       \
+       .flags          = _flags,                       \
+}
+
+int sh_hwblk_clk_register(struct clk *clks, int nr);
+
+#endif /* __ASM_SH_HWBLK_H */
diff --git a/arch/sh/include/asm/lmb.h b/arch/sh/include/asm/lmb.h
new file mode 100644 (file)
index 0000000..9b437f6
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __ASM_SH_LMB_H
+#define __ASM_SH_LMB_H
+
+#define LMB_REAL_LIMIT 0
+
+#endif /* __ASM_SH_LMB_H */
index b1b9953..5c8ea28 100644 (file)
@@ -10,6 +10,15 @@ struct swsusp_arch_regs {
        struct pt_regs user_regs;
        unsigned long bank1_regs[8];
 };
+
+void sh_mobile_call_standby(unsigned long mode);
+
+#ifdef CONFIG_CPU_IDLE
+void sh_mobile_setup_cpuidle(void);
+#else
+static inline void sh_mobile_setup_cpuidle(void) {}
+#endif
+
 #endif
 
 /* flags passed to assembly suspend code */
index 6f83f2c..7d80df4 100644 (file)
@@ -65,6 +65,7 @@ static inline void syscall_get_arguments(struct task_struct *task,
        case 3: args[2] = regs->regs[6];
        case 2: args[1] = regs->regs[5];
        case 1: args[0] = regs->regs[4];
+       case 0:
                break;
        default:
                BUG();
index d570ac2..5123bca 100644 (file)
@@ -97,7 +97,7 @@ static inline struct thread_info *current_thread_info(void)
 
 extern struct thread_info *alloc_thread_info(struct task_struct *tsk);
 extern void free_thread_info(struct thread_info *ti);
+
 #endif /* THREAD_SHIFT < PAGE_SHIFT */
 
 #endif /* __ASSEMBLY__ */
@@ -116,6 +116,7 @@ extern void free_thread_info(struct thread_info *ti);
 #define TIF_SYSCALL_AUDIT      5       /* syscall auditing active */
 #define TIF_SECCOMP            6       /* secure computing */
 #define TIF_NOTIFY_RESUME      7       /* callback before returning to user */
+#define TIF_SYSCALL_FTRACE     8       /* for ftrace syscall instrumentation */
 #define TIF_USEDFPU            16      /* FPU was used by this task this quantum (SMP) */
 #define TIF_POLLING_NRFLAG     17      /* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_MEMDIE             18
@@ -129,25 +130,27 @@ extern void free_thread_info(struct thread_info *ti);
 #define _TIF_SYSCALL_AUDIT     (1 << TIF_SYSCALL_AUDIT)
 #define _TIF_SECCOMP           (1 << TIF_SECCOMP)
 #define _TIF_NOTIFY_RESUME     (1 << TIF_NOTIFY_RESUME)
+#define _TIF_SYSCALL_FTRACE    (1 << TIF_SYSCALL_FTRACE)
 #define _TIF_USEDFPU           (1 << TIF_USEDFPU)
 #define _TIF_POLLING_NRFLAG    (1 << TIF_POLLING_NRFLAG)
 #define _TIF_FREEZE            (1 << TIF_FREEZE)
 
 /*
- * _TIF_ALLWORK_MASK and _TIF_WORK_MASK need to fit within a byte, or we
+ * _TIF_ALLWORK_MASK and _TIF_WORK_MASK need to fit within 2 bytes, or we
  * blow the tst immediate size constraints and need to fix up
  * arch/sh/kernel/entry-common.S.
  */
 
 /* work to do in syscall trace */
 #define _TIF_WORK_SYSCALL_MASK (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP | \
-                                _TIF_SYSCALL_AUDIT | _TIF_SECCOMP)
+                                _TIF_SYSCALL_AUDIT | _TIF_SECCOMP    | \
+                                _TIF_SYSCALL_FTRACE)
 
 /* work to do on any return to u-space */
 #define _TIF_ALLWORK_MASK      (_TIF_SYSCALL_TRACE | _TIF_SIGPENDING      | \
                                 _TIF_NEED_RESCHED  | _TIF_SYSCALL_AUDIT   | \
                                 _TIF_SINGLESTEP    | _TIF_RESTORE_SIGMASK | \
-                                _TIF_NOTIFY_RESUME)
+                                _TIF_NOTIFY_RESUME | _TIF_SYSCALL_FTRACE)
 
 /* work to do on interrupt/exception return */
 #define _TIF_WORK_MASK         (_TIF_ALLWORK_MASK & ~(_TIF_SYSCALL_TRACE | \
index 738ea43..4856040 100644 (file)
@@ -221,4 +221,18 @@ enum {
        GPIO_FN_KEYOUT3, GPIO_FN_KEYOUT4_IN6, GPIO_FN_KEYOUT5_IN5,
 };
 
+enum {
+       HWBLK_UNKNOWN = 0,
+       HWBLK_TLB, HWBLK_IC, HWBLK_OC, HWBLK_URAM, HWBLK_XYMEM,
+       HWBLK_INTC, HWBLK_DMAC, HWBLK_SHYWAY, HWBLK_HUDI,
+       HWBLK_UBC, HWBLK_TMU, HWBLK_CMT, HWBLK_RWDT, HWBLK_FLCTL,
+       HWBLK_SCIF0, HWBLK_SCIF1, HWBLK_SCIF2, HWBLK_SIO,
+       HWBLK_SIOF0, HWBLK_SIOF1, HWBLK_IIC, HWBLK_RTC,
+       HWBLK_TPU, HWBLK_IRDA, HWBLK_SDHI, HWBLK_SIM, HWBLK_KEYSC,
+       HWBLK_TSIF, HWBLK_USBF, HWBLK_2DG, HWBLK_SIU, HWBLK_VOU,
+       HWBLK_JPU, HWBLK_BEU, HWBLK_CEU, HWBLK_VEU, HWBLK_VPU,
+       HWBLK_LCDC,
+       HWBLK_NR,
+};
+
 #endif /* __ASM_SH7722_H__ */
index 14c8ca9..9b36fae 100644 (file)
@@ -265,4 +265,21 @@ enum {
        GPIO_FN_IDEA1, GPIO_FN_IDEA0,
 };
 
+enum {
+       HWBLK_UNKNOWN = 0,
+       HWBLK_TLB, HWBLK_IC, HWBLK_OC, HWBLK_L2C, HWBLK_ILMEM, HWBLK_FPU,
+       HWBLK_INTC, HWBLK_DMAC0, HWBLK_SHYWAY,
+       HWBLK_HUDI, HWBLK_DBG, HWBLK_UBC, HWBLK_SUBC,
+       HWBLK_TMU0, HWBLK_CMT, HWBLK_RWDT, HWBLK_DMAC1, HWBLK_TMU1,
+       HWBLK_FLCTL,
+       HWBLK_SCIF0, HWBLK_SCIF1, HWBLK_SCIF2,
+       HWBLK_SCIF3, HWBLK_SCIF4, HWBLK_SCIF5,
+       HWBLK_MSIOF0, HWBLK_MSIOF1, HWBLK_MERAM, HWBLK_IIC, HWBLK_RTC,
+       HWBLK_ATAPI, HWBLK_ADC, HWBLK_TPU, HWBLK_IRDA, HWBLK_TSIF, HWBLK_ICB,
+       HWBLK_SDHI0, HWBLK_SDHI1, HWBLK_KEYSC, HWBLK_USB,
+       HWBLK_2DG, HWBLK_SIU, HWBLK_VEU2H1, HWBLK_VOU, HWBLK_BEU, HWBLK_CEU,
+       HWBLK_VEU2H0, HWBLK_VPU, HWBLK_LCDC,
+       HWBLK_NR,
+};
+
 #endif /* __ASM_SH7723_H__ */
index 9411e3e..94ed99b 100644 (file)
@@ -29,6 +29,8 @@ obj-$(CONFIG_IO_TRAPPED)      += io_trapped.o
 obj-$(CONFIG_KPROBES)          += kprobes.o
 obj-$(CONFIG_GENERIC_GPIO)     += gpio.o
 obj-$(CONFIG_DYNAMIC_FTRACE)   += ftrace.o
+obj-$(CONFIG_FTRACE_SYSCALLS)  += ftrace.o
+obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
 obj-$(CONFIG_DUMP_CODE)                += disassemble.o
 obj-$(CONFIG_HIBERNATION)      += swsusp.o
 
index 99aceb2..d218e80 100644 (file)
@@ -26,6 +26,7 @@ int main(void)
        DEFINE(TI_CPU,          offsetof(struct thread_info, cpu));
        DEFINE(TI_PRE_COUNT,    offsetof(struct thread_info, preempt_count));
        DEFINE(TI_RESTART_BLOCK,offsetof(struct thread_info, restart_block));
+       DEFINE(TI_SIZE,         sizeof(struct thread_info));
 
 #ifdef CONFIG_HIBERNATION
        DEFINE(PBE_ADDRESS, offsetof(struct pbe, address));
index eecad7c..3d6b931 100644 (file)
@@ -19,4 +19,4 @@ obj-$(CONFIG_UBC_WAKEUP)      += ubc.o
 obj-$(CONFIG_SH_ADC)           += adc.o
 obj-$(CONFIG_SH_CLK_CPG)       += clock-cpg.o
 
-obj-y  += irq/ init.o clock.o
+obj-y  += irq/ init.o clock.o hwblk.o
diff --git a/arch/sh/kernel/cpu/hwblk.c b/arch/sh/kernel/cpu/hwblk.c
new file mode 100644 (file)
index 0000000..c0ad7d4
--- /dev/null
@@ -0,0 +1,155 @@
+#include <linux/clk.h>
+#include <linux/compiler.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <asm/suspend.h>
+#include <asm/hwblk.h>
+#include <asm/clock.h>
+
+static DEFINE_SPINLOCK(hwblk_lock);
+
+static void hwblk_area_mod_cnt(struct hwblk_info *info,
+                              int area, int counter, int value, int goal)
+{
+       struct hwblk_area *hap = info->areas + area;
+
+       hap->cnt[counter] += value;
+
+       if (hap->cnt[counter] != goal)
+               return;
+
+       if (hap->flags & HWBLK_AREA_FLAG_PARENT)
+               hwblk_area_mod_cnt(info, hap->parent, counter, value, goal);
+}
+
+
+static int __hwblk_mod_cnt(struct hwblk_info *info, int hwblk,
+                         int counter, int value, int goal)
+{
+       struct hwblk *hp = info->hwblks + hwblk;
+
+       hp->cnt[counter] += value;
+       if (hp->cnt[counter] == goal)
+               hwblk_area_mod_cnt(info, hp->area, counter, value, goal);
+
+       return hp->cnt[counter];
+}
+
+static void hwblk_mod_cnt(struct hwblk_info *info, int hwblk,
+                         int counter, int value, int goal)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&hwblk_lock, flags);
+       __hwblk_mod_cnt(info, hwblk, counter, value, goal);
+       spin_unlock_irqrestore(&hwblk_lock, flags);
+}
+
+void hwblk_cnt_inc(struct hwblk_info *info, int hwblk, int counter)
+{
+       hwblk_mod_cnt(info, hwblk, counter, 1, 1);
+}
+
+void hwblk_cnt_dec(struct hwblk_info *info, int hwblk, int counter)
+{
+       hwblk_mod_cnt(info, hwblk, counter, -1, 0);
+}
+
+void hwblk_enable(struct hwblk_info *info, int hwblk)
+{
+       struct hwblk *hp = info->hwblks + hwblk;
+       unsigned long tmp;
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&hwblk_lock, flags);
+
+       ret = __hwblk_mod_cnt(info, hwblk, HWBLK_CNT_USAGE, 1, 1);
+       if (ret == 1) {
+               tmp = __raw_readl(hp->mstp);
+               tmp &= ~(1 << hp->bit);
+               __raw_writel(tmp, hp->mstp);
+       }
+
+       spin_unlock_irqrestore(&hwblk_lock, flags);
+}
+
+void hwblk_disable(struct hwblk_info *info, int hwblk)
+{
+       struct hwblk *hp = info->hwblks + hwblk;
+       unsigned long tmp;
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&hwblk_lock, flags);
+
+       ret = __hwblk_mod_cnt(info, hwblk, HWBLK_CNT_USAGE, -1, 0);
+       if (ret == 0) {
+               tmp = __raw_readl(hp->mstp);
+               tmp |= 1 << hp->bit;
+               __raw_writel(tmp, hp->mstp);
+       }
+
+       spin_unlock_irqrestore(&hwblk_lock, flags);
+}
+
+struct hwblk_info *hwblk_info;
+
+int __init hwblk_register(struct hwblk_info *info)
+{
+       hwblk_info = info;
+       return 0;
+}
+
+int __init __weak arch_hwblk_init(void)
+{
+       return 0;
+}
+
+int __weak arch_hwblk_sleep_mode(void)
+{
+       return SUSP_SH_SLEEP;
+}
+
+int __init hwblk_init(void)
+{
+       return arch_hwblk_init();
+}
+
+/* allow clocks to enable and disable hardware blocks */
+static int sh_hwblk_clk_enable(struct clk *clk)
+{
+       if (!hwblk_info)
+               return -ENOENT;
+
+       hwblk_enable(hwblk_info, clk->arch_flags);
+       return 0;
+}
+
+static void sh_hwblk_clk_disable(struct clk *clk)
+{
+       if (hwblk_info)
+               hwblk_disable(hwblk_info, clk->arch_flags);
+}
+
+static struct clk_ops sh_hwblk_clk_ops = {
+       .enable         = sh_hwblk_clk_enable,
+       .disable        = sh_hwblk_clk_disable,
+       .recalc         = followparent_recalc,
+};
+
+int __init sh_hwblk_clk_register(struct clk *clks, int nr)
+{
+       struct clk *clkp;
+       int ret = 0;
+       int k;
+
+       for (k = 0; !ret && (k < nr); k++) {
+               clkp = clks + k;
+               clkp->ops = &sh_hwblk_clk_ops;
+               ret |= clk_register(clkp);
+       }
+
+       return ret;
+}
index ebdd391..1d7ae38 100644 (file)
@@ -25,8 +25,8 @@ clock-$(CONFIG_CPU_SUBTYPE_SH7780)    := clock-sh7780.o
 clock-$(CONFIG_CPU_SUBTYPE_SH7785)     := clock-sh7785.o
 clock-$(CONFIG_CPU_SUBTYPE_SH7786)     := clock-sh7786.o
 clock-$(CONFIG_CPU_SUBTYPE_SH7343)     := clock-sh7343.o
-clock-$(CONFIG_CPU_SUBTYPE_SH7722)     := clock-sh7722.o
-clock-$(CONFIG_CPU_SUBTYPE_SH7723)     := clock-sh7723.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7722)     := clock-sh7722.o hwblk-sh7722.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7723)     := clock-sh7723.o hwblk-sh7723.o
 clock-$(CONFIG_CPU_SUBTYPE_SH7724)     := clock-sh7724.o
 clock-$(CONFIG_CPU_SUBTYPE_SH7366)     := clock-sh7366.o
 clock-$(CONFIG_CPU_SUBTYPE_SHX3)       := clock-shx3.o
index 40f8593..1fa9e1d 100644 (file)
@@ -22,6 +22,8 @@
 #include <linux/kernel.h>
 #include <linux/io.h>
 #include <asm/clock.h>
+#include <asm/hwblk.h>
+#include <cpu/sh7722.h>
 
 /* SH7722 registers */
 #define FRQCR          0xa4150000
@@ -140,35 +142,37 @@ struct clk div6_clks[] = {
        SH_CLK_DIV6("video_clk", &pll_clk, VCLKCR, 0),
 };
 
-#define MSTP(_str, _parent, _reg, _bit, _flags) \
-  SH_CLK_MSTP32(_str, -1, _parent, _reg, _bit, _flags)
+#define R_CLK &r_clk
+#define P_CLK &div4_clks[DIV4_P]
+#define B_CLK &div4_clks[DIV4_B]
+#define U_CLK &div4_clks[DIV4_U]
 
 static struct clk mstp_clks[] = {
-       MSTP("uram0", &div4_clks[DIV4_U], MSTPCR0, 28, CLK_ENABLE_ON_INIT),
-       MSTP("xymem0", &div4_clks[DIV4_B], MSTPCR0, 26, CLK_ENABLE_ON_INIT),
-       MSTP("tmu0", &div4_clks[DIV4_P], MSTPCR0, 15, 0),
-       MSTP("cmt0", &r_clk, MSTPCR0, 14, 0),
-       MSTP("rwdt0", &r_clk, MSTPCR0, 13, 0),
-       MSTP("flctl0", &div4_clks[DIV4_P], MSTPCR0, 10, 0),
-       MSTP("scif0", &div4_clks[DIV4_P], MSTPCR0, 7, 0),
-       MSTP("scif1", &div4_clks[DIV4_P], MSTPCR0, 6, 0),
-       MSTP("scif2", &div4_clks[DIV4_P], MSTPCR0, 5, 0),
-
-       MSTP("i2c0", &div4_clks[DIV4_P], MSTPCR1, 9, 0),
-       MSTP("rtc0", &r_clk, MSTPCR1, 8, 0),
-
-       MSTP("sdhi0", &div4_clks[DIV4_P], MSTPCR2, 18, 0),
-       MSTP("keysc0", &r_clk, MSTPCR2, 14, 0),
-       MSTP("usbf0", &div4_clks[DIV4_P], MSTPCR2, 11, 0),
-       MSTP("2dg0", &div4_clks[DIV4_B], MSTPCR2, 9, 0),
-       MSTP("siu0", &div4_clks[DIV4_B], MSTPCR2, 8, 0),
-       MSTP("vou0", &div4_clks[DIV4_B], MSTPCR2, 5, 0),
-       MSTP("jpu0", &div4_clks[DIV4_B], MSTPCR2, 6, CLK_ENABLE_ON_INIT),
-       MSTP("beu0", &div4_clks[DIV4_B], MSTPCR2, 4, 0),
-       MSTP("ceu0", &div4_clks[DIV4_B], MSTPCR2, 3, 0),
-       MSTP("veu0", &div4_clks[DIV4_B], MSTPCR2, 2, CLK_ENABLE_ON_INIT),
-       MSTP("vpu0", &div4_clks[DIV4_B], MSTPCR2, 1, CLK_ENABLE_ON_INIT),
-       MSTP("lcdc0", &div4_clks[DIV4_B], MSTPCR2, 0, 0),
+       SH_HWBLK_CLK("uram0", -1, U_CLK, HWBLK_URAM, CLK_ENABLE_ON_INIT),
+       SH_HWBLK_CLK("xymem0", -1, B_CLK, HWBLK_XYMEM, CLK_ENABLE_ON_INIT),
+       SH_HWBLK_CLK("tmu0", -1, P_CLK, HWBLK_TMU, 0),
+       SH_HWBLK_CLK("cmt0", -1, R_CLK, HWBLK_CMT, 0),
+       SH_HWBLK_CLK("rwdt0", -1, R_CLK, HWBLK_RWDT, 0),
+       SH_HWBLK_CLK("flctl0", -1, P_CLK, HWBLK_FLCTL, 0),
+       SH_HWBLK_CLK("scif0", -1, P_CLK, HWBLK_SCIF0, 0),
+       SH_HWBLK_CLK("scif1", -1, P_CLK, HWBLK_SCIF1, 0),
+       SH_HWBLK_CLK("scif2", -1, P_CLK, HWBLK_SCIF2, 0),
+
+       SH_HWBLK_CLK("i2c0", -1, P_CLK, HWBLK_IIC, 0),
+       SH_HWBLK_CLK("rtc0", -1, R_CLK, HWBLK_RTC, 0),
+
+       SH_HWBLK_CLK("sdhi0", -1, P_CLK, HWBLK_SDHI, 0),
+       SH_HWBLK_CLK("keysc0", -1, R_CLK, HWBLK_KEYSC, 0),
+       SH_HWBLK_CLK("usbf0", -1, P_CLK, HWBLK_USBF, 0),
+       SH_HWBLK_CLK("2dg0", -1, B_CLK, HWBLK_2DG, 0),
+       SH_HWBLK_CLK("siu0", -1, B_CLK, HWBLK_SIU, 0),
+       SH_HWBLK_CLK("vou0", -1, B_CLK, HWBLK_VOU, 0),
+       SH_HWBLK_CLK("jpu0", -1, B_CLK, HWBLK_JPU, CLK_ENABLE_ON_INIT),
+       SH_HWBLK_CLK("beu0", -1, B_CLK, HWBLK_BEU, 0),
+       SH_HWBLK_CLK("ceu0", -1, B_CLK, HWBLK_CEU, 0),
+       SH_HWBLK_CLK("veu0", -1, B_CLK, HWBLK_VEU, CLK_ENABLE_ON_INIT),
+       SH_HWBLK_CLK("vpu0", -1, B_CLK, HWBLK_VPU, CLK_ENABLE_ON_INIT),
+       SH_HWBLK_CLK("lcdc0", -1, P_CLK, HWBLK_LCDC, 0),
 };
 
 int __init arch_clk_init(void)
@@ -191,7 +195,7 @@ int __init arch_clk_init(void)
                ret = sh_clk_div6_register(div6_clks, ARRAY_SIZE(div6_clks));
 
        if (!ret)
-               ret = sh_clk_mstp32_register(mstp_clks, ARRAY_SIZE(mstp_clks));
+               ret = sh_hwblk_clk_register(mstp_clks, ARRAY_SIZE(mstp_clks));
 
        return ret;
 }
index e67c267..bf64c78 100644 (file)
@@ -22,6 +22,8 @@
 #include <linux/kernel.h>
 #include <linux/io.h>
 #include <asm/clock.h>
+#include <asm/hwblk.h>
+#include <cpu/sh7723.h>
 
 /* SH7723 registers */
 #define FRQCR          0xa4150000
@@ -140,60 +142,64 @@ struct clk div6_clks[] = {
        SH_CLK_DIV6("video_clk", &pll_clk, VCLKCR, 0),
 };
 
-#define MSTP(_str, _parent, _reg, _bit, _force_on, _need_cpg, _need_ram) \
-  SH_CLK_MSTP32(_str, -1, _parent, _reg, _bit, _force_on * CLK_ENABLE_ON_INIT)
+#define R_CLK (&r_clk)
+#define P_CLK (&div4_clks[DIV4_P])
+#define B_CLK (&div4_clks[DIV4_B])
+#define U_CLK (&div4_clks[DIV4_U])
+#define I_CLK (&div4_clks[DIV4_I])
+#define SH_CLK (&div4_clks[DIV4_SH])
 
 static struct clk mstp_clks[] = {
        /* See page 60 of Datasheet V1.0: Overview -> Block Diagram */
-       MSTP("tlb0", &div4_clks[DIV4_I], MSTPCR0, 31, 1, 1, 0),
-       MSTP("ic0", &div4_clks[DIV4_I], MSTPCR0, 30, 1, 1, 0),
-       MSTP("oc0", &div4_clks[DIV4_I], MSTPCR0, 29, 1, 1, 0),
-       MSTP("l2c0", &div4_clks[DIV4_SH], MSTPCR0, 28, 1, 1, 0),
-       MSTP("ilmem0", &div4_clks[DIV4_I], MSTPCR0, 27, 1, 1, 0),
-       MSTP("fpu0", &div4_clks[DIV4_I], MSTPCR0, 24, 1, 1, 0),
-       MSTP("intc0", &div4_clks[DIV4_I], MSTPCR0, 22, 1, 1, 0),
-       MSTP("dmac0", &div4_clks[DIV4_B], MSTPCR0, 21, 0, 1, 1),
-       MSTP("sh0", &div4_clks[DIV4_SH], MSTPCR0, 20, 0, 1, 0),
-       MSTP("hudi0", &div4_clks[DIV4_P], MSTPCR0, 19, 0, 1, 0),
-       MSTP("ubc0", &div4_clks[DIV4_I], MSTPCR0, 17, 0, 1, 0),
-       MSTP("tmu0", &div4_clks[DIV4_P], MSTPCR0, 15, 0, 1, 0),
-       MSTP("cmt0", &r_clk, MSTPCR0, 14, 0, 0, 0),
-       MSTP("rwdt0", &r_clk, MSTPCR0, 13, 0, 0, 0),
-       MSTP("dmac1", &div4_clks[DIV4_B], MSTPCR0, 12, 0, 1, 1),
-       MSTP("tmu1", &div4_clks[DIV4_P], MSTPCR0, 11, 0, 1, 0),
-       MSTP("flctl0", &div4_clks[DIV4_P], MSTPCR0, 10, 0, 1, 0),
-       MSTP("scif0", &div4_clks[DIV4_P], MSTPCR0, 9, 0, 1, 0),
-       MSTP("scif1", &div4_clks[DIV4_P], MSTPCR0, 8, 0, 1, 0),
-       MSTP("scif2", &div4_clks[DIV4_P], MSTPCR0, 7, 0, 1, 0),
-       MSTP("scif3", &div4_clks[DIV4_B], MSTPCR0, 6, 0, 1, 0),
-       MSTP("scif4", &div4_clks[DIV4_B], MSTPCR0, 5, 0, 1, 0),
-       MSTP("scif5", &div4_clks[DIV4_B], MSTPCR0, 4, 0, 1, 0),
-       MSTP("msiof0", &div4_clks[DIV4_B], MSTPCR0, 2, 0, 1, 0),
-       MSTP("msiof1", &div4_clks[DIV4_B], MSTPCR0, 1, 0, 1, 0),
-       MSTP("meram0", &div4_clks[DIV4_SH], MSTPCR0, 0, 1, 1, 0),
-
-       MSTP("i2c0", &div4_clks[DIV4_P], MSTPCR1, 9, 0, 1, 0),
-       MSTP("rtc0", &r_clk, MSTPCR1, 8, 0, 0, 0),
-
-       MSTP("atapi0", &div4_clks[DIV4_SH], MSTPCR2, 28, 0, 1, 0),
-       MSTP("adc0", &div4_clks[DIV4_P], MSTPCR2, 27, 0, 1, 0),
-       MSTP("tpu0", &div4_clks[DIV4_B], MSTPCR2, 25, 0, 1, 0),
-       MSTP("irda0", &div4_clks[DIV4_P], MSTPCR2, 24, 0, 1, 0),
-       MSTP("tsif0", &div4_clks[DIV4_B], MSTPCR2, 22, 0, 1, 0),
-       MSTP("icb0", &div4_clks[DIV4_B], MSTPCR2, 21, 0, 1, 1),
-       MSTP("sdhi0", &div4_clks[DIV4_B], MSTPCR2, 18, 0, 1, 0),
-       MSTP("sdhi1", &div4_clks[DIV4_B], MSTPCR2, 17, 0, 1, 0),
-       MSTP("keysc0", &r_clk, MSTPCR2, 14, 0, 0, 0),
-       MSTP("usb0", &div4_clks[DIV4_B], MSTPCR2, 11, 0, 1, 0),
-       MSTP("2dg0", &div4_clks[DIV4_B], MSTPCR2, 10, 0, 1, 1),
-       MSTP("siu0", &div4_clks[DIV4_B], MSTPCR2, 8, 0, 1, 0),
-       MSTP("veu1", &div4_clks[DIV4_B], MSTPCR2, 6, 1, 1, 1),
-       MSTP("vou0", &div4_clks[DIV4_B], MSTPCR2, 5, 0, 1, 1),
-       MSTP("beu0", &div4_clks[DIV4_B], MSTPCR2, 4, 0, 1, 1),
-       MSTP("ceu0", &div4_clks[DIV4_B], MSTPCR2, 3, 0, 1, 1),
-       MSTP("veu0", &div4_clks[DIV4_B], MSTPCR2, 2, 1, 1, 1),
-       MSTP("vpu0", &div4_clks[DIV4_B], MSTPCR2, 1, 1, 1, 1),
-       MSTP("lcdc0", &div4_clks[DIV4_B], MSTPCR2, 0, 0, 1, 1),
+       SH_HWBLK_CLK("tlb0", -1, I_CLK, HWBLK_TLB, CLK_ENABLE_ON_INIT),
+       SH_HWBLK_CLK("ic0", -1, I_CLK, HWBLK_IC, CLK_ENABLE_ON_INIT),
+       SH_HWBLK_CLK("oc0", -1, I_CLK, HWBLK_OC, CLK_ENABLE_ON_INIT),
+       SH_HWBLK_CLK("l2c0", -1, SH_CLK, HWBLK_L2C, CLK_ENABLE_ON_INIT),
+       SH_HWBLK_CLK("ilmem0", -1, I_CLK, HWBLK_ILMEM, CLK_ENABLE_ON_INIT),
+       SH_HWBLK_CLK("fpu0", -1, I_CLK, HWBLK_FPU, CLK_ENABLE_ON_INIT),
+       SH_HWBLK_CLK("intc0", -1, I_CLK, HWBLK_INTC, CLK_ENABLE_ON_INIT),
+       SH_HWBLK_CLK("dmac0", -1, B_CLK, HWBLK_DMAC0, 0),
+       SH_HWBLK_CLK("sh0", -1, SH_CLK, HWBLK_SHYWAY, CLK_ENABLE_ON_INIT),
+       SH_HWBLK_CLK("hudi0", -1, P_CLK, HWBLK_HUDI, 0),
+       SH_HWBLK_CLK("ubc0", -1, I_CLK, HWBLK_UBC, 0),
+       SH_HWBLK_CLK("tmu0", -1, P_CLK, HWBLK_TMU0, 0),
+       SH_HWBLK_CLK("cmt0", -1, R_CLK, HWBLK_CMT, 0),
+       SH_HWBLK_CLK("rwdt0", -1, R_CLK, HWBLK_RWDT, 0),
+       SH_HWBLK_CLK("dmac1", -1, B_CLK, HWBLK_DMAC1, 0),
+       SH_HWBLK_CLK("tmu1", -1, P_CLK, HWBLK_TMU1, 0),
+       SH_HWBLK_CLK("flctl0", -1, P_CLK, HWBLK_FLCTL, 0),
+       SH_HWBLK_CLK("scif0", -1, P_CLK, HWBLK_SCIF0, 0),
+       SH_HWBLK_CLK("scif1", -1, P_CLK, HWBLK_SCIF1, 0),
+       SH_HWBLK_CLK("scif2", -1, P_CLK, HWBLK_SCIF2, 0),
+       SH_HWBLK_CLK("scif3", -1, B_CLK, HWBLK_SCIF3, 0),
+       SH_HWBLK_CLK("scif4", -1, B_CLK, HWBLK_SCIF4, 0),
+       SH_HWBLK_CLK("scif5", -1, B_CLK, HWBLK_SCIF5, 0),
+       SH_HWBLK_CLK("msiof0", -1, B_CLK, HWBLK_MSIOF0, 0),
+       SH_HWBLK_CLK("msiof1", -1, B_CLK, HWBLK_MSIOF1, 0),
+       SH_HWBLK_CLK("meram0", -1, SH_CLK, HWBLK_MERAM, 0),
+
+       SH_HWBLK_CLK("i2c0", -1, P_CLK, HWBLK_IIC, 0),
+       SH_HWBLK_CLK("rtc0", -1, R_CLK, HWBLK_RTC, 0),
+
+       SH_HWBLK_CLK("atapi0", -1, SH_CLK, HWBLK_ATAPI, 0),
+       SH_HWBLK_CLK("adc0", -1, P_CLK, HWBLK_ADC, 0),
+       SH_HWBLK_CLK("tpu0", -1, B_CLK, HWBLK_TPU, 0),
+       SH_HWBLK_CLK("irda0", -1, P_CLK, HWBLK_IRDA, 0),
+       SH_HWBLK_CLK("tsif0", -1, B_CLK, HWBLK_TSIF, 0),
+       SH_HWBLK_CLK("icb0", -1, B_CLK, HWBLK_ICB, CLK_ENABLE_ON_INIT),
+       SH_HWBLK_CLK("sdhi0", -1, B_CLK, HWBLK_SDHI0, 0),
+       SH_HWBLK_CLK("sdhi1", -1, B_CLK, HWBLK_SDHI1, 0),
+       SH_HWBLK_CLK("keysc0", -1, R_CLK, HWBLK_KEYSC, 0),
+       SH_HWBLK_CLK("usb0", -1, B_CLK, HWBLK_USB, 0),
+       SH_HWBLK_CLK("2dg0", -1, B_CLK, HWBLK_2DG, 0),
+       SH_HWBLK_CLK("siu0", -1, B_CLK, HWBLK_SIU, 0),
+       SH_HWBLK_CLK("veu1", -1, B_CLK, HWBLK_VEU2H1, CLK_ENABLE_ON_INIT),
+       SH_HWBLK_CLK("vou0", -1, B_CLK, HWBLK_VOU, 0),
+       SH_HWBLK_CLK("beu0", -1, B_CLK, HWBLK_BEU, 0),
+       SH_HWBLK_CLK("ceu0", -1, B_CLK, HWBLK_CEU, 0),
+       SH_HWBLK_CLK("veu0", -1, B_CLK, HWBLK_VEU2H0, CLK_ENABLE_ON_INIT),
+       SH_HWBLK_CLK("vpu0", -1, B_CLK, HWBLK_VPU, CLK_ENABLE_ON_INIT),
+       SH_HWBLK_CLK("lcdc0", -1, B_CLK, HWBLK_LCDC, 0),
 };
 
 int __init arch_clk_init(void)
@@ -216,7 +222,7 @@ int __init arch_clk_init(void)
                ret = sh_clk_div6_register(div6_clks, ARRAY_SIZE(div6_clks));
 
        if (!ret)
-               ret = sh_clk_mstp32_register(mstp_clks, ARRAY_SIZE(mstp_clks));
+               ret = sh_hwblk_clk_register(mstp_clks, ARRAY_SIZE(mstp_clks));
 
        return ret;
 }
diff --git a/arch/sh/kernel/cpu/sh4a/hwblk-sh7722.c b/arch/sh/kernel/cpu/sh4a/hwblk-sh7722.c
new file mode 100644 (file)
index 0000000..a288b5d
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * arch/sh/kernel/cpu/sh4a/hwblk-sh7722.c
+ *
+ * SH7722 hardware block support
+ *
+ * Copyright (C) 2009 Magnus Damm
+ *
+ * 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
+ *
+ * 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
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <asm/suspend.h>
+#include <asm/hwblk.h>
+#include <cpu/sh7722.h>
+
+/* SH7722 registers */
+#define MSTPCR0                0xa4150030
+#define MSTPCR1                0xa4150034
+#define MSTPCR2                0xa4150038
+
+/* SH7722 Power Domains */
+enum { CORE_AREA, SUB_AREA, CORE_AREA_BM };
+static struct hwblk_area sh7722_hwblk_area[] = {
+       [CORE_AREA] = HWBLK_AREA(0, 0),
+       [CORE_AREA_BM] = HWBLK_AREA(HWBLK_AREA_FLAG_PARENT, CORE_AREA),
+       [SUB_AREA] = HWBLK_AREA(0, 0),
+};
+
+/* Table mapping HWBLK to Module Stop Bit and Power Domain */
+static struct hwblk sh7722_hwblk[HWBLK_NR] = {
+       [HWBLK_TLB] = HWBLK(MSTPCR0, 31, CORE_AREA),
+       [HWBLK_IC] = HWBLK(MSTPCR0, 30, CORE_AREA),
+       [HWBLK_OC] = HWBLK(MSTPCR0, 29, CORE_AREA),
+       [HWBLK_URAM] = HWBLK(MSTPCR0, 28, CORE_AREA),
+       [HWBLK_XYMEM] = HWBLK(MSTPCR0, 26, CORE_AREA),
+       [HWBLK_INTC] = HWBLK(MSTPCR0, 22, CORE_AREA),
+       [HWBLK_DMAC] = HWBLK(MSTPCR0, 21, CORE_AREA_BM),
+       [HWBLK_SHYWAY] = HWBLK(MSTPCR0, 20, CORE_AREA),
+       [HWBLK_HUDI] = HWBLK(MSTPCR0, 19, CORE_AREA),
+       [HWBLK_UBC] = HWBLK(MSTPCR0, 17, CORE_AREA),
+       [HWBLK_TMU] = HWBLK(MSTPCR0, 15, CORE_AREA),
+       [HWBLK_CMT] = HWBLK(MSTPCR0, 14, SUB_AREA),
+       [HWBLK_RWDT] = HWBLK(MSTPCR0, 13, SUB_AREA),
+       [HWBLK_FLCTL] = HWBLK(MSTPCR0, 10, CORE_AREA),
+       [HWBLK_SCIF0] = HWBLK(MSTPCR0, 7, CORE_AREA),
+       [HWBLK_SCIF1] = HWBLK(MSTPCR0, 6, CORE_AREA),
+       [HWBLK_SCIF2] = HWBLK(MSTPCR0, 5, CORE_AREA),
+       [HWBLK_SIO] = HWBLK(MSTPCR0, 3, CORE_AREA),
+       [HWBLK_SIOF0] = HWBLK(MSTPCR0, 2, CORE_AREA),
+       [HWBLK_SIOF1] = HWBLK(MSTPCR0, 1, CORE_AREA),
+
+       [HWBLK_IIC] = HWBLK(MSTPCR1, 9, CORE_AREA),
+       [HWBLK_RTC] = HWBLK(MSTPCR1, 8, SUB_AREA),
+
+       [HWBLK_TPU] = HWBLK(MSTPCR2, 25, CORE_AREA),
+       [HWBLK_IRDA] = HWBLK(MSTPCR2, 24, CORE_AREA),
+       [HWBLK_SDHI] = HWBLK(MSTPCR2, 18, CORE_AREA),
+       [HWBLK_SIM] = HWBLK(MSTPCR2, 16, CORE_AREA),
+       [HWBLK_KEYSC] = HWBLK(MSTPCR2, 14, SUB_AREA),
+       [HWBLK_TSIF] = HWBLK(MSTPCR2, 13, SUB_AREA),
+       [HWBLK_USBF] = HWBLK(MSTPCR2, 11, CORE_AREA),
+       [HWBLK_2DG] = HWBLK(MSTPCR2, 9, CORE_AREA_BM),
+       [HWBLK_SIU] = HWBLK(MSTPCR2, 8, CORE_AREA),
+       [HWBLK_JPU] = HWBLK(MSTPCR2, 6, CORE_AREA_BM),
+       [HWBLK_VOU] = HWBLK(MSTPCR2, 5, CORE_AREA_BM),
+       [HWBLK_BEU] = HWBLK(MSTPCR2, 4, CORE_AREA_BM),
+       [HWBLK_CEU] = HWBLK(MSTPCR2, 3, CORE_AREA_BM),
+       [HWBLK_VEU] = HWBLK(MSTPCR2, 2, CORE_AREA_BM),
+       [HWBLK_VPU] = HWBLK(MSTPCR2, 1, CORE_AREA_BM),
+       [HWBLK_LCDC] = HWBLK(MSTPCR2, 0, CORE_AREA_BM),
+};
+
+static struct hwblk_info sh7722_hwblk_info = {
+       .areas = sh7722_hwblk_area,
+       .nr_areas = ARRAY_SIZE(sh7722_hwblk_area),
+       .hwblks = sh7722_hwblk,
+       .nr_hwblks = ARRAY_SIZE(sh7722_hwblk),
+};
+
+int arch_hwblk_sleep_mode(void)
+{
+       if (!sh7722_hwblk_area[CORE_AREA].cnt[HWBLK_CNT_USAGE])
+               return SUSP_SH_STANDBY | SUSP_SH_SF;
+
+       if (!sh7722_hwblk_area[CORE_AREA_BM].cnt[HWBLK_CNT_USAGE])
+               return SUSP_SH_SLEEP | SUSP_SH_SF;
+
+       return SUSP_SH_SLEEP;
+}
+
+int __init arch_hwblk_init(void)
+{
+       return hwblk_register(&sh7722_hwblk_info);
+}
diff --git a/arch/sh/kernel/cpu/sh4a/hwblk-sh7723.c b/arch/sh/kernel/cpu/sh4a/hwblk-sh7723.c
new file mode 100644 (file)
index 0000000..a7f4684
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * arch/sh/kernel/cpu/sh4a/hwblk-sh7723.c
+ *
+ * SH7723 hardware block support
+ *
+ * Copyright (C) 2009 Magnus Damm
+ *
+ * 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
+ *
+ * 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
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <asm/suspend.h>
+#include <asm/hwblk.h>
+#include <cpu/sh7723.h>
+
+/* SH7723 registers */
+#define MSTPCR0                0xa4150030
+#define MSTPCR1                0xa4150034
+#define MSTPCR2                0xa4150038
+
+/* SH7723 Power Domains */
+enum { CORE_AREA, SUB_AREA, CORE_AREA_BM };
+static struct hwblk_area sh7723_hwblk_area[] = {
+       [CORE_AREA] = HWBLK_AREA(0, 0),
+       [CORE_AREA_BM] = HWBLK_AREA(HWBLK_AREA_FLAG_PARENT, CORE_AREA),
+       [SUB_AREA] = HWBLK_AREA(0, 0),
+};
+
+/* Table mapping HWBLK to Module Stop Bit and Power Domain */
+static struct hwblk sh7723_hwblk[HWBLK_NR] = {
+       [HWBLK_TLB] = HWBLK(MSTPCR0, 31, CORE_AREA),
+       [HWBLK_IC] = HWBLK(MSTPCR0, 30, CORE_AREA),
+       [HWBLK_OC] = HWBLK(MSTPCR0, 29, CORE_AREA),
+       [HWBLK_L2C] = HWBLK(MSTPCR0, 28, CORE_AREA),
+       [HWBLK_ILMEM] = HWBLK(MSTPCR0, 27, CORE_AREA),
+       [HWBLK_FPU] = HWBLK(MSTPCR0, 24, CORE_AREA),
+       [HWBLK_INTC] = HWBLK(MSTPCR0, 22, CORE_AREA),
+       [HWBLK_DMAC0] = HWBLK(MSTPCR0, 21, CORE_AREA_BM),
+       [HWBLK_SHYWAY] = HWBLK(MSTPCR0, 20, CORE_AREA),
+       [HWBLK_HUDI] = HWBLK(MSTPCR0, 19, CORE_AREA),
+       [HWBLK_DBG] = HWBLK(MSTPCR0, 18, CORE_AREA),
+       [HWBLK_UBC] = HWBLK(MSTPCR0, 17, CORE_AREA),
+       [HWBLK_SUBC] = HWBLK(MSTPCR0, 16, CORE_AREA),
+       [HWBLK_TMU0] = HWBLK(MSTPCR0, 15, CORE_AREA),
+       [HWBLK_CMT] = HWBLK(MSTPCR0, 14, SUB_AREA),
+       [HWBLK_RWDT] = HWBLK(MSTPCR0, 13, SUB_AREA),
+       [HWBLK_DMAC1] = HWBLK(MSTPCR0, 12, CORE_AREA_BM),
+       [HWBLK_TMU1] = HWBLK(MSTPCR0, 11, CORE_AREA),
+       [HWBLK_FLCTL] = HWBLK(MSTPCR0, 10, CORE_AREA),
+       [HWBLK_SCIF0] = HWBLK(MSTPCR0, 9, CORE_AREA),
+       [HWBLK_SCIF1] = HWBLK(MSTPCR0, 8, CORE_AREA),
+       [HWBLK_SCIF2] = HWBLK(MSTPCR0, 7, CORE_AREA),
+       [HWBLK_SCIF3] = HWBLK(MSTPCR0, 6, CORE_AREA),
+       [HWBLK_SCIF4] = HWBLK(MSTPCR0, 5, CORE_AREA),
+       [HWBLK_SCIF5] = HWBLK(MSTPCR0, 4, CORE_AREA),
+       [HWBLK_MSIOF0] = HWBLK(MSTPCR0, 2, CORE_AREA),
+       [HWBLK_MSIOF1] = HWBLK(MSTPCR0, 1, CORE_AREA),
+       [HWBLK_MERAM] = HWBLK(MSTPCR0, 0, CORE_AREA),
+
+       [HWBLK_IIC] = HWBLK(MSTPCR1, 9, CORE_AREA),
+       [HWBLK_RTC] = HWBLK(MSTPCR1, 8, SUB_AREA),
+
+       [HWBLK_ATAPI] = HWBLK(MSTPCR2, 28, CORE_AREA_BM),
+       [HWBLK_ADC] = HWBLK(MSTPCR2, 27, CORE_AREA),
+       [HWBLK_TPU] = HWBLK(MSTPCR2, 25, CORE_AREA),
+       [HWBLK_IRDA] = HWBLK(MSTPCR2, 24, CORE_AREA),
+       [HWBLK_TSIF] = HWBLK(MSTPCR2, 22, CORE_AREA),
+       [HWBLK_ICB] = HWBLK(MSTPCR2, 21, CORE_AREA_BM),
+       [HWBLK_SDHI0] = HWBLK(MSTPCR2, 18, CORE_AREA),
+       [HWBLK_SDHI1] = HWBLK(MSTPCR2, 17, CORE_AREA),
+       [HWBLK_KEYSC] = HWBLK(MSTPCR2, 14, SUB_AREA),
+       [HWBLK_USB] = HWBLK(MSTPCR2, 11, CORE_AREA),
+       [HWBLK_2DG] = HWBLK(MSTPCR2, 10, CORE_AREA_BM),
+       [HWBLK_SIU] = HWBLK(MSTPCR2, 8, CORE_AREA),
+       [HWBLK_VEU2H1] = HWBLK(MSTPCR2, 6, CORE_AREA_BM),
+       [HWBLK_VOU] = HWBLK(MSTPCR2, 5, CORE_AREA_BM),
+       [HWBLK_BEU] = HWBLK(MSTPCR2, 4, CORE_AREA_BM),
+       [HWBLK_CEU] = HWBLK(MSTPCR2, 3, CORE_AREA_BM),
+       [HWBLK_VEU2H0] = HWBLK(MSTPCR2, 2, CORE_AREA_BM),
+       [HWBLK_VPU] = HWBLK(MSTPCR2, 1, CORE_AREA_BM),
+       [HWBLK_LCDC] = HWBLK(MSTPCR2, 0, CORE_AREA_BM),
+};
+
+static struct hwblk_info sh7723_hwblk_info = {
+       .areas = sh7723_hwblk_area,
+       .nr_areas = ARRAY_SIZE(sh7723_hwblk_area),
+       .hwblks = sh7723_hwblk,
+       .nr_hwblks = ARRAY_SIZE(sh7723_hwblk),
+};
+
+int arch_hwblk_sleep_mode(void)
+{
+       if (!sh7723_hwblk_area[CORE_AREA].cnt[HWBLK_CNT_USAGE])
+               return SUSP_SH_STANDBY | SUSP_SH_SF;
+
+       if (!sh7723_hwblk_area[CORE_AREA_BM].cnt[HWBLK_CNT_USAGE])
+               return SUSP_SH_SLEEP | SUSP_SH_SF;
+
+       return SUSP_SH_SLEEP;
+}
+
+int __init arch_hwblk_init(void)
+{
+       return hwblk_register(&sh7723_hwblk_info);
+}
index c18f7d0..f6d2088 100644 (file)
@@ -40,7 +40,7 @@ static struct platform_device iic_device = {
 };
 
 static struct r8a66597_platdata r8a66597_data = {
-       /* This set zero to all members */
+       .on_chip = 1,
 };
 
 static struct resource usb_host_resources[] = {
index e1bb80b..2851649 100644 (file)
@@ -398,7 +398,7 @@ static struct platform_device rtc_device = {
 };
 
 static struct r8a66597_platdata r8a66597_data = {
-       /* This set zero to all members */
+       .on_chip = 1,
 };
 
 static struct resource sh7723_usb_host_resources[] = {
index 08bfa7c..e8a5111 100644 (file)
@@ -4,3 +4,4 @@
 
 # Power Management & Sleep mode
 obj-$(CONFIG_PM)       += pm.o sleep.o
+obj-$(CONFIG_CPU_IDLE) += cpuidle.o
diff --git a/arch/sh/kernel/cpu/shmobile/cpuidle.c b/arch/sh/kernel/cpu/shmobile/cpuidle.c
new file mode 100644 (file)
index 0000000..4afdd97
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * arch/sh/kernel/cpu/shmobile/cpuidle.c
+ *
+ * Cpuidle support code for SuperH Mobile
+ *
+ *  Copyright (C) 2009 Magnus Damm
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/suspend.h>
+#include <linux/cpuidle.h>
+#include <asm/suspend.h>
+#include <asm/uaccess.h>
+#include <asm/hwblk.h>
+
+static unsigned long cpuidle_mode[] = {
+       SUSP_SH_SLEEP, /* regular sleep mode */
+       SUSP_SH_SLEEP | SUSP_SH_SF, /* sleep mode + self refresh */
+};
+
+static int cpuidle_sleep_enter(struct cpuidle_device *dev,
+                              struct cpuidle_state *state)
+{
+       unsigned long allowed_mode = arch_hwblk_sleep_mode();
+       ktime_t before, after;
+       int requested_state = state - &dev->states[0];
+       int allowed_state;
+       int k;
+
+       /* convert allowed mode to allowed state */
+       for (k = ARRAY_SIZE(cpuidle_mode) - 1; k > 0; k--)
+               if (cpuidle_mode[k] == allowed_mode)
+                       break;
+
+       allowed_state = k;
+
+       /* take the following into account for sleep mode selection:
+        * - allowed_state: best mode allowed by hardware (clock deps)
+        * - requested_state: best mode allowed by software (latencies)
+        */
+       k = min_t(int, allowed_state, requested_state);
+
+       dev->last_state = &dev->states[k];
+       before = ktime_get();
+       sh_mobile_call_standby(cpuidle_mode[k]);
+       after = ktime_get();
+       return ktime_to_ns(ktime_sub(after, before)) >> 10;
+}
+
+static struct cpuidle_device cpuidle_dev;
+static struct cpuidle_driver cpuidle_driver = {
+       .name =         "sh_idle",
+       .owner =        THIS_MODULE,
+};
+
+void sh_mobile_setup_cpuidle(void)
+{
+       struct cpuidle_device *dev = &cpuidle_dev;
+       struct cpuidle_state *state;
+       int i;
+
+       cpuidle_register_driver(&cpuidle_driver);
+
+       for (i = 0; i < CPUIDLE_STATE_MAX; i++) {
+               dev->states[i].name[0] = '\0';
+               dev->states[i].desc[0] = '\0';
+       }
+
+       i = CPUIDLE_DRIVER_STATE_START;
+
+       state = &dev->states[i++];
+       snprintf(state->name, CPUIDLE_NAME_LEN, "C0");
+       strncpy(state->desc, "SuperH Sleep Mode", CPUIDLE_DESC_LEN);
+       state->exit_latency = 1;
+       state->target_residency = 1 * 2;
+       state->power_usage = 3;
+       state->flags = 0;
+       state->flags |= CPUIDLE_FLAG_SHALLOW;
+       state->flags |= CPUIDLE_FLAG_TIME_VALID;
+       state->enter = cpuidle_sleep_enter;
+
+       dev->safe_state = state;
+
+       state = &dev->states[i++];
+       snprintf(state->name, CPUIDLE_NAME_LEN, "C1");
+       strncpy(state->desc, "SuperH Sleep Mode [SF]", CPUIDLE_DESC_LEN);
+       state->exit_latency = 100;
+       state->target_residency = 1 * 2;
+       state->power_usage = 1;
+       state->flags = 0;
+       state->flags |= CPUIDLE_FLAG_TIME_VALID;
+       state->enter = cpuidle_sleep_enter;
+
+       dev->state_count = i;
+
+       cpuidle_register_device(dev);
+}
index 8c067ad..de078d2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * arch/sh/kernel/cpu/sh4a/pm-sh_mobile.c
+ * arch/sh/kernel/cpu/shmobile/pm.c
  *
  * Power management support code for SuperH Mobile
  *
  *
  * R-standby mode is unsupported, but will be added in the future
  * U-standby mode is low priority since it needs bootloader hacks
- *
- * All modes should be tied in with cpuidle. But before that can
- * happen we need to keep track of enabled hardware blocks so we
- * can avoid entering sleep modes that stop clocks to hardware
- * blocks that are in use even though the cpu core is idle.
  */
 
+#define ILRAM_BASE 0xe5200000
+
 extern const unsigned char sh_mobile_standby[];
 extern const unsigned int sh_mobile_standby_size;
 
-static void sh_mobile_call_standby(unsigned long mode)
+void sh_mobile_call_standby(unsigned long mode)
 {
        extern void *vbr_base;
-       void *onchip_mem = (void *)0xe5200000; /* ILRAM */
+       void *onchip_mem = (void *)ILRAM_BASE;
        void (*standby_onchip_mem)(unsigned long) = onchip_mem;
 
        /* Note: Wake up from sleep may generate exceptions!
@@ -55,11 +52,6 @@ static void sh_mobile_call_standby(unsigned long mode)
        if (mode & SUSP_SH_SF)
                asm volatile("ldc %0, vbr" : : "r" (onchip_mem) : "memory");
 
-       /* Copy the assembly snippet to the otherwise ununsed ILRAM */
-       memcpy(onchip_mem, sh_mobile_standby, sh_mobile_standby_size);
-       wmb();
-       ctrl_barrier();
-
        /* Let assembly snippet in on-chip memory handle the rest */
        standby_onchip_mem(mode);
 
@@ -85,7 +77,15 @@ static struct platform_suspend_ops sh_pm_ops = {
 
 static int __init sh_pm_init(void)
 {
+       void *onchip_mem = (void *)ILRAM_BASE;
+
+       /* Copy the assembly snippet to the otherwise ununsed ILRAM */
+       memcpy(onchip_mem, sh_mobile_standby, sh_mobile_standby_size);
+       wmb();
+       ctrl_barrier();
+
        suspend_set_ops(&sh_pm_ops);
+       sh_mobile_setup_cpuidle();
        return 0;
 }
 
index d62359c..d621756 100644 (file)
@@ -131,7 +131,7 @@ ENTRY(resume_userspace)
         nop
 #endif
        mov.l   @(TI_FLAGS,r8), r0              ! current_thread_info->flags
-       tst     #_TIF_WORK_MASK, r0
+       tst     #(_TIF_WORK_MASK & 0xff), r0
        bt/s    __restore_all
         tst    #_TIF_NEED_RESCHED, r0
 
@@ -163,7 +163,7 @@ work_resched:
 #endif
        !
        mov.l   @(TI_FLAGS,r8), r0              ! current_thread_info->flags
-       tst     #_TIF_WORK_MASK, r0
+       tst     #(_TIF_WORK_MASK & 0xff), r0
        bt      __restore_all
        bra     work_pending
         tst    #_TIF_NEED_RESCHED, r0
@@ -181,7 +181,7 @@ work_resched:
 syscall_exit_work:
        ! r0: current_thread_info->flags
        ! r8: current_thread_info
-       tst     #_TIF_WORK_SYSCALL_MASK, r0
+       tst     #(_TIF_WORK_SYSCALL_MASK & 0xff), r0
        bt/s    work_pending
         tst    #_TIF_NEED_RESCHED, r0
 #ifdef CONFIG_TRACE_IRQFLAGS
@@ -331,8 +331,12 @@ ENTRY(system_call)
        !
        get_current_thread_info r8, r10
        mov.l   @(TI_FLAGS,r8), r8
-       mov     #_TIF_WORK_SYSCALL_MASK, r10
+       mov     #(_TIF_WORK_SYSCALL_MASK & 0xff), r10
+       mov     #(_TIF_WORK_SYSCALL_MASK >> 8), r9
        tst     r10, r8
+       shll8   r9
+       bf      syscall_trace_entry
+       tst     r9, r8
        bf      syscall_trace_entry
        !
        mov.l   2f, r8                  ! Number of syscalls
@@ -359,7 +363,11 @@ syscall_exit:
        !
        get_current_thread_info r8, r0
        mov.l   @(TI_FLAGS,r8), r0              ! current_thread_info->flags
-       tst     #_TIF_ALLWORK_MASK, r0
+       tst     #(_TIF_ALLWORK_MASK & 0xff), r0
+       mov     #(_TIF_ALLWORK_MASK >> 8), r1
+       bf      syscall_exit_work
+       shlr8   r0
+       tst     r0, r1
        bf      syscall_exit_work
        bra     __restore_all
         nop
index 066f37d..6647dfc 100644 (file)
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/kernel.h>
 #include <asm/ftrace.h>
 #include <asm/cacheflush.h>
+#include <asm/unistd.h>
+#include <trace/syscall.h>
 
+#ifdef CONFIG_DYNAMIC_FTRACE
 static unsigned char ftrace_replaced_code[MCOUNT_INSN_SIZE];
 
 static unsigned char ftrace_nop[4];
@@ -131,3 +135,189 @@ int __init ftrace_dyn_arch_init(void *data)
 
        return 0;
 }
+#endif /* CONFIG_DYNAMIC_FTRACE */
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+#ifdef CONFIG_DYNAMIC_FTRACE
+extern void ftrace_graph_call(void);
+
+static int ftrace_mod(unsigned long ip, unsigned long old_addr,
+                     unsigned long new_addr)
+{
+       unsigned char code[MCOUNT_INSN_SIZE];
+
+       if (probe_kernel_read(code, (void *)ip, MCOUNT_INSN_SIZE))
+               return -EFAULT;
+
+       if (old_addr != __raw_readl((unsigned long *)code))
+               return -EINVAL;
+
+       __raw_writel(new_addr, ip);
+       return 0;
+}
+
+int ftrace_enable_ftrace_graph_caller(void)
+{
+       unsigned long ip, old_addr, new_addr;
+
+       ip = (unsigned long)(&ftrace_graph_call) + GRAPH_INSN_OFFSET;
+       old_addr = (unsigned long)(&skip_trace);
+       new_addr = (unsigned long)(&ftrace_graph_caller);
+
+       return ftrace_mod(ip, old_addr, new_addr);
+}
+
+int ftrace_disable_ftrace_graph_caller(void)
+{
+       unsigned long ip, old_addr, new_addr;
+
+       ip = (unsigned long)(&ftrace_graph_call) + GRAPH_INSN_OFFSET;
+       old_addr = (unsigned long)(&ftrace_graph_caller);
+       new_addr = (unsigned long)(&skip_trace);
+
+       return ftrace_mod(ip, old_addr, new_addr);
+}
+#endif /* CONFIG_DYNAMIC_FTRACE */
+
+/*
+ * Hook the return address and push it in the stack of return addrs
+ * in the current thread info.
+ *
+ * This is the main routine for the function graph tracer. The function
+ * graph tracer essentially works like this:
+ *
+ * parent is the stack address containing self_addr's return address.
+ * We pull the real return address out of parent and store it in
+ * current's ret_stack. Then, we replace the return address on the stack
+ * with the address of return_to_handler. self_addr is the function that
+ * called mcount.
+ *
+ * When self_addr returns, it will jump to return_to_handler which calls
+ * ftrace_return_to_handler. ftrace_return_to_handler will pull the real
+ * return address off of current's ret_stack and jump to it.
+ */
+void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
+{
+       unsigned long old;
+       int faulted, err;
+       struct ftrace_graph_ent trace;
+       unsigned long return_hooker = (unsigned long)&return_to_handler;
+
+       if (unlikely(atomic_read(&current->tracing_graph_pause)))
+               return;
+
+       /*
+        * Protect against fault, even if it shouldn't
+        * happen. This tool is too much intrusive to
+        * ignore such a protection.
+        */
+       __asm__ __volatile__(
+               "1:                                             \n\t"
+               "mov.l          @%2, %0                         \n\t"
+               "2:                                             \n\t"
+               "mov.l          %3, @%2                         \n\t"
+               "mov            #0, %1                          \n\t"
+               "3:                                             \n\t"
+               ".section .fixup, \"ax\"                        \n\t"
+               "4:                                             \n\t"
+               "mov.l          5f, %0                          \n\t"
+               "jmp            @%0                             \n\t"
+               " mov           #1, %1                          \n\t"
+               ".balign 4                                      \n\t"
+               "5:     .long 3b                                \n\t"
+               ".previous                                      \n\t"
+               ".section __ex_table,\"a\"                      \n\t"
+               ".long 1b, 4b                                   \n\t"
+               ".long 2b, 4b                                   \n\t"
+               ".previous                                      \n\t"
+               : "=&r" (old), "=r" (faulted)
+               : "r" (parent), "r" (return_hooker)
+       );
+
+       if (unlikely(faulted)) {
+               ftrace_graph_stop();
+               WARN_ON(1);
+               return;
+       }
+
+       err = ftrace_push_return_trace(old, self_addr, &trace.depth, 0);
+       if (err == -EBUSY) {
+               __raw_writel(old, parent);
+               return;
+       }
+
+       trace.func = self_addr;
+
+       /* Only trace if the calling function expects to */
+       if (!ftrace_graph_entry(&trace)) {
+               current->curr_ret_stack--;
+               __raw_writel(old, parent);
+       }
+}
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
+#ifdef CONFIG_FTRACE_SYSCALLS
+
+extern unsigned long __start_syscalls_metadata[];
+extern unsigned long __stop_syscalls_metadata[];
+extern unsigned long *sys_call_table;
+
+static struct syscall_metadata **syscalls_metadata;
+
+static struct syscall_metadata *find_syscall_meta(unsigned long *syscall)
+{
+       struct syscall_metadata *start;
+       struct syscall_metadata *stop;
+       char str[KSYM_SYMBOL_LEN];
+
+
+       start = (struct syscall_metadata *)__start_syscalls_metadata;
+       stop = (struct syscall_metadata *)__stop_syscalls_metadata;
+       kallsyms_lookup((unsigned long) syscall, NULL, NULL, NULL, str);
+
+       for ( ; start < stop; start++) {
+               if (start->name && !strcmp(start->name, str))
+                       return start;
+       }
+
+       return NULL;
+}
+
+#define FTRACE_SYSCALL_MAX     (NR_syscalls - 1)
+
+struct syscall_metadata *syscall_nr_to_meta(int nr)
+{
+       if (!syscalls_metadata || nr >= FTRACE_SYSCALL_MAX || nr < 0)
+               return NULL;
+
+       return syscalls_metadata[nr];
+}
+
+void arch_init_ftrace_syscalls(void)
+{
+       int i;
+       struct syscall_metadata *meta;
+       unsigned long **psys_syscall_table = &sys_call_table;
+       static atomic_t refs;
+
+       if (atomic_inc_return(&refs) != 1)
+               goto end;
+
+       syscalls_metadata = kzalloc(sizeof(*syscalls_metadata) *
+                                       FTRACE_SYSCALL_MAX, GFP_KERNEL);
+       if (!syscalls_metadata) {
+               WARN_ON(1);
+               return;
+       }
+
+       for (i = 0; i < FTRACE_SYSCALL_MAX; i++) {
+               meta = find_syscall_meta(psys_syscall_table[i]);
+               syscalls_metadata[i] = meta;
+       }
+       return;
+
+       /* Paranoid: avoid overflow */
+end:
+       atomic_dec(&refs);
+}
+#endif /* CONFIG_FTRACE_SYSCALLS */
index 3d09062..278c68c 100644 (file)
@@ -114,23 +114,6 @@ asmlinkage int do_IRQ(unsigned int irq, struct pt_regs *regs)
 #endif
 
        irq_enter();
-
-#ifdef CONFIG_DEBUG_STACKOVERFLOW
-       /* Debugging check for stack overflow: is there less than 1KB free? */
-       {
-               long sp;
-
-               __asm__ __volatile__ ("and r15, %0" :
-                                       "=r" (sp) : "0" (THREAD_SIZE - 1));
-
-               if (unlikely(sp < (sizeof(struct thread_info) + STACK_WARN))) {
-                       printk("do_IRQ: stack overflow: %ld\n",
-                              sp - sizeof(struct thread_info));
-                       dump_stack();
-               }
-       }
-#endif
-
        irq = irq_demux(intc_evt2irq(irq));
 
 #ifdef CONFIG_IRQSTACKS
index 92d7740..9fee977 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/tick.h>
 #include <linux/reboot.h>
 #include <linux/fs.h>
+#include <linux/ftrace.h>
 #include <linux/preempt.h>
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
@@ -264,8 +265,8 @@ static void ubc_set_tracing(int asid, unsigned long pc)
  *     switch_to(x,y) should switch tasks from x to y.
  *
  */
-struct task_struct *__switch_to(struct task_struct *prev,
-                               struct task_struct *next)
+__notrace_funcgraph struct task_struct *
+__switch_to(struct task_struct *prev, struct task_struct *next)
 {
 #if defined(CONFIG_SH_FPU)
        unlazy_fpu(prev, task_pt_regs(prev));
index 3392e83..c198ece 100644 (file)
@@ -34,6 +34,8 @@
 #include <asm/syscalls.h>
 #include <asm/fpu.h>
 
+#include <trace/syscall.h>
+
 /*
  * This routine will get a word off of the process kernel stack.
  */
@@ -459,6 +461,9 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
                 */
                ret = -1L;
 
+       if (unlikely(test_thread_flag(TIF_SYSCALL_FTRACE)))
+               ftrace_syscall_enter(regs);
+
        if (unlikely(current->audit_context))
                audit_syscall_entry(audit_arch(), regs->regs[3],
                                    regs->regs[4], regs->regs[5],
@@ -475,6 +480,9 @@ asmlinkage void do_syscall_trace_leave(struct pt_regs *regs)
                audit_syscall_exit(AUDITSC_RESULT(regs->regs[0]),
                                   regs->regs[0]);
 
+       if (unlikely(test_thread_flag(TIF_SYSCALL_FTRACE)))
+               ftrace_syscall_exit(regs);
+
        step = test_thread_flag(TIF_SINGLESTEP);
        if (step || test_thread_flag(TIF_SYSCALL_TRACE))
                tracehook_report_syscall_exit(regs, step);
index dd38338..ceb409b 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
+#include <linux/lmb.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/page.h>
@@ -233,39 +234,45 @@ void __init __add_active_range(unsigned int nid, unsigned long start_pfn,
 void __init setup_bootmem_allocator(unsigned long free_pfn)
 {
        unsigned long bootmap_size;
+       unsigned long bootmap_pages, bootmem_paddr;
+       u64 total_pages = (lmb_end_of_DRAM() - __MEMORY_START) >> PAGE_SHIFT;
+       int i;
+
+       bootmap_pages = bootmem_bootmap_pages(total_pages);
+
+       bootmem_paddr = lmb_alloc(bootmap_pages << PAGE_SHIFT, PAGE_SIZE);
 
        /*
         * Find a proper area for the bootmem bitmap. After this
         * bootstrap step all allocations (until the page allocator
         * is intact) must be done via bootmem_alloc().
         */
-       bootmap_size = init_bootmem_node(NODE_DATA(0), free_pfn,
+       bootmap_size = init_bootmem_node(NODE_DATA(0),
+                                        bootmem_paddr >> PAGE_SHIFT,
                                         min_low_pfn, max_low_pfn);
 
-       __add_active_range(0, min_low_pfn, max_low_pfn);
-       register_bootmem_low_pages();
-
-       node_set_online(0);
+       /* Add active regions with valid PFNs. */
+       for (i = 0; i < lmb.memory.cnt; i++) {
+               unsigned long start_pfn, end_pfn;
+               start_pfn = lmb.memory.region[i].base >> PAGE_SHIFT;
+               end_pfn = start_pfn + lmb_size_pages(&lmb.memory, i);
+               __add_active_range(0, start_pfn, end_pfn);
+       }
 
        /*
-        * Reserve the kernel text and
-        * Reserve the bootmem bitmap. We do this in two steps (first step
-        * was init_bootmem()), because this catches the (definitely buggy)
-        * case of us accidentally initializing the bootmem allocator with
-        * an invalid RAM area.
+        * Add all physical memory to the bootmem map and mark each
+        * area as present.
         */
-       reserve_bootmem(__MEMORY_START + CONFIG_ZERO_PAGE_OFFSET,
-                       (PFN_PHYS(free_pfn) + bootmap_size + PAGE_SIZE - 1) -
-                       (__MEMORY_START + CONFIG_ZERO_PAGE_OFFSET),
-                       BOOTMEM_DEFAULT);
+       register_bootmem_low_pages();
 
-       /*
-        * Reserve physical pages below CONFIG_ZERO_PAGE_OFFSET.
-        */
-       if (CONFIG_ZERO_PAGE_OFFSET != 0)
-               reserve_bootmem(__MEMORY_START, CONFIG_ZERO_PAGE_OFFSET,
+       /* Reserve the sections we're already using. */
+       for (i = 0; i < lmb.reserved.cnt; i++)
+               reserve_bootmem(lmb.reserved.region[i].base,
+                               lmb_size_bytes(&lmb.reserved, i),
                                BOOTMEM_DEFAULT);
 
+       node_set_online(0);
+
        sparse_memory_present_with_active_regions(0);
 
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -296,12 +303,37 @@ void __init setup_bootmem_allocator(unsigned long free_pfn)
 static void __init setup_memory(void)
 {
        unsigned long start_pfn;
+       u64 base = min_low_pfn << PAGE_SHIFT;
+       u64 size = (max_low_pfn << PAGE_SHIFT) - base;
 
        /*
         * Partially used pages are not usable - thus
         * we are rounding upwards:
         */
        start_pfn = PFN_UP(__pa(_end));
+
+       lmb_add(base, size);
+
+       /*
+        * Reserve the kernel text and
+        * Reserve the bootmem bitmap. We do this in two steps (first step
+        * was init_bootmem()), because this catches the (definitely buggy)
+        * case of us accidentally initializing the bootmem allocator with
+        * an invalid RAM area.
+        */
+       lmb_reserve(__MEMORY_START + CONFIG_ZERO_PAGE_OFFSET,
+                   (PFN_PHYS(start_pfn) + PAGE_SIZE - 1) -
+                   (__MEMORY_START + CONFIG_ZERO_PAGE_OFFSET));
+
+       /*
+        * Reserve physical pages below CONFIG_ZERO_PAGE_OFFSET.
+        */
+       if (CONFIG_ZERO_PAGE_OFFSET != 0)
+               lmb_reserve(__MEMORY_START, CONFIG_ZERO_PAGE_OFFSET);
+
+       lmb_analyze();
+       lmb_dump_all();
+
        setup_bootmem_allocator(start_pfn);
 }
 #else
@@ -402,6 +434,7 @@ void __init setup_arch(char **cmdline_p)
        nodes_clear(node_online_map);
 
        /* Setup bootmem with available RAM */
+       lmb_init();
        setup_memory();
        sparse_init();
 
index fcc5de3..cec6108 100644 (file)
@@ -106,8 +106,8 @@ EXPORT_SYMBOL(flush_dcache_page);
 EXPORT_SYMBOL(clear_user_page);
 #endif
 
-#ifdef CONFIG_FUNCTION_TRACER
-EXPORT_SYMBOL(mcount);
+#ifdef CONFIG_MCOUNT
+DECLARE_EXPORT(mcount);
 #endif
 EXPORT_SYMBOL(csum_partial);
 EXPORT_SYMBOL(csum_partial_copy_generic);
index 9b352a1..d2424b0 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/smp.h>
 #include <linux/rtc.h>
 #include <asm/clock.h>
+#include <asm/hwblk.h>
 #include <asm/rtc.h>
 
 /* Dummy RTC ops */
@@ -96,6 +97,7 @@ void __init time_init(void)
        if (board_time_init)
                board_time_init();
 
+       hwblk_init();
        clk_init();
 
        rtc_sh_get_time(&xtime);
index f53c76a..80dc9f8 100644 (file)
@@ -50,12 +50,7 @@ SECTIONS
                _etext = .;             /* End of text section */
        } = 0x0009
 
-       . = ALIGN(16);          /* Exception table */
-       __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) {
-               __start___ex_table = .;
-               *(__ex_table)
-               __stop___ex_table = .;
-       }
+       EXCEPTION_TABLE(16)
 
        NOTES
        RO_DATA(PAGE_SIZE)
@@ -71,69 +66,14 @@ SECTIONS
                __uncached_end = .;
        }
 
-       . = ALIGN(THREAD_SIZE);
-       .data : AT(ADDR(.data) - LOAD_OFFSET) {         /* Data */
-               *(.data.init_task)
-
-               . = ALIGN(L1_CACHE_BYTES);
-               *(.data.cacheline_aligned)
-
-               . = ALIGN(L1_CACHE_BYTES);
-               *(.data.read_mostly)
-
-               . = ALIGN(PAGE_SIZE);
-               *(.data.page_aligned)
-
-               __nosave_begin = .;
-               *(.data.nosave)
-               . = ALIGN(PAGE_SIZE);
-               __nosave_end = .;
-
-               DATA_DATA
-               CONSTRUCTORS
-       }
+       RW_DATA_SECTION(L1_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE)
 
        _edata = .;                     /* End of data section */
 
        . = ALIGN(PAGE_SIZE);           /* Init code and data */
-       .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(PAGE_SIZE);
-       .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) {
-               __initramfs_start = .;
-               *(.init.ramfs)
-               __initramfs_end = .;
-       }
-#endif
+       __init_begin = .;
+       INIT_TEXT_SECTION(PAGE_SIZE)
+       INIT_DATA_SECTION(16)
 
        . = ALIGN(4);
        .machvec.init : AT(ADDR(.machvec.init) - LOAD_OFFSET) {
@@ -152,16 +92,10 @@ SECTIONS
        .exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) { EXIT_DATA }
 
        . = ALIGN(PAGE_SIZE);
-       .bss : AT(ADDR(.bss) - LOAD_OFFSET) {
-               __init_end = .;
-               __bss_start = .;                /* BSS */
-               *(.bss.page_aligned)
-               *(.bss)
-               *(COMMON)
-               . = ALIGN(4);
-               _ebss = .;                      /* uClinux MTD sucks */
-               _end = . ;
-       }
+       __init_end = .;
+       BSS_SECTION(0, PAGE_SIZE, 4)
+       _ebss = .;                      /* uClinux MTD sucks */
+       _end = . ;
 
        /*
         * When something in the kernel is NOT compiled as a module, the
@@ -170,7 +104,7 @@ SECTIONS
         * it's a module.
         */
        /DISCARD/ : {
-               *(.exitcall.exit)
+               EXIT_CALL
        }
 
        STABS_DEBUG
index aaea580..c2b28d8 100644 (file)
@@ -24,7 +24,7 @@ memcpy-y                      := memcpy.o
 memcpy-$(CONFIG_CPU_SH4)       := memcpy-sh4.o
 
 lib-$(CONFIG_MMU)              += copy_page.o clear_page.o
-lib-$(CONFIG_FUNCTION_TRACER)  += mcount.o
+lib-$(CONFIG_MCOUNT)           += mcount.o
 lib-y                          += $(memcpy-y) $(udivsi3-y)
 
 EXTRA_CFLAGS += -Werror
index 110fbfe..84a5776 100644 (file)
@@ -1,14 +1,16 @@
 /*
  * arch/sh/lib/mcount.S
  *
- *  Copyright (C) 2008  Paul Mundt
- *  Copyright (C) 2008  Matt Fleming
+ *  Copyright (C) 2008, 2009  Paul Mundt
+ *  Copyright (C) 2008, 2009  Matt Fleming
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  */
 #include <asm/ftrace.h>
+#include <asm/thread_info.h>
+#include <asm/asm-offsets.h>
 
 #define MCOUNT_ENTER()         \
        mov.l   r4, @-r15;      \
        rts;                    \
         mov.l  @r15+, r4
 
+#ifdef CONFIG_STACK_DEBUG
+/*
+ * Perform diagnostic checks on the state of the kernel stack.
+ *
+ * Check for stack overflow. If there is less than 1KB free
+ * then it has overflowed.
+ *
+ * Make sure the stack pointer contains a valid address. Valid
+ * addresses for kernel stacks are anywhere after the bss
+ * (after _ebss) and anywhere in init_thread_union (init_stack).
+ */
+#define STACK_CHECK()                                  \
+       mov     #(THREAD_SIZE >> 10), r0;               \
+       shll8   r0;                                     \
+       shll2   r0;                                     \
+                                                       \
+       /* r1 = sp & (THREAD_SIZE - 1) */               \
+       mov     #-1, r1;                                \
+       add     r0, r1;                                 \
+       and     r15, r1;                                \
+                                                       \
+       mov     #TI_SIZE, r3;                           \
+       mov     #(STACK_WARN >> 8), r2;                 \
+       shll8   r2;                                     \
+       add     r3, r2;                                 \
+                                                       \
+       /* Is the stack overflowing? */                 \
+       cmp/hi  r2, r1;                                 \
+       bf      stack_panic;                            \
+                                                       \
+       /* If sp > _ebss then we're OK. */              \
+       mov.l   .L_ebss, r1;                            \
+       cmp/hi  r1, r15;                                \
+       bt      1f;                                     \
+                                                       \
+       /* If sp < init_stack, we're not OK. */         \
+       mov.l   .L_init_thread_union, r1;               \
+       cmp/hs  r1, r15;                                \
+       bf      stack_panic;                            \
+                                                       \
+       /* If sp > init_stack && sp < _ebss, not OK. */ \
+       add     r0, r1;                                 \
+       cmp/hs  r1, r15;                                \
+       bt      stack_panic;                            \
+1:
+#else
+#define STACK_CHECK()
+#endif /* CONFIG_STACK_DEBUG */
+
        .align 2
        .globl  _mcount
        .type   _mcount,@function
        .type   mcount,@function
 _mcount:
 mcount:
+       STACK_CHECK()
+
+#ifndef CONFIG_FUNCTION_TRACER
+       rts
+        nop
+#else
+#ifndef CONFIG_DYNAMIC_FTRACE
+       mov.l   .Lfunction_trace_stop, r0
+       mov.l   @r0, r0
+       tst     r0, r0
+       bf      ftrace_stub
+#endif
+
        MCOUNT_ENTER()
 
 #ifdef CONFIG_DYNAMIC_FTRACE
@@ -52,16 +116,69 @@ mcount_call:
        jsr     @r6
         nop
 
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       mov.l   .Lftrace_graph_return, r6
+       mov.l   .Lftrace_stub, r7
+       cmp/eq  r6, r7
+       bt      1f
+
+       mov.l   .Lftrace_graph_caller, r0
+       jmp     @r0
+        nop
+
+1:
+       mov.l   .Lftrace_graph_entry, r6
+       mov.l   .Lftrace_graph_entry_stub, r7
+       cmp/eq  r6, r7
+       bt      skip_trace
+
+       mov.l   .Lftrace_graph_caller, r0
+       jmp     @r0
+        nop
+
+       .align 2
+.Lftrace_graph_return:
+       .long   ftrace_graph_return
+.Lftrace_graph_entry:
+       .long   ftrace_graph_entry
+.Lftrace_graph_entry_stub:
+       .long   ftrace_graph_entry_stub
+.Lftrace_graph_caller:
+       .long   ftrace_graph_caller
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
+       .globl skip_trace
 skip_trace:
        MCOUNT_LEAVE()
 
        .align 2
 .Lftrace_trace_function:
-       .long   ftrace_trace_function
+       .long   ftrace_trace_function
 
 #ifdef CONFIG_DYNAMIC_FTRACE
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+/*
+ * NOTE: Do not move either ftrace_graph_call or ftrace_caller
+ * as this will affect the calculation of GRAPH_INSN_OFFSET.
+ */
+       .globl ftrace_graph_call
+ftrace_graph_call:
+       mov.l   .Lskip_trace, r0
+       jmp     @r0
+        nop
+
+       .align 2
+.Lskip_trace:
+       .long   skip_trace
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
        .globl ftrace_caller
 ftrace_caller:
+       mov.l   .Lfunction_trace_stop, r0
+       mov.l   @r0, r0
+       tst     r0, r0
+       bf      ftrace_stub
+
        MCOUNT_ENTER()
 
        .globl ftrace_call
@@ -70,9 +187,18 @@ ftrace_call:
        jsr     @r6
         nop
 
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       bra     ftrace_graph_call
+        nop
+#else
        MCOUNT_LEAVE()
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
 #endif /* CONFIG_DYNAMIC_FTRACE */
 
+       .align 2
+.Lfunction_trace_stop:
+       .long   function_trace_stop
+
 /*
  * NOTE: From here on the locations of the .Lftrace_stub label and
  * ftrace_stub itself are fixed. Adding additional data here will skew
@@ -80,7 +206,6 @@ ftrace_call:
  * Place new labels either after the ftrace_stub body, or before
  * ftrace_caller. You have been warned.
  */
-       .align 2
 .Lftrace_stub:
        .long   ftrace_stub
 
@@ -88,3 +213,98 @@ ftrace_call:
 ftrace_stub:
        rts
         nop
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       .globl  ftrace_graph_caller
+ftrace_graph_caller:
+       mov.l   2f, r0
+       mov.l   @r0, r0
+       tst     r0, r0
+       bt      1f
+
+       mov.l   3f, r1
+       jmp     @r1
+        nop
+1:
+       /*
+        * MCOUNT_ENTER() pushed 5 registers onto the stack, so
+        * the stack address containing our return address is
+        * r15 + 20.
+        */
+       mov     #20, r0
+       add     r15, r0
+       mov     r0, r4
+
+       mov.l   .Lprepare_ftrace_return, r0
+       jsr     @r0
+        nop
+
+       MCOUNT_LEAVE()
+
+       .align 2
+2:     .long   function_trace_stop
+3:     .long   skip_trace
+.Lprepare_ftrace_return:
+       .long   prepare_ftrace_return
+
+       .globl  return_to_handler
+return_to_handler:
+       /*
+        * Save the return values.
+        */
+       mov.l   r0, @-r15
+       mov.l   r1, @-r15
+
+       mov     #0, r4
+
+       mov.l   .Lftrace_return_to_handler, r0
+       jsr     @r0
+        nop
+
+       /*
+        * The return value from ftrace_return_handler has the real
+        * address that we should return to.
+        */
+       lds     r0, pr
+       mov.l   @r15+, r1
+       rts
+        mov.l  @r15+, r0
+
+
+       .align 2
+.Lftrace_return_to_handler:
+       .long   ftrace_return_to_handler
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+#endif /* CONFIG_FUNCTION_TRACER */
+
+#ifdef CONFIG_STACK_DEBUG
+       .globl  stack_panic
+stack_panic:
+       mov.l   .Ldump_stack, r0
+       jsr     @r0
+        nop
+
+       mov.l   .Lpanic, r0
+       jsr     @r0
+        mov.l  .Lpanic_s, r4
+
+       rts
+        nop
+
+       .align 2
+.L_ebss:
+       .long   _ebss
+.L_init_thread_union:
+       .long   init_thread_union
+.Lpanic:
+       .long   panic
+.Lpanic_s:
+       .long   .Lpanic_str
+.Ldump_stack:
+       .long   dump_stack
+
+       .section        .rodata
+       .align 2
+.Lpanic_str:
+       .string "Stack error"
+#endif /* CONFIG_STACK_DEBUG */
index 7192594..dbbdeba 100644 (file)
@@ -2,7 +2,7 @@
  * Page fault handler for SH with an MMU.
  *
  *  Copyright (C) 1999  Niibe Yutaka
- *  Copyright (C) 2003 - 2008  Paul Mundt
+ *  Copyright (C) 2003 - 2009  Paul Mundt
  *
  *  Based on linux/arch/i386/mm/fault.c:
  *   Copyright (C) 1995  Linus Torvalds
@@ -25,18 +25,91 @@ static inline int notify_page_fault(struct pt_regs *regs, int trap)
 {
        int ret = 0;
 
-#ifdef CONFIG_KPROBES
-       if (!user_mode(regs)) {
+       if (kprobes_built_in() && !user_mode(regs)) {
                preempt_disable();
                if (kprobe_running() && kprobe_fault_handler(regs, trap))
                        ret = 1;
                preempt_enable();
        }
-#endif
 
        return ret;
 }
 
+static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address)
+{
+       unsigned index = pgd_index(address);
+       pgd_t *pgd_k;
+       pud_t *pud, *pud_k;
+       pmd_t *pmd, *pmd_k;
+
+       pgd += index;
+       pgd_k = init_mm.pgd + index;
+
+       if (!pgd_present(*pgd_k))
+               return NULL;
+
+       pud = pud_offset(pgd, address);
+       pud_k = pud_offset(pgd_k, address);
+       if (!pud_present(*pud_k))
+               return NULL;
+
+       pmd = pmd_offset(pud, address);
+       pmd_k = pmd_offset(pud_k, address);
+       if (!pmd_present(*pmd_k))
+               return NULL;
+
+       if (!pmd_present(*pmd))
+               set_pmd(pmd, *pmd_k);
+       else {
+               /*
+                * The page tables are fully synchronised so there must
+                * be another reason for the fault. Return NULL here to
+                * signal that we have not taken care of the fault.
+                */
+               BUG_ON(pmd_page(*pmd) != pmd_page(*pmd_k));
+               return NULL;
+       }
+
+       return pmd_k;
+}
+
+/*
+ * Handle a fault on the vmalloc or module mapping area
+ */
+static noinline int vmalloc_fault(unsigned long address)
+{
+       pgd_t *pgd_k;
+       pmd_t *pmd_k;
+       pte_t *pte_k;
+
+       /* Make sure we are in vmalloc area: */
+       if (!(address >= VMALLOC_START && address < VMALLOC_END))
+               return -1;
+
+       /*
+        * Synchronize this task's top level page-table
+        * with the 'reference' page table.
+        *
+        * Do _not_ use "current" here. We might be inside
+        * an interrupt in the middle of a task switch..
+        */
+       pgd_k = get_TTB();
+       pmd_k = vmalloc_sync_one(pgd_k, address);
+       if (!pmd_k)
+               return -1;
+
+       pte_k = pte_offset_kernel(pmd_k, address);
+       if (!pte_present(*pte_k))
+               return -1;
+
+       return 0;
+}
+
+static int fault_in_kernel_space(unsigned long address)
+{
+       return address >= TASK_SIZE;
+}
+
 /*
  * This routine handles page faults.  It determines the address,
  * and the problem, and then passes it off to one of the appropriate
@@ -46,6 +119,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
                                        unsigned long writeaccess,
                                        unsigned long address)
 {
+       unsigned long vec;
        struct task_struct *tsk;
        struct mm_struct *mm;
        struct vm_area_struct * vma;
@@ -53,59 +127,30 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
        int fault;
        siginfo_t info;
 
-       /*
-        * We don't bother with any notifier callbacks here, as they are
-        * all handled through the __do_page_fault() fast-path.
-        */
-
        tsk = current;
+       mm = tsk->mm;
        si_code = SEGV_MAPERR;
+       vec = lookup_exception_vector();
 
-       if (unlikely(address >= TASK_SIZE)) {
-               /*
-                * Synchronize this task's top level page-table
-                * with the 'reference' page table.
-                *
-                * Do _not_ use "tsk" here. We might be inside
-                * an interrupt in the middle of a task switch..
-                */
-               int offset = pgd_index(address);
-               pgd_t *pgd, *pgd_k;
-               pud_t *pud, *pud_k;
-               pmd_t *pmd, *pmd_k;
-
-               pgd = get_TTB() + offset;
-               pgd_k = swapper_pg_dir + offset;
-
-               if (!pgd_present(*pgd)) {
-                       if (!pgd_present(*pgd_k))
-                               goto bad_area_nosemaphore;
-                       set_pgd(pgd, *pgd_k);
+       /*
+        * We fault-in kernel-space virtual memory on-demand. The
+        * 'reference' page table is init_mm.pgd.
+        *
+        * NOTE! We MUST NOT take any locks for this case. We may
+        * be in an interrupt or a critical region, and should
+        * only copy the information from the master page table,
+        * nothing more.
+        */
+       if (unlikely(fault_in_kernel_space(address))) {
+               if (vmalloc_fault(address) >= 0)
                        return;
-               }
-
-               pud = pud_offset(pgd, address);
-               pud_k = pud_offset(pgd_k, address);
-
-               if (!pud_present(*pud)) {
-                       if (!pud_present(*pud_k))
-                               goto bad_area_nosemaphore;
-                       set_pud(pud, *pud_k);
+               if (notify_page_fault(regs, vec))
                        return;
-               }
 
-               pmd = pmd_offset(pud, address);
-               pmd_k = pmd_offset(pud_k, address);
-               if (pmd_present(*pmd) || !pmd_present(*pmd_k))
-                       goto bad_area_nosemaphore;
-               set_pmd(pmd, *pmd_k);
-
-               return;
+               goto bad_area_nosemaphore;
        }
 
-       mm = tsk->mm;
-
-       if (unlikely(notify_page_fault(regs, lookup_exception_vector())))
+       if (unlikely(notify_page_fault(regs, vec)))
                return;
 
        /* Only enable interrupts if they were on before the fault */
@@ -115,8 +160,8 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
        perf_swcounter_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address);
 
        /*
-        * If we're in an interrupt or have no user
-        * context, we must not take the fault..
+        * If we're in an interrupt, have no user context or are running
+        * in an atomic region then we must not take the fault:
         */
        if (in_atomic() || !mm)
                goto no_context;
@@ -132,10 +177,11 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
                goto bad_area;
        if (expand_stack(vma, address))
                goto bad_area;
-/*
- * Ok, we have a good vm_area for this memory access, so
- * we can handle it..
- */
+
+       /*
+        * Ok, we have a good vm_area for this memory access, so
+        * we can handle it..
+        */
 good_area:
        si_code = SEGV_ACCERR;
        if (writeaccess) {
@@ -173,10 +219,10 @@ survive:
        up_read(&mm->mmap_sem);
        return;
 
-/*
- * Something tried to access memory that isn't in our memory map..
- * Fix it, but check if it's kernel or user first..
- */
+       /*
       * Something tried to access memory that isn't in our memory map..
       * Fix it, but check if it's kernel or user first..
       */
 bad_area:
        up_read(&mm->mmap_sem);
 
index 095d93b..9b784fd 100644 (file)
@@ -9,6 +9,7 @@
  */
 #include <linux/module.h>
 #include <linux/bootmem.h>
+#include <linux/lmb.h>
 #include <linux/mm.h>
 #include <linux/numa.h>
 #include <linux/pfn.h>
@@ -26,6 +27,15 @@ EXPORT_SYMBOL_GPL(node_data);
 void __init setup_memory(void)
 {
        unsigned long free_pfn = PFN_UP(__pa(_end));
+       u64 base = min_low_pfn << PAGE_SHIFT;
+       u64 size = (max_low_pfn << PAGE_SHIFT) - min_low_pfn;
+
+       lmb_add(base, size);
+
+       /* Reserve the LMB regions used by the kernel, initrd, etc.. */
+       lmb_reserve(__MEMORY_START + CONFIG_ZERO_PAGE_OFFSET,
+                   (PFN_PHYS(free_pfn) + PAGE_SIZE - 1) -
+                   (__MEMORY_START + CONFIG_ZERO_PAGE_OFFSET));
 
        /*
         * Node 0 sets up its pgdat at the first available pfn,
@@ -45,24 +55,23 @@ void __init setup_memory(void)
 
 void __init setup_bootmem_node(int nid, unsigned long start, unsigned long end)
 {
-       unsigned long bootmap_pages, bootmap_start, bootmap_size;
-       unsigned long start_pfn, free_pfn, end_pfn;
+       unsigned long bootmap_pages;
+       unsigned long start_pfn, end_pfn;
+       unsigned long bootmem_paddr;
 
        /* Don't allow bogus node assignment */
        BUG_ON(nid > MAX_NUMNODES || nid == 0);
 
-       /*
-        * The free pfn starts at the beginning of the range, and is
-        * advanced as necessary for pgdat and node map allocations.
-        */
-       free_pfn = start_pfn = start >> PAGE_SHIFT;
+       start_pfn = start >> PAGE_SHIFT;
        end_pfn = end >> PAGE_SHIFT;
 
+       lmb_add(start, end - start);
+
        __add_active_range(nid, start_pfn, end_pfn);
 
        /* Node-local pgdat */
-       NODE_DATA(nid) = pfn_to_kaddr(free_pfn);
-       free_pfn += PFN_UP(sizeof(struct pglist_data));
+       NODE_DATA(nid) = __va(lmb_alloc_base(sizeof(struct pglist_data),
+                                            SMP_CACHE_BYTES, end_pfn));
        memset(NODE_DATA(nid), 0, sizeof(struct pglist_data));
 
        NODE_DATA(nid)->bdata = &bootmem_node_data[nid];
@@ -71,16 +80,17 @@ void __init setup_bootmem_node(int nid, unsigned long start, unsigned long end)
 
        /* Node-local bootmap */
        bootmap_pages = bootmem_bootmap_pages(end_pfn - start_pfn);
-       bootmap_start = (unsigned long)pfn_to_kaddr(free_pfn);
-       bootmap_size = init_bootmem_node(NODE_DATA(nid), free_pfn, start_pfn,
-                                   end_pfn);
+       bootmem_paddr = lmb_alloc_base(bootmap_pages << PAGE_SHIFT,
+                                      PAGE_SIZE, end_pfn);
+       init_bootmem_node(NODE_DATA(nid), bootmem_paddr >> PAGE_SHIFT,
+                         start_pfn, end_pfn);
 
        free_bootmem_with_active_regions(nid, end_pfn);
 
        /* Reserve the pgdat and bootmap space with the bootmem allocator */
        reserve_bootmem_node(NODE_DATA(nid), start_pfn << PAGE_SHIFT,
                             sizeof(struct pglist_data), BOOTMEM_DEFAULT);
-       reserve_bootmem_node(NODE_DATA(nid), free_pfn << PAGE_SHIFT,
+       reserve_bootmem_node(NODE_DATA(nid), bootmem_paddr,
                             bootmap_pages << PAGE_SHIFT, BOOTMEM_DEFAULT);
 
        /* It's up */
index 43dcf9e..0dddd2f 100644 (file)
@@ -37,7 +37,7 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Yoshihiro Shimoda");
 MODULE_ALIAS("platform:m66592_udc");
 
-#define DRIVER_VERSION "18 Oct 2007"
+#define DRIVER_VERSION "26 Jun 2009"
 
 /* module parameters */
 #if defined(CONFIG_SUPERH_BUILT_IN_M66592)
@@ -276,24 +276,27 @@ static int pipe_buffer_setting(struct m66592 *m66592,
                buf_bsize = 0;
                break;
        case M66592_BULK:
-               bufnum = m66592->bi_bufnum +
-                        (info->pipe - M66592_BASE_PIPENUM_BULK) * 16;
-               m66592->bi_bufnum += 16;
+               /* isochronous pipes may be used as bulk pipes */
+               if (info->pipe > M66592_BASE_PIPENUM_BULK)
+                       bufnum = info->pipe - M66592_BASE_PIPENUM_BULK;
+               else
+                       bufnum = info->pipe - M66592_BASE_PIPENUM_ISOC;
+
+               bufnum = M66592_BASE_BUFNUM + (bufnum * 16);
                buf_bsize = 7;
                pipecfg |= M66592_DBLB;
                if (!info->dir_in)
                        pipecfg |= M66592_SHTNAK;
                break;
        case M66592_ISO:
-               bufnum = m66592->bi_bufnum +
+               bufnum = M66592_BASE_BUFNUM +
                         (info->pipe - M66592_BASE_PIPENUM_ISOC) * 16;
-               m66592->bi_bufnum += 16;
                buf_bsize = 7;
                break;
        }
-       if (m66592->bi_bufnum > M66592_MAX_BUFNUM) {
-               pr_err("m66592 pipe memory is insufficient(%d)\n",
-                               m66592->bi_bufnum);
+
+       if (buf_bsize && ((bufnum + 16) >= M66592_MAX_BUFNUM)) {
+               pr_err("m66592 pipe memory is insufficient\n");
                return -ENOMEM;
        }
 
@@ -313,17 +316,6 @@ static void pipe_buffer_release(struct m66592 *m66592,
        if (info->pipe == 0)
                return;
 
-       switch (info->type) {
-       case M66592_BULK:
-               if (is_bulk_pipe(info->pipe))
-                       m66592->bi_bufnum -= 16;
-               break;
-       case M66592_ISO:
-               if (is_isoc_pipe(info->pipe))
-                       m66592->bi_bufnum -= 16;
-               break;
-       }
-
        if (is_bulk_pipe(info->pipe)) {
                m66592->bulk--;
        } else if (is_interrupt_pipe(info->pipe))
@@ -1603,8 +1595,6 @@ static int __init m66592_probe(struct platform_device *pdev)
        m66592->timer.data = (unsigned long)m66592;
        m66592->reg = reg;
 
-       m66592->bi_bufnum = M66592_BASE_BUFNUM;
-
        ret = request_irq(irq, m66592_irq, IRQF_DISABLED | IRQF_SHARED,
                        udc_name, m66592);
        if (ret < 0) {
index 286ce07..9a9c2bf 100644 (file)
@@ -506,7 +506,6 @@ struct m66592 {
        int interrupt;
        int isochronous;
        int num_dma;
-       int bi_bufnum;  /* bulk and isochronous's bufnum */
 };
 
 #define gadget_to_m66592(_gadget) container_of(_gadget, struct m66592, gadget)
index 1a920c7..f21ca7d 100644 (file)
@@ -336,13 +336,6 @@ config USB_R8A66597_HCD
          To compile this driver as a module, choose M here: the
          module will be called r8a66597-hcd.
 
-config SUPERH_ON_CHIP_R8A66597
-       boolean "Enable SuperH on-chip R8A66597 USB"
-       depends on USB_R8A66597_HCD && (CPU_SUBTYPE_SH7366 || CPU_SUBTYPE_SH7723 || CPU_SUBTYPE_SH7724)
-       help
-          This driver enables support for the on-chip R8A66597 in the
-          SH7366, SH7723 and SH7724 processors.
-
 config USB_WHCI_HCD
        tristate "Wireless USB Host Controller Interface (WHCI) driver (EXPERIMENTAL)"
        depends on EXPERIMENTAL
index e18f749..82dce3e 100644 (file)
@@ -91,43 +91,43 @@ static int r8a66597_clock_enable(struct r8a66597 *r8a66597)
        u16 tmp;
        int i = 0;
 
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
-#if defined(CONFIG_HAVE_CLK)
-       clk_enable(r8a66597->clk);
+       if (r8a66597->pdata->on_chip) {
+#ifdef CONFIG_HAVE_CLK
+               clk_enable(r8a66597->clk);
 #endif
-       do {
-               r8a66597_write(r8a66597, SCKE, SYSCFG0);
-               tmp = r8a66597_read(r8a66597, SYSCFG0);
-               if (i++ > 1000) {
-                       printk(KERN_ERR "r8a66597: register access fail.\n");
-                       return -ENXIO;
-               }
-       } while ((tmp & SCKE) != SCKE);
-       r8a66597_write(r8a66597, 0x04, 0x02);
-#else
-       do {
-               r8a66597_write(r8a66597, USBE, SYSCFG0);
-               tmp = r8a66597_read(r8a66597, SYSCFG0);
-               if (i++ > 1000) {
-                       printk(KERN_ERR "r8a66597: register access fail.\n");
-                       return -ENXIO;
-               }
-       } while ((tmp & USBE) != USBE);
-       r8a66597_bclr(r8a66597, USBE, SYSCFG0);
-       r8a66597_mdfy(r8a66597, get_xtal_from_pdata(r8a66597->pdata), XTAL,
-                       SYSCFG0);
+               do {
+                       r8a66597_write(r8a66597, SCKE, SYSCFG0);
+                       tmp = r8a66597_read(r8a66597, SYSCFG0);
+                       if (i++ > 1000) {
+                               printk(KERN_ERR "r8a66597: reg access fail.\n");
+                               return -ENXIO;
+                       }
+               } while ((tmp & SCKE) != SCKE);
+               r8a66597_write(r8a66597, 0x04, 0x02);
+       } else {
+               do {
+                       r8a66597_write(r8a66597, USBE, SYSCFG0);
+                       tmp = r8a66597_read(r8a66597, SYSCFG0);
+                       if (i++ > 1000) {
+                               printk(KERN_ERR "r8a66597: reg access fail.\n");
+                               return -ENXIO;
+                       }
+               } while ((tmp & USBE) != USBE);
+               r8a66597_bclr(r8a66597, USBE, SYSCFG0);
+               r8a66597_mdfy(r8a66597, get_xtal_from_pdata(r8a66597->pdata),
+                             XTAL, SYSCFG0);
 
-       i = 0;
-       r8a66597_bset(r8a66597, XCKE, SYSCFG0);
-       do {
-               msleep(1);
-               tmp = r8a66597_read(r8a66597, SYSCFG0);
-               if (i++ > 500) {
-                       printk(KERN_ERR "r8a66597: register access fail.\n");
-                       return -ENXIO;
-               }
-       } while ((tmp & SCKE) != SCKE);
-#endif /* #if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) */
+               i = 0;
+               r8a66597_bset(r8a66597, XCKE, SYSCFG0);
+               do {
+                       msleep(1);
+                       tmp = r8a66597_read(r8a66597, SYSCFG0);
+                       if (i++ > 500) {
+                               printk(KERN_ERR "r8a66597: reg access fail.\n");
+                               return -ENXIO;
+                       }
+               } while ((tmp & SCKE) != SCKE);
+       }
 
        return 0;
 }
@@ -136,15 +136,16 @@ static void r8a66597_clock_disable(struct r8a66597 *r8a66597)
 {
        r8a66597_bclr(r8a66597, SCKE, SYSCFG0);
        udelay(1);
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
-#if defined(CONFIG_HAVE_CLK)
-       clk_disable(r8a66597->clk);
-#endif
-#else
-       r8a66597_bclr(r8a66597, PLLC, SYSCFG0);
-       r8a66597_bclr(r8a66597, XCKE, SYSCFG0);
-       r8a66597_bclr(r8a66597, USBE, SYSCFG0);
+
+       if (r8a66597->pdata->on_chip) {
+#ifdef CONFIG_HAVE_CLK
+               clk_disable(r8a66597->clk);
 #endif
+       } else {
+               r8a66597_bclr(r8a66597, PLLC, SYSCFG0);
+               r8a66597_bclr(r8a66597, XCKE, SYSCFG0);
+               r8a66597_bclr(r8a66597, USBE, SYSCFG0);
+       }
 }
 
 static void r8a66597_enable_port(struct r8a66597 *r8a66597, int port)
@@ -205,7 +206,7 @@ static int enable_controller(struct r8a66597 *r8a66597)
 
        r8a66597_bset(r8a66597, SIGNE | SACKE, INTENB1);
 
-       for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++)
+       for (port = 0; port < r8a66597->max_root_hub; port++)
                r8a66597_enable_port(r8a66597, port);
 
        return 0;
@@ -218,7 +219,7 @@ static void disable_controller(struct r8a66597 *r8a66597)
        r8a66597_write(r8a66597, 0, INTENB0);
        r8a66597_write(r8a66597, 0, INTSTS0);
 
-       for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++)
+       for (port = 0; port < r8a66597->max_root_hub; port++)
                r8a66597_disable_port(r8a66597, port);
 
        r8a66597_clock_disable(r8a66597);
@@ -249,11 +250,12 @@ static int is_hub_limit(char *devpath)
        return ((strlen(devpath) >= 4) ? 1 : 0);
 }
 
-static void get_port_number(char *devpath, u16 *root_port, u16 *hub_port)
+static void get_port_number(struct r8a66597 *r8a66597,
+                           char *devpath, u16 *root_port, u16 *hub_port)
 {
        if (root_port) {
                *root_port = (devpath[0] & 0x0F) - 1;
-               if (*root_port >= R8A66597_MAX_ROOT_HUB)
+               if (*root_port >= r8a66597->max_root_hub)
                        printk(KERN_ERR "r8a66597: Illegal root port number.\n");
        }
        if (hub_port)
@@ -355,7 +357,8 @@ static int make_r8a66597_device(struct r8a66597 *r8a66597,
        INIT_LIST_HEAD(&dev->device_list);
        list_add_tail(&dev->device_list, &r8a66597->child_device);
 
-       get_port_number(urb->dev->devpath, &dev->root_port, &dev->hub_port);
+       get_port_number(r8a66597, urb->dev->devpath,
+                       &dev->root_port, &dev->hub_port);
        if (!is_child_device(urb->dev->devpath))
                r8a66597->root_hub[dev->root_port].dev = dev;
 
@@ -420,7 +423,7 @@ static void free_usb_address(struct r8a66597 *r8a66597,
        list_del(&dev->device_list);
        kfree(dev);
 
-       for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++) {
+       for (port = 0; port < r8a66597->max_root_hub; port++) {
                if (r8a66597->root_hub[port].dev == dev) {
                        r8a66597->root_hub[port].dev = NULL;
                        break;
@@ -495,10 +498,20 @@ static void r8a66597_pipe_toggle(struct r8a66597 *r8a66597,
                r8a66597_bset(r8a66597, SQCLR, pipe->pipectr);
 }
 
+static inline unsigned short mbw_value(struct r8a66597 *r8a66597)
+{
+       if (r8a66597->pdata->on_chip)
+               return MBW_32;
+       else
+               return MBW_16;
+}
+
 /* this function must be called with interrupt disabled */
 static inline void cfifo_change(struct r8a66597 *r8a66597, u16 pipenum)
 {
-       r8a66597_mdfy(r8a66597, MBW | pipenum, MBW | CURPIPE, CFIFOSEL);
+       unsigned short mbw = mbw_value(r8a66597);
+
+       r8a66597_mdfy(r8a66597, mbw | pipenum, mbw | CURPIPE, CFIFOSEL);
        r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, pipenum);
 }
 
@@ -506,11 +519,13 @@ static inline void cfifo_change(struct r8a66597 *r8a66597, u16 pipenum)
 static inline void fifo_change_from_pipe(struct r8a66597 *r8a66597,
                                         struct r8a66597_pipe *pipe)
 {
+       unsigned short mbw = mbw_value(r8a66597);
+
        cfifo_change(r8a66597, 0);
-       r8a66597_mdfy(r8a66597, MBW | 0, MBW | CURPIPE, D0FIFOSEL);
-       r8a66597_mdfy(r8a66597, MBW | 0, MBW | CURPIPE, D1FIFOSEL);
+       r8a66597_mdfy(r8a66597, mbw | 0, mbw | CURPIPE, D0FIFOSEL);
+       r8a66597_mdfy(r8a66597, mbw | 0, mbw | CURPIPE, D1FIFOSEL);
 
-       r8a66597_mdfy(r8a66597, MBW | pipe->info.pipenum, MBW | CURPIPE,
+       r8a66597_mdfy(r8a66597, mbw | pipe->info.pipenum, mbw | CURPIPE,
                      pipe->fifosel);
        r8a66597_reg_wait(r8a66597, pipe->fifosel, CURPIPE, pipe->info.pipenum);
 }
@@ -742,9 +757,13 @@ static void enable_r8a66597_pipe_dma(struct r8a66597 *r8a66597,
                                     struct r8a66597_pipe *pipe,
                                     struct urb *urb)
 {
-#if !defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
        int i;
        struct r8a66597_pipe_info *info = &pipe->info;
+       unsigned short mbw = mbw_value(r8a66597);
+
+       /* pipe dma is only for external controlles */
+       if (r8a66597->pdata->on_chip)
+               return;
 
        if ((pipe->info.pipenum != 0) && (info->type != R8A66597_INT)) {
                for (i = 0; i < R8A66597_MAX_DMA_CHANNEL; i++) {
@@ -763,8 +782,8 @@ static void enable_r8a66597_pipe_dma(struct r8a66597 *r8a66597,
                        set_pipe_reg_addr(pipe, i);
 
                        cfifo_change(r8a66597, 0);
-                       r8a66597_mdfy(r8a66597, MBW | pipe->info.pipenum,
-                                     MBW | CURPIPE, pipe->fifosel);
+                       r8a66597_mdfy(r8a66597, mbw | pipe->info.pipenum,
+                                     mbw | CURPIPE, pipe->fifosel);
 
                        r8a66597_reg_wait(r8a66597, pipe->fifosel, CURPIPE,
                                          pipe->info.pipenum);
@@ -772,7 +791,6 @@ static void enable_r8a66597_pipe_dma(struct r8a66597 *r8a66597,
                        break;
                }
        }
-#endif /* #if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) */
 }
 
 /* this function must be called with interrupt disabled */
@@ -1769,7 +1787,7 @@ static void r8a66597_timer(unsigned long _r8a66597)
 
        spin_lock_irqsave(&r8a66597->lock, flags);
 
-       for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++)
+       for (port = 0; port < r8a66597->max_root_hub; port++)
                r8a66597_root_hub_control(r8a66597, port);
 
        spin_unlock_irqrestore(&r8a66597->lock, flags);
@@ -1807,7 +1825,7 @@ static void set_address_zero(struct r8a66597 *r8a66597, struct urb *urb)
        u16 root_port, hub_port;
 
        if (usb_address == 0) {
-               get_port_number(urb->dev->devpath,
+               get_port_number(r8a66597, urb->dev->devpath,
                                &root_port, &hub_port);
                set_devadd_reg(r8a66597, 0,
                               get_r8a66597_usb_speed(urb->dev->speed),
@@ -2082,7 +2100,7 @@ static int r8a66597_hub_status_data(struct usb_hcd *hcd, char *buf)
 
        *buf = 0;       /* initialize (no change) */
 
-       for (i = 0; i < R8A66597_MAX_ROOT_HUB; i++) {
+       for (i = 0; i < r8a66597->max_root_hub; i++) {
                if (r8a66597->root_hub[i].port & 0xffff0000)
                        *buf |= 1 << (i + 1);
        }
@@ -2097,11 +2115,11 @@ static void r8a66597_hub_descriptor(struct r8a66597 *r8a66597,
 {
        desc->bDescriptorType = 0x29;
        desc->bHubContrCurrent = 0;
-       desc->bNbrPorts = R8A66597_MAX_ROOT_HUB;
+       desc->bNbrPorts = r8a66597->max_root_hub;
        desc->bDescLength = 9;
        desc->bPwrOn2PwrGood = 0;
        desc->wHubCharacteristics = cpu_to_le16(0x0011);
-       desc->bitmap[0] = ((1 << R8A66597_MAX_ROOT_HUB) - 1) << 1;
+       desc->bitmap[0] = ((1 << r8a66597->max_root_hub) - 1) << 1;
        desc->bitmap[1] = ~0;
 }
 
@@ -2129,7 +2147,7 @@ static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                }
                break;
        case ClearPortFeature:
-               if (wIndex > R8A66597_MAX_ROOT_HUB)
+               if (wIndex > r8a66597->max_root_hub)
                        goto error;
                if (wLength != 0)
                        goto error;
@@ -2162,12 +2180,12 @@ static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                *buf = 0x00;
                break;
        case GetPortStatus:
-               if (wIndex > R8A66597_MAX_ROOT_HUB)
+               if (wIndex > r8a66597->max_root_hub)
                        goto error;
                *(__le32 *)buf = cpu_to_le32(rh->port);
                break;
        case SetPortFeature:
-               if (wIndex > R8A66597_MAX_ROOT_HUB)
+               if (wIndex > r8a66597->max_root_hub)
                        goto error;
                if (wLength != 0)
                        goto error;
@@ -2216,7 +2234,7 @@ static int r8a66597_bus_suspend(struct usb_hcd *hcd)
 
        dbg("%s", __func__);
 
-       for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++) {
+       for (port = 0; port < r8a66597->max_root_hub; port++) {
                struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
                unsigned long dvstctr_reg = get_dvstctr_reg(port);
 
@@ -2247,7 +2265,7 @@ static int r8a66597_bus_resume(struct usb_hcd *hcd)
 
        dbg("%s", __func__);
 
-       for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++) {
+       for (port = 0; port < r8a66597->max_root_hub; port++) {
                struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
                unsigned long dvstctr_reg = get_dvstctr_reg(port);
 
@@ -2305,16 +2323,16 @@ static struct hc_driver r8a66597_hc_driver = {
 };
 
 #if defined(CONFIG_PM)
-static int r8a66597_suspend(struct platform_device *pdev, pm_message_t state)
+static int r8a66597_suspend(struct device *dev)
 {
-       struct r8a66597         *r8a66597 = dev_get_drvdata(&pdev->dev);
+       struct r8a66597         *r8a66597 = dev_get_drvdata(dev);
        int port;
 
        dbg("%s", __func__);
 
        disable_controller(r8a66597);
 
-       for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++) {
+       for (port = 0; port < r8a66597->max_root_hub; port++) {
                struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
 
                rh->port = 0x00000000;
@@ -2323,9 +2341,9 @@ static int r8a66597_suspend(struct platform_device *pdev, pm_message_t state)
        return 0;
 }
 
-static int r8a66597_resume(struct platform_device *pdev)
+static int r8a66597_resume(struct device *dev)
 {
-       struct r8a66597         *r8a66597 = dev_get_drvdata(&pdev->dev);
+       struct r8a66597         *r8a66597 = dev_get_drvdata(dev);
        struct usb_hcd          *hcd = r8a66597_to_hcd(r8a66597);
 
        dbg("%s", __func__);
@@ -2335,9 +2353,15 @@ static int r8a66597_resume(struct platform_device *pdev)
 
        return 0;
 }
+
+static struct dev_pm_ops r8a66597_dev_pm_ops = {
+       .suspend = r8a66597_suspend,
+       .resume = r8a66597_resume,
+};
+
+#define R8A66597_DEV_PM_OPS    (&r8a66597_dev_pm_ops)
 #else  /* if defined(CONFIG_PM) */
-#define r8a66597_suspend       NULL
-#define r8a66597_resume                NULL
+#define R8A66597_DEV_PM_OPS    NULL
 #endif
 
 static int __init_or_module r8a66597_remove(struct platform_device *pdev)
@@ -2348,8 +2372,9 @@ static int __init_or_module r8a66597_remove(struct platform_device *pdev)
        del_timer_sync(&r8a66597->rh_timer);
        usb_remove_hcd(hcd);
        iounmap((void *)r8a66597->reg);
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK)
-       clk_put(r8a66597->clk);
+#ifdef CONFIG_HAVE_CLK
+       if (r8a66597->pdata->on_chip)
+               clk_put(r8a66597->clk);
 #endif
        usb_put_hcd(hcd);
        return 0;
@@ -2357,7 +2382,7 @@ static int __init_or_module r8a66597_remove(struct platform_device *pdev)
 
 static int __devinit r8a66597_probe(struct platform_device *pdev)
 {
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK)
+#ifdef CONFIG_HAVE_CLK
        char clk_name[8];
 #endif
        struct resource *res = NULL, *ires;
@@ -2419,15 +2444,20 @@ static int __devinit r8a66597_probe(struct platform_device *pdev)
        r8a66597->pdata = pdev->dev.platform_data;
        r8a66597->irq_sense_low = irq_trigger == IRQF_TRIGGER_LOW;
 
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK)
-       snprintf(clk_name, sizeof(clk_name), "usb%d", pdev->id);
-       r8a66597->clk = clk_get(&pdev->dev, clk_name);
-       if (IS_ERR(r8a66597->clk)) {
-               dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
-               ret = PTR_ERR(r8a66597->clk);
-               goto clean_up2;
-       }
+       if (r8a66597->pdata->on_chip) {
+#ifdef CONFIG_HAVE_CLK
+               snprintf(clk_name, sizeof(clk_name), "usb%d", pdev->id);
+               r8a66597->clk = clk_get(&pdev->dev, clk_name);
+               if (IS_ERR(r8a66597->clk)) {
+                       dev_err(&pdev->dev, "cannot get clock \"%s\"\n",
+                               clk_name);
+                       ret = PTR_ERR(r8a66597->clk);
+                       goto clean_up2;
+               }
 #endif
+               r8a66597->max_root_hub = 1;
+       } else
+               r8a66597->max_root_hub = 2;
 
        spin_lock_init(&r8a66597->lock);
        init_timer(&r8a66597->rh_timer);
@@ -2457,8 +2487,9 @@ static int __devinit r8a66597_probe(struct platform_device *pdev)
        return 0;
 
 clean_up3:
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK)
-       clk_put(r8a66597->clk);
+#ifdef CONFIG_HAVE_CLK
+       if (r8a66597->pdata->on_chip)
+               clk_put(r8a66597->clk);
 clean_up2:
 #endif
        usb_put_hcd(hcd);
@@ -2473,11 +2504,10 @@ clean_up:
 static struct platform_driver r8a66597_driver = {
        .probe =        r8a66597_probe,
        .remove =       r8a66597_remove,
-       .suspend =      r8a66597_suspend,
-       .resume =       r8a66597_resume,
        .driver         = {
                .name = (char *) hcd_name,
                .owner  = THIS_MODULE,
+               .pm     = R8A66597_DEV_PM_OPS,
        },
 };
 
index d72680b..eecbd91 100644 (file)
@@ -26,7 +26,7 @@
 #ifndef __R8A66597_H__
 #define __R8A66597_H__
 
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK)
+#ifdef CONFIG_HAVE_CLK
 #include <linux/clk.h>
 #endif
 
 #define        REW             0x4000  /* b14: Buffer rewind */
 #define        DCLRM           0x2000  /* b13: DMA buffer clear mode */
 #define        DREQE           0x1000  /* b12: DREQ output enable */
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
-#define        MBW             0x0800
-#else
-#define        MBW             0x0400  /* b10: Maximum bit width for FIFO access */
-#endif
 #define          MBW_8          0x0000   /*  8bit */
 #define          MBW_16         0x0400   /* 16bit */
+#define          MBW_32         0x0800   /* 32bit */
 #define        BIGEND          0x0100  /* b8: Big endian mode */
 #define          BYTE_LITTLE    0x0000         /* little dendian */
 #define          BYTE_BIG       0x0100         /* big endifan */
 #define R8A66597_MAX_NUM_PIPE          10
 #define R8A66597_BUF_BSIZE             8
 #define R8A66597_MAX_DEVICE            10
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
-#define R8A66597_MAX_ROOT_HUB          1
-#else
 #define R8A66597_MAX_ROOT_HUB          2
-#endif
 #define R8A66597_MAX_SAMPLING          5
 #define R8A66597_RH_POLL_TIME          10
 #define R8A66597_MAX_DMA_CHANNEL       2
@@ -487,7 +479,7 @@ struct r8a66597_root_hub {
 struct r8a66597 {
        spinlock_t lock;
        unsigned long reg;
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK)
+#ifdef CONFIG_HAVE_CLK
        struct clk *clk;
 #endif
        struct r8a66597_platdata        *pdata;
@@ -504,6 +496,7 @@ struct r8a66597 {
        unsigned short interval_map;
        unsigned char pipe_cnt[R8A66597_MAX_NUM_PIPE];
        unsigned char dma_map;
+       unsigned int max_root_hub;
 
        struct list_head child_device;
        unsigned long child_connect_map[4];
@@ -550,21 +543,22 @@ static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597,
                                      unsigned long offset, u16 *buf,
                                      int len)
 {
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
        unsigned long fifoaddr = r8a66597->reg + offset;
        unsigned long count;
 
-       count = len / 4;
-       insl(fifoaddr, buf, count);
+       if (r8a66597->pdata->on_chip) {
+               count = len / 4;
+               insl(fifoaddr, buf, count);
 
-       if (len & 0x00000003) {
-               unsigned long tmp = inl(fifoaddr);
-               memcpy((unsigned char *)buf + count * 4, &tmp, len & 0x03);
+               if (len & 0x00000003) {
+                       unsigned long tmp = inl(fifoaddr);
+                       memcpy((unsigned char *)buf + count * 4, &tmp,
+                              len & 0x03);
+               }
+       } else {
+               len = (len + 1) / 2;
+               insw(fifoaddr, buf, len);
        }
-#else
-       len = (len + 1) / 2;
-       insw(r8a66597->reg + offset, buf, len);
-#endif
 }
 
 static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val,
@@ -578,33 +572,33 @@ static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597,
                                       int len)
 {
        unsigned long fifoaddr = r8a66597->reg + offset;
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
        unsigned long count;
        unsigned char *pb;
        int i;
 
-       count = len / 4;
-       outsl(fifoaddr, buf, count);
+       if (r8a66597->pdata->on_chip) {
+               count = len / 4;
+               outsl(fifoaddr, buf, count);
+
+               if (len & 0x00000003) {
+                       pb = (unsigned char *)buf + count * 4;
+                       for (i = 0; i < (len & 0x00000003); i++) {
+                               if (r8a66597_read(r8a66597, CFIFOSEL) & BIGEND)
+                                       outb(pb[i], fifoaddr + i);
+                               else
+                                       outb(pb[i], fifoaddr + 3 - i);
+                       }
+               }
+       } else {
+               int odd = len & 0x0001;
 
-       if (len & 0x00000003) {
-               pb = (unsigned char *)buf + count * 4;
-               for (i = 0; i < (len & 0x00000003); i++) {
-                       if (r8a66597_read(r8a66597, CFIFOSEL) & BIGEND)
-                               outb(pb[i], fifoaddr + i);
-                       else
-                               outb(pb[i], fifoaddr + 3 - i);
+               len = len / 2;
+               outsw(fifoaddr, buf, len);
+               if (unlikely(odd)) {
+                       buf = &buf[len];
+                       outb((unsigned char)*buf, fifoaddr);
                }
        }
-#else
-       int odd = len & 0x0001;
-
-       len = len / 2;
-       outsw(fifoaddr, buf, len);
-       if (unlikely(odd)) {
-               buf = &buf[len];
-               outb((unsigned char)*buf, fifoaddr);
-       }
-#endif
 }
 
 static inline void r8a66597_mdfy(struct r8a66597 *r8a66597,
index 3b54b39..7e2c977 100644 (file)
@@ -1867,7 +1867,7 @@ config FB_W100
 
 config FB_SH_MOBILE_LCDC
        tristate "SuperH Mobile LCDC framebuffer support"
-       depends on FB && SUPERH
+       depends on FB && SUPERH && HAVE_CLK
        select FB_SYS_FILLRECT
        select FB_SYS_COPYAREA
        select FB_SYS_IMAGEBLIT
index 8f24564..98fb82f 100644 (file)
@@ -42,11 +42,9 @@ struct sh_mobile_lcdc_chan {
 struct sh_mobile_lcdc_priv {
        void __iomem *base;
        int irq;
-#ifdef CONFIG_HAVE_CLK
        atomic_t clk_usecnt;
        struct clk *dot_clk;
        struct clk *clk;
-#endif
        unsigned long lddckr;
        struct sh_mobile_lcdc_chan ch[2];
        int started;
@@ -185,7 +183,6 @@ struct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = {
        lcdc_sys_read_data,
 };
 
-#ifdef CONFIG_HAVE_CLK
 static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv)
 {
        if (atomic_inc_and_test(&priv->clk_usecnt)) {
@@ -203,10 +200,6 @@ static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv)
                clk_disable(priv->clk);
        }
 }
-#else
-static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv) {}
-static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv) {}
-#endif
 
 static int sh_mobile_lcdc_sginit(struct fb_info *info,
                                  struct list_head *pagelist)
@@ -515,7 +508,6 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv)
                board_cfg = &ch->cfg.board_cfg;
                if (board_cfg->display_off)
                        board_cfg->display_off(board_cfg->board_data);
-
        }
 
        /* stop the lcdc */
@@ -574,9 +566,7 @@ static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev,
                                       int clock_source,
                                       struct sh_mobile_lcdc_priv *priv)
 {
-#ifdef CONFIG_HAVE_CLK
        char clk_name[8];
-#endif
        char *str;
        int icksel;
 
@@ -590,7 +580,6 @@ static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev,
 
        priv->lddckr = icksel << 16;
 
-#ifdef CONFIG_HAVE_CLK
        atomic_set(&priv->clk_usecnt, -1);
        snprintf(clk_name, sizeof(clk_name), "lcdc%d", pdev->id);
        priv->clk = clk_get(&pdev->dev, clk_name);
@@ -598,7 +587,7 @@ static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev,
                dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
                return PTR_ERR(priv->clk);
        }
-       
+
        if (str) {
                priv->dot_clk = clk_get(&pdev->dev, str);
                if (IS_ERR(priv->dot_clk)) {
@@ -607,7 +596,6 @@ static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev,
                        return PTR_ERR(priv->dot_clk);
                }
        }
-#endif
 
        return 0;
 }
@@ -942,11 +930,9 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev)
                framebuffer_release(info);
        }
 
-#ifdef CONFIG_HAVE_CLK
        if (priv->dot_clk)
                clk_put(priv->dot_clk);
        clk_put(priv->clk);
-#endif
 
        if (priv->base)
                iounmap(priv->base);
index e9f0384..460ee3f 100644 (file)
@@ -31,6 +31,9 @@ struct r8a66597_platdata {
        /* This ops can controll port power instead of DVSTCTR register. */
        void (*port_power)(int port, int power);
 
+       /* set one = on chip controller, set zero = external controller */
+       unsigned        on_chip:1;
+
        /* (external controller only) set R8A66597_PLATDATA_XTAL_nnMHZ */
        unsigned        xtal:2;