]> git.kernelconcepts.de Git - mv-sheeva.git/commitdiff
Merge branch 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 18 Dec 2009 00:38:06 +0000 (16:38 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 18 Dec 2009 00:38:06 +0000 (16:38 -0800)
* 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus: (71 commits)
  MIPS: Lasat: Fix botched changes to sysctl code.
  RTC: rtc-cmos.c: Fix warning on MIPS
  MIPS: Cleanup random differences beween lmo and Linus' kernel.
  MIPS: No longer hardwire CONFIG_EMBEDDED to y
  MIPS: Fix and enhance built-in kernel command line
  MIPS: eXcite: Remove platform.
  MIPS: Loongson: Cleanups of serial port support
  MIPS: Lemote 2F: Suspend CS5536 MFGPT Timer
  MIPS: Excite: move iodev_remove to .devexit.text
  MIPS: Lasat: Convert to proc_fops / seq_file
  MIPS: Cleanup signal code initialization
  MIPS: Modularize COP2 handling
  MIPS: Move EARLY_PRINTK to Kconfig.debug
  MIPS: Yeeloong 2F: Cleanup reset logic using the new ec_write function
  MIPS: Yeeloong 2F: Add LID open event as the wakeup event
  MIPS: Yeeloong 2F: Add basic EC operations
  MIPS: Move several variables from .bss to .init.data
  MIPS: Tracing: Make function graph tracer work with -mmcount-ra-address
  MIPS: Tracing: Reserve $12(t0) for mcount-ra-address of gcc 4.5
  MIPS: Tracing: Make ftrace for MIPS work without -fno-omit-frame-pointer
  ...

297 files changed:
.gitignore
Documentation/dontdiff
Documentation/kbuild/kbuild.txt
Documentation/kbuild/kconfig.txt
Kbuild
MAINTAINERS
Makefile
arch/alpha/boot/bootp.c
arch/alpha/boot/bootpz.c
arch/alpha/boot/main.c
arch/alpha/include/asm/asm-offsets.h [new file with mode: 0644]
arch/alpha/include/asm/fcntl.h
arch/arm/Makefile
arch/arm/common/dmabounce.c
arch/arm/include/asm/asm-offsets.h [new file with mode: 0644]
arch/arm/include/asm/cacheflush.h
arch/arm/include/asm/mach-types.h [new file with mode: 0644]
arch/arm/mach-kirkwood/Kconfig
arch/arm/mach-kirkwood/Makefile
arch/arm/mach-kirkwood/netspace_v2-setup.c [new file with mode: 0644]
arch/arm/mach-pxa/Kconfig
arch/arm/mach-pxa/devices.c
arch/arm/mach-s3c2410/include/mach/spi.h
arch/arm/mm/cache-fa.S
arch/arm/mm/cache-l2x0.c
arch/arm/mm/cache-v3.S
arch/arm/mm/cache-v4.S
arch/arm/mm/cache-v4wb.S
arch/arm/mm/cache-v4wt.S
arch/arm/mm/cache-v6.S
arch/arm/mm/cache-v7.S
arch/arm/mm/flush.c
arch/arm/mm/highmem.c
arch/arm/mm/nommu.c
arch/arm/mm/proc-arm1020.S
arch/arm/mm/proc-arm1020e.S
arch/arm/mm/proc-arm1022.S
arch/arm/mm/proc-arm1026.S
arch/arm/mm/proc-arm920.S
arch/arm/mm/proc-arm922.S
arch/arm/mm/proc-arm925.S
arch/arm/mm/proc-arm926.S
arch/arm/mm/proc-arm940.S
arch/arm/mm/proc-arm946.S
arch/arm/mm/proc-feroceon.S
arch/arm/mm/proc-mohawk.S
arch/arm/mm/proc-syms.c
arch/arm/mm/proc-v6.S
arch/arm/mm/proc-xsc3.S
arch/arm/mm/proc-xscale.S
arch/arm/tools/Makefile
arch/arm/tools/gen-mach-types
arch/arm/tools/mach-types
arch/avr32/include/asm/asm-offsets.h [new file with mode: 0644]
arch/blackfin/include/asm/asm-offsets.h [new file with mode: 0644]
arch/cris/arch-v32/kernel/head.S
arch/cris/include/asm/asm-offsets.h [new file with mode: 0644]
arch/cris/kernel/asm-offsets.c
arch/cris/kernel/vmlinux.lds.S
arch/frv/include/asm/asm-offsets.h [new file with mode: 0644]
arch/frv/kernel/setup.c
arch/h8300/include/asm/asm-offsets.h [new file with mode: 0644]
arch/ia64/Makefile
arch/ia64/include/asm/asm-offsets.h [new file with mode: 0644]
arch/ia64/include/asm/irq.h
arch/ia64/kernel/Makefile
arch/ia64/kvm/asm-offsets.c
arch/m68k/include/asm/asm-offsets.h [new file with mode: 0644]
arch/m68k/kernel/head.S
arch/microblaze/include/asm/asm-offsets.h [new file with mode: 0644]
arch/mips/include/asm/asm-offsets.h [new file with mode: 0644]
arch/mips/include/asm/fcntl.h
arch/mn10300/include/asm/asm-offsets.h [new file with mode: 0644]
arch/parisc/include/asm/asm-offsets.h [new file with mode: 0644]
arch/powerpc/include/asm/asm-offsets.h [new file with mode: 0644]
arch/powerpc/platforms/52xx/efika.c
arch/powerpc/platforms/amigaone/setup.c
arch/powerpc/platforms/cell/spufs/Makefile
arch/powerpc/platforms/chrp/setup.c
arch/powerpc/platforms/powermac/bootx_init.c
arch/s390/include/asm/asm-offsets.h [new file with mode: 0644]
arch/score/include/asm/asm-offsets.h [new file with mode: 0644]
arch/score/include/asm/cacheflush.h
arch/score/include/asm/delay.h
arch/score/include/asm/page.h
arch/score/kernel/setup.c
arch/score/mm/cache.c
arch/score/mm/init.c
arch/sh/Makefile
arch/sh/drivers/pci/fixups-rts7751r2d.c
arch/sh/include/asm/.gitignore [deleted file]
arch/sh/include/asm/asm-offsets.h [new file with mode: 0644]
arch/sh/include/asm/machvec.h
arch/sh/tools/Makefile
arch/sh/tools/gen-mach-types
arch/sparc/include/asm/asm-offsets.h [new file with mode: 0644]
arch/sparc/include/asm/fcntl.h
arch/um/Makefile
arch/um/include/asm/asm-offsets.h [new file with mode: 0644]
arch/x86/boot/header.S
arch/x86/boot/version.c
arch/x86/include/asm/asm-offsets.h [new file with mode: 0644]
arch/x86/kernel/ptrace.c
arch/xtensa/include/asm/asm-offsets.h [new file with mode: 0644]
drivers/accessibility/braille/braille_console.c
drivers/hid/hid-lg.h
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/lis3lv02d_i2c.c [new file with mode: 0644]
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/leds-adp5520.c [new file with mode: 0644]
drivers/leds/leds-alix2.c
drivers/leds/leds-cobalt-qube.c
drivers/leds/leds-cobalt-raq.c
drivers/leds/leds-lt3593.c [new file with mode: 0644]
drivers/leds/leds-pwm.c
drivers/leds/leds-regulator.c [new file with mode: 0644]
drivers/leds/leds-ss4200.c [new file with mode: 0644]
drivers/misc/Kconfig
drivers/mmc/core/sdio.c
drivers/mmc/core/sdio_bus.c
drivers/mmc/host/Kconfig
drivers/mmc/host/Makefile
drivers/mmc/host/sdhci-of-core.c [moved from drivers/mmc/host/sdhci-of.c with 58% similarity]
drivers/mmc/host/sdhci-of-esdhc.c [new file with mode: 0644]
drivers/mmc/host/sdhci-of-hlwd.c [new file with mode: 0644]
drivers/mmc/host/sdhci-of.h [new file with mode: 0644]
drivers/mmc/host/sdhci.h
drivers/mtd/maps/pxa2xx-flash.c
drivers/net/wireless/iwlwifi/iwl-core.h
drivers/pcmcia/pxa2xx_base.c
drivers/platform/x86/compal-laptop.c
drivers/regulator/88pm8607.c [new file with mode: 0644]
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/ab3100.c
drivers/regulator/core.c
drivers/regulator/da903x.c
drivers/regulator/lp3971.c
drivers/regulator/max8660.c [new file with mode: 0644]
drivers/regulator/mc13783-regulator.c [new file with mode: 0644]
drivers/regulator/mc13783.c [deleted file]
drivers/regulator/twl-regulator.c
drivers/regulator/wm831x-dcdc.c
drivers/regulator/wm831x-ldo.c
drivers/rtc/rtc-ds1305.c
drivers/rtc/rtc-ds1307.c
drivers/rtc/rtc-ds1374.c
drivers/spi/Kconfig
drivers/spi/Makefile
drivers/spi/atmel_spi.c
drivers/spi/dw_spi.c [new file with mode: 0644]
drivers/spi/dw_spi_pci.c [new file with mode: 0644]
drivers/spi/spi_bfin5xx.c
drivers/spi/spi_mpc8xxx.c
drivers/spi/spi_s3c24xx.c
drivers/spi/spi_s3c24xx_fiq.S [new file with mode: 0644]
drivers/spi/spi_s3c24xx_fiq.h [new file with mode: 0644]
drivers/spi/spi_s3c64xx.c [new file with mode: 0644]
drivers/spi/spi_sh_sci.c
drivers/spi/spi_txx9.c
drivers/spi/spidev.c
drivers/staging/iio/ring_sw.h
drivers/staging/panel/panel.c
drivers/video/atafb.c
drivers/video/backlight/adp5520_bl.c
drivers/video/backlight/adx_bl.c
drivers/video/backlight/atmel-pwm-bl.c
drivers/video/backlight/backlight.c
drivers/video/backlight/corgi_lcd.c
drivers/video/backlight/cr_bllcd.c
drivers/video/backlight/da903x_bl.c
drivers/video/backlight/generic_bl.c
drivers/video/backlight/hp680_bl.c
drivers/video/backlight/jornada720_bl.c
drivers/video/backlight/kb3886_bl.c
drivers/video/backlight/locomolcd.c
drivers/video/backlight/mbp_nvidia_bl.c
drivers/video/backlight/omap1_bl.c
drivers/video/backlight/progear_bl.c
drivers/video/backlight/pwm_bl.c
drivers/video/backlight/tosa_bl.c
drivers/video/backlight/wm831x_bl.c
drivers/video/via/viafbdev.c
fs/Kconfig
fs/anon_inodes.c
fs/binfmt_aout.c
fs/binfmt_elf.c
fs/binfmt_elf_fdpic.c
fs/binfmt_flat.c
fs/binfmt_som.c
fs/btrfs/Kconfig
fs/btrfs/acl.c
fs/btrfs/btrfs_inode.h
fs/btrfs/ctree.c
fs/btrfs/ctree.h
fs/btrfs/dir-item.c
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/file.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/ordered-data.c
fs/btrfs/ordered-data.h
fs/btrfs/relocation.c
fs/btrfs/super.c
fs/btrfs/transaction.c
fs/btrfs/transaction.h
fs/btrfs/tree-log.c
fs/btrfs/volumes.c
fs/btrfs/xattr.c
fs/btrfs/xattr.h
fs/direct-io.c
fs/ecryptfs/dentry.c
fs/ecryptfs/inode.c
fs/ecryptfs/main.c
fs/exec.c
fs/ext4/Kconfig
fs/gfs2/Kconfig
fs/gfs2/inode.c
fs/inode.c
fs/jbd/Kconfig
fs/jbd2/Kconfig
fs/jfs/jfs_txnmgr.c
fs/namei.c
fs/namespace.c
fs/nfs/super.c
fs/nilfs2/Kconfig
fs/ntfs/inode.c
fs/pipe.c
fs/ramfs/file-nommu.c
fs/reiserfs/Kconfig
fs/reiserfs/inode.c
fs/stack.c
fs/sync.c
fs/ubifs/file.c
fs/xfs/linux-2.6/xfs_iops.c
fs/xfs/xfs_iget.c
include/asm-generic/fcntl.h
include/linux/Kbuild
include/linux/backlight.h
include/linux/binfmts.h
include/linux/fs.h
include/linux/fs_stack.h
include/linux/init_task.h
include/linux/kmemleak.h
include/linux/leds-lp3944.h
include/linux/leds-pca9532.h
include/linux/leds-regulator.h [new file with mode: 0644]
include/linux/mfd/wm831x/pdata.h
include/linux/mmdebug.h
include/linux/mmzone.h
include/linux/mnt_namespace.h
include/linux/page-flags.h
include/linux/pwm_backlight.h
include/linux/regulator/consumer.h
include/linux/regulator/machine.h
include/linux/regulator/max8660.h [new file with mode: 0644]
include/linux/sched.h
include/linux/spi/dw_spi.h [new file with mode: 0644]
include/linux/vermagic.h
include/linux/vt.h
include/linux/writeback.h
init/Makefile
init/version.c
kernel/bounds.c
kernel/exit.c
kernel/fork.c
kernel/kexec.c
kernel/module.c
kernel/printk.c
kernel/sysctl.c
kernel/trace/trace.c
lib/Kconfig.debug
lib/vsprintf.c
mm/kmemleak.c
mm/readahead.c
mm/shmem.c
mm/slab.c
net/socket.c
scripts/Kbuild.include
scripts/Makefile.lib
scripts/Makefile.modbuiltin [new file with mode: 0644]
scripts/basic/fixdep.c
scripts/genksyms/keywords.c_shipped
scripts/genksyms/keywords.gperf
scripts/headers.sh
scripts/kconfig/Makefile
scripts/kconfig/confdata.c
scripts/mkcompile_h
scripts/mod/modpost.c
scripts/package/Makefile
scripts/package/buildtar
scripts/tags.sh
scripts/unifdef.c
usr/gen_init_cpio.c

index 946c7ec5c922ff5bb02726144178f56f57c3378d..fb2190c61af0982ae9b8792b51d970bddaafdf5f 100644 (file)
@@ -22,6 +22,7 @@
 *.lst
 *.symtypes
 *.order
+modules.builtin
 *.elf
 *.bin
 *.gz
@@ -45,14 +46,8 @@ Module.symvers
 #
 # Generated include files
 #
-include/asm
-include/asm-*/asm-offsets.h
 include/config
-include/linux/autoconf.h
-include/linux/compile.h
 include/linux/version.h
-include/linux/utsrelease.h
-include/linux/bounds.h
 include/generated
 
 # stgit generated dirs
index e151b2a36267c17fdb7da317e309bea3de408a4b..3ad6acead94950a3b83e4f14912e01cc64973b6b 100644 (file)
@@ -103,6 +103,7 @@ gconf
 gen-devlist
 gen_crc32table
 gen_init_cpio
+generated
 genheaders
 genksyms
 *_gray256.c
index bb3bf38f03dac1e055dc973ce65d49d14defbe42..6f8c1cabbc5d1fefe2a18d3c77354b54426d3363 100644 (file)
@@ -1,3 +1,17 @@
+Output files
+
+modules.order
+--------------------------------------------------
+This file records the order in which modules appear in Makefiles. This
+is used by modprobe to deterministically resolve aliases that match
+multiple modules.
+
+modules.builtin
+--------------------------------------------------
+This file lists all modules that are built into the kernel. This is used
+by modprobe to not fail when trying to load something builtin.
+
+
 Environment variables
 
 KCPPFLAGS
index 849b5e56d06fc95927f47aaa8b006cfb73cf34c6..49efae703979ca793383463bce7c2d1eda42468b 100644 (file)
@@ -103,10 +103,16 @@ KCONFIG_AUTOCONFIG
 This environment variable can be set to specify the path & name of the
 "auto.conf" file.  Its default value is "include/config/auto.conf".
 
+KCONFIG_TRISTATE
+--------------------------------------------------
+This environment variable can be set to specify the path & name of the
+"tristate.conf" file.  Its default value is "include/config/tristate.conf".
+
 KCONFIG_AUTOHEADER
 --------------------------------------------------
 This environment variable can be set to specify the path & name of the
-"autoconf.h" (header) file.  Its default value is "include/linux/autoconf.h".
+"autoconf.h" (header) file.
+Its default value is "include/generated/autoconf.h".
 
 
 ======================================================================
diff --git a/Kbuild b/Kbuild
index f056b4feee519748ae6ef22fde3df1da532e177b..e3737ad72b5a7ab8ad916b5b6b2725eaf89122a1 100644 (file)
--- a/Kbuild
+++ b/Kbuild
@@ -8,7 +8,7 @@
 #####
 # 1) Generate bounds.h
 
-bounds-file := include/linux/bounds.h
+bounds-file := include/generated/bounds.h
 
 always  := $(bounds-file)
 targets := $(bounds-file) kernel/bounds.s
@@ -43,7 +43,7 @@ $(obj)/$(bounds-file): kernel/bounds.s Kbuild
 # 2) Generate asm-offsets.h
 #
 
-offsets-file := include/asm/asm-offsets.h
+offsets-file := include/generated/asm-offsets.h
 
 always  += $(offsets-file)
 targets += $(offsets-file)
index 0699782f8c5bf869eb65059454ef4de1e909f04c..efd2ef2c266073d39e8611a1bd6e5dbd38646f41 100644 (file)
@@ -5434,6 +5434,12 @@ F:       drivers/uwb/*
 F:     include/linux/uwb.h
 F:     include/linux/uwb/
 
+UNIFDEF
+M:     Tony Finch <dot@dotat.at>
+W:     http://dotat.at/prog/unifdef
+S:     Maintained
+F:     scripts/unifdef.c
+
 UNIFORM CDROM DRIVER
 M:     Jens Axboe <axboe@kernel.dk>
 W:     http://www.kernel.dk
index 33d4732a6c4a319c4479933c826dd37be489684b..8491b21b553727ce472ed9929226c0378fae7542 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -334,10 +334,9 @@ CFLAGS_GCOV        = -fprofile-arcs -ftest-coverage
 
 # Use LINUXINCLUDE when you must reference the include/ directory.
 # Needed to be compatible with the O= option
-LINUXINCLUDE    := -Iinclude \
-                   $(if $(KBUILD_SRC),-Iinclude2 -I$(srctree)/include) \
-                   -I$(srctree)/arch/$(hdr-arch)/include               \
-                   -include include/linux/autoconf.h
+LINUXINCLUDE    := -I$(srctree)/arch/$(hdr-arch)/include -Iinclude \
+                   $(if $(KBUILD_SRC), -I$(srctree)/include) \
+                   -include include/generated/autoconf.h
 
 KBUILD_CPPFLAGS := -D__KERNEL__
 
@@ -465,7 +464,7 @@ ifeq ($(KBUILD_EXTMOD),)
 # Carefully list dependencies so we do not try to build scripts twice
 # in parallel
 PHONY += scripts
-scripts: scripts_basic include/config/auto.conf
+scripts: scripts_basic include/config/auto.conf include/config/tristate.conf
        $(Q)$(MAKE) $(build)=$(@)
 
 # Objects we will link into vmlinux / subdirs we need to visit
@@ -492,18 +491,18 @@ $(KCONFIG_CONFIG) include/config/auto.conf.cmd: ;
 # with it and forgot to run make oldconfig.
 # if auto.conf.cmd is missing then we are probably in a cleaned tree so
 # we execute the config step to be sure to catch updated Kconfig files
-include/config/auto.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd
+include/config/%.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd
        $(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig
 else
-# external modules needs include/linux/autoconf.h and include/config/auto.conf
+# external modules needs include/generated/autoconf.h and include/config/auto.conf
 # but do not care if they are up-to-date. Use auto.conf to trigger the test
 PHONY += include/config/auto.conf
 
 include/config/auto.conf:
-       $(Q)test -e include/linux/autoconf.h -a -e $@ || (              \
+       $(Q)test -e include/generated/autoconf.h -a -e $@ || (          \
        echo;                                                           \
        echo "  ERROR: Kernel configuration is invalid.";               \
-       echo "         include/linux/autoconf.h or $@ are missing.";    \
+       echo "         include/generated/autoconf.h or $@ are missing.";\
        echo "         Run 'make oldconfig && make prepare' on kernel src to fix it.";  \
        echo;                                                           \
        /bin/false)
@@ -877,6 +876,9 @@ $(sort $(vmlinux-init) $(vmlinux-main)) $(vmlinux-lds): $(vmlinux-dirs) ;
 PHONY += $(vmlinux-dirs)
 $(vmlinux-dirs): prepare scripts
        $(Q)$(MAKE) $(build)=$@
+ifdef CONFIG_MODULES
+       $(Q)$(MAKE) $(modbuiltin)=$@
+endif
 
 # Build the kernel release string
 #
@@ -955,7 +957,6 @@ PHONY += prepare archprepare prepare0 prepare1 prepare2 prepare3
 # prepare3 is used to check if we are building in a separate output directory,
 # and if so do:
 # 1) Check that make has not been executed in the kernel src $(srctree)
-# 2) Create the include2 directory, used for the second asm symlink
 prepare3: include/config/kernel.release
 ifneq ($(KBUILD_SRC),)
        @$(kecho) '  Using $(srctree) as source for kernel'
@@ -964,17 +965,13 @@ ifneq ($(KBUILD_SRC),)
                echo "  in the '$(srctree)' directory.";\
                /bin/false; \
        fi;
-       $(Q)if [ ! -d include2 ]; then                                  \
-           mkdir -p include2;                                          \
-           ln -fsn $(srctree)/include/asm-$(SRCARCH) include2/asm;     \
-       fi
 endif
 
 # prepare2 creates a makefile if using a separate output directory
 prepare2: prepare3 outputmakefile
 
-prepare1: prepare2 include/linux/version.h include/linux/utsrelease.h \
-                   include/asm include/config/auto.conf
+prepare1: prepare2 include/linux/version.h include/generated/utsrelease.h \
+                   include/config/auto.conf
        $(cmd_crmodverdir)
 
 archprepare: prepare1 scripts_basic
@@ -986,42 +983,6 @@ prepare0: archprepare FORCE
 # All the preparing..
 prepare: prepare0
 
-# The asm symlink changes when $(ARCH) changes.
-# Detect this and ask user to run make mrproper
-# If asm is a stale symlink (point to dir that does not exist) remove it
-define check-symlink
-       set -e;                                                            \
-       if [ -L include/asm ]; then                                        \
-               asmlink=`readlink include/asm | cut -d '-' -f 2`;          \
-               if [ "$$asmlink" != "$(SRCARCH)" ]; then                   \
-                       echo "ERROR: the symlink $@ points to asm-$$asmlink but asm-$(SRCARCH) was expected"; \
-                       echo "       set ARCH or save .config and run 'make mrproper' to fix it";             \
-                       exit 1;                                            \
-               fi;                                                        \
-               test -e $$asmlink || rm include/asm;                       \
-       elif [ -d include/asm ]; then                                      \
-               echo "ERROR: $@ is a directory but a symlink was expected";\
-               exit 1;                                                    \
-       fi
-endef
-
-# We create the target directory of the symlink if it does
-# not exist so the test in check-symlink works and we have a
-# directory for generated filesas used by some architectures.
-define create-symlink
-       if [ ! -L include/asm ]; then                                      \
-                       $(kecho) '  SYMLINK $@ -> include/asm-$(SRCARCH)'; \
-                       if [ ! -d include/asm-$(SRCARCH) ]; then           \
-                               mkdir -p include/asm-$(SRCARCH);           \
-                       fi;                                                \
-                       ln -fsn asm-$(SRCARCH) $@;                         \
-       fi
-endef
-
-include/asm: FORCE
-       $(Q)$(check-symlink)
-       $(Q)$(create-symlink)
-
 # Generate some files
 # ---------------------------------------------------------------------------
 
@@ -1046,7 +1007,7 @@ endef
 include/linux/version.h: $(srctree)/Makefile FORCE
        $(call filechk,version.h)
 
-include/linux/utsrelease.h: include/config/kernel.release FORCE
+include/generated/utsrelease.h: include/config/kernel.release FORCE
        $(call filechk,utsrelease.h)
 
 PHONY += headerdep
@@ -1076,11 +1037,6 @@ firmware_install: FORCE
 export INSTALL_HDR_PATH = $(objtree)/usr
 
 hdr-inst := -rR -f $(srctree)/scripts/Makefile.headersinst obj
-# Find out where the Kbuild file is located to support
-# arch/$(ARCH)/include/asm
-hdr-dir = $(strip                                                         \
-          $(if $(wildcard $(srctree)/arch/$(hdr-arch)/include/asm/Kbuild), \
-               arch/$(hdr-arch)/include/asm, include/asm-$(hdr-arch)))
 
 # If we do an all arch process set dst to asm-$(hdr-arch)
 hdr-dst = $(if $(KBUILD_HEADERS), dst=include/asm-$(hdr-arch), dst=include/asm)
@@ -1095,10 +1051,10 @@ headers_install_all:
 
 PHONY += headers_install
 headers_install: __headers
-       $(if $(wildcard $(srctree)/$(hdr-dir)/Kbuild),, \
+       $(if $(wildcard $(srctree)/arch/$(hdr-arch)/include/asm/Kbuild),, \
        $(error Headers not exportable for the $(SRCARCH) architecture))
        $(Q)$(MAKE) $(hdr-inst)=include
-       $(Q)$(MAKE) $(hdr-inst)=$(hdr-dir) $(hdr-dst)
+       $(Q)$(MAKE) $(hdr-inst)=arch/$(hdr-arch)/include/asm $(hdr-dst)
 
 PHONY += headers_check_all
 headers_check_all: headers_install_all
@@ -1107,7 +1063,7 @@ headers_check_all: headers_install_all
 PHONY += headers_check
 headers_check: headers_install
        $(Q)$(MAKE) $(hdr-inst)=include HDRCHECK=1
-       $(Q)$(MAKE) $(hdr-inst)=$(hdr-dir) $(hdr-dst) HDRCHECK=1
+       $(Q)$(MAKE) $(hdr-inst)=arch/$(hdr-arch)/include/asm $(hdr-dst) HDRCHECK=1
 
 # ---------------------------------------------------------------------------
 # Modules
@@ -1127,6 +1083,7 @@ all: modules
 PHONY += modules
 modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux)
        $(Q)$(AWK) '!x[$$0]++' $(vmlinux-dirs:%=$(objtree)/%/modules.order) > $(objtree)/modules.order
+       $(Q)$(AWK) '!x[$$0]++' $(vmlinux-dirs:%=$(objtree)/%/modules.builtin) > $(objtree)/modules.builtin
        @$(kecho) '  Building modules, stage 2.';
        $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost
        $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.fwinst obj=firmware __fw_modbuild
@@ -1156,6 +1113,7 @@ _modinst_:
                ln -s $(objtree) $(MODLIB)/build ; \
        fi
        @cp -f $(objtree)/modules.order $(MODLIB)/
+       @cp -f $(objtree)/modules.builtin $(MODLIB)/
        $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modinst
 
 # This depmod is only for convenience to give the initial
@@ -1194,12 +1152,10 @@ CLEAN_FILES +=  vmlinux System.map \
                 .tmp_kallsyms* .tmp_version .tmp_vmlinux* .tmp_System.map
 
 # Directories & files removed with 'make mrproper'
-MRPROPER_DIRS  += include/config include2 usr/include include/generated
-MRPROPER_FILES += .config .config.old include/asm .version .old_version \
-                  include/linux/autoconf.h include/linux/version.h      \
-                  include/linux/utsrelease.h                            \
-                  include/linux/bounds.h include/asm*/asm-offsets.h     \
-                 Module.symvers Module.markers tags TAGS cscope*
+MRPROPER_DIRS  += include/config usr/include include/generated
+MRPROPER_FILES += .config .config.old .version .old_version             \
+                  include/linux/version.h                               \
+                 Module.symvers tags TAGS cscope*
 
 # clean - Delete most, but leave enough to build external modules
 #
@@ -1218,7 +1174,7 @@ clean: archclean $(clean-dirs)
                \( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \
                -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
                -o -name '*.symtypes' -o -name 'modules.order' \
-               -o -name 'Module.markers' -o -name '.tmp_*.o.*' \
+               -o -name modules.builtin -o -name '.tmp_*.o.*' \
                -o -name '*.gcno' \) -type f -print | xargs rm -f
 
 # mrproper - Delete all generated files, including .config
@@ -1416,8 +1372,8 @@ $(clean-dirs):
 
 clean: rm-dirs := $(MODVERDIR)
 clean: rm-files := $(KBUILD_EXTMOD)/Module.symvers \
-                   $(KBUILD_EXTMOD)/Module.markers \
-                   $(KBUILD_EXTMOD)/modules.order
+                   $(KBUILD_EXTMOD)/modules.order \
+                   $(KBUILD_EXTMOD)/modules.builtin
 clean: $(clean-dirs)
        $(call cmd,rmdirs)
        $(call cmd,rmfiles)
index 3af21c78933943df7e3750b3d61d3fd391581b87..3c8d1b25c66105b3fb34f9b693c712d9b3d05d52 100644 (file)
@@ -9,7 +9,7 @@
  */
 #include <linux/kernel.h>
 #include <linux/string.h>
-#include <linux/utsrelease.h>
+#include <generated/utsrelease.h>
 #include <linux/mm.h>
 
 #include <asm/system.h>
index 1036b515e20c80f55fa04db8c8dbd88ac7c749c0..ade3f129dc2722e26168495bdc28066d24fcd609 100644 (file)
@@ -11,7 +11,7 @@
  */
 #include <linux/kernel.h>
 #include <linux/string.h>
-#include <linux/utsrelease.h>
+#include <generated/utsrelease.h>
 #include <linux/mm.h>
 
 #include <asm/system.h>
index 89f3be071ae5df5f947c7d7ee9fb888e93fa2912..644b7db55438f4f1d1b8136bd9f680bbcf4f75a8 100644 (file)
@@ -7,7 +7,7 @@
  */
 #include <linux/kernel.h>
 #include <linux/string.h>
-#include <linux/utsrelease.h>
+#include <generated/utsrelease.h>
 #include <linux/mm.h>
 
 #include <asm/system.h>
diff --git a/arch/alpha/include/asm/asm-offsets.h b/arch/alpha/include/asm/asm-offsets.h
new file mode 100644 (file)
index 0000000..d370ee3
--- /dev/null
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
index 21b1117a0c61344af1acc94c36dc2f6e475d67a0..70145cbb21cb48ff27cbbe949d0c519f6bd55565 100644 (file)
@@ -16,7 +16,7 @@
 #define O_NOATIME      04000000
 #define O_CLOEXEC      010000000 /* set close_on_exec */
 /*
- * Before Linux 2.6.32 only O_DSYNC semantics were implemented, but using
+ * Before Linux 2.6.33 only O_DSYNC semantics were implemented, but using
  * the O_SYNC flag.  We continue to use the existing numerical value
  * for O_DSYNC semantics now, but using the correct symbolic name for it.
  * This new value is used to request true Posix O_SYNC semantics.  It is
index fa0cdab2e1d3109d75418f2022314dd796f8f0da..e9da08483b3cdb74bd687cf3601ec4dccf395c25 100644 (file)
@@ -242,15 +242,8 @@ all:       $(KBUILD_IMAGE)
 
 boot := arch/arm/boot
 
-#      Update machine arch and proc symlinks if something which affects
-#      them changed.  We use .arch to indicate when they were updated
-#      last, otherwise make uses the target directory mtime.
-
-archprepare: maketools
-
-PHONY += maketools FORCE
-maketools: include/linux/version.h FORCE
-       $(Q)$(MAKE) $(build)=arch/arm/tools include/asm-arm/mach-types.h
+archprepare:
+       $(Q)$(MAKE) $(build)=arch/arm/tools include/generated/mach-types.h
 
 # Convert bzImage to zImage
 bzImage: zImage
@@ -261,9 +254,6 @@ zImage Image xipImage bootpImage uImage: vmlinux
 zinstall install: vmlinux
        $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@
 
-CLEAN_FILES += include/asm-arm/mach-types.h \
-              include/asm-arm/arch include/asm-arm/.arch
-
 # We use MRPROPER_FILES and CLEAN_FILES now
 archclean:
        $(Q)$(MAKE) $(clean)=$(boot)
index 5a375e5fef21766c3a5120c16c7cd2f8929b42ea..bc90364a96c7bf364fdd10aa198a0d93ab2af2b3 100644 (file)
@@ -308,15 +308,11 @@ static inline void unmap_single(struct device *dev, dma_addr_t dma_addr,
                        memcpy(ptr, buf->safe, size);
 
                        /*
-                        * DMA buffers must have the same cache properties
-                        * as if they were really used for DMA - which means
-                        * data must be written back to RAM.  Note that
-                        * we don't use dmac_flush_range() here for the
-                        * bidirectional case because we know the cache
-                        * lines will be coherent with the data written.
+                        * Since we may have written to a page cache page,
+                        * we need to ensure that the data will be coherent
+                        * with user mappings.
                         */
-                       dmac_clean_range(ptr, ptr + size);
-                       outer_clean_range(__pa(ptr), __pa(ptr) + size);
+                       __cpuc_flush_kernel_dcache_area(ptr, size);
                }
                free_safe_buffer(dev->archdata.dmabounce, buf);
        }
diff --git a/arch/arm/include/asm/asm-offsets.h b/arch/arm/include/asm/asm-offsets.h
new file mode 100644 (file)
index 0000000..d370ee3
--- /dev/null
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
index 73eceb87e58869ffa978bf35cc71b015a2d40d03..730aefcfbee3eb8e0c46ea0a6dc0b9ba0fd1e27f 100644 (file)
@@ -211,7 +211,7 @@ struct cpu_cache_fns {
 
        void (*coherent_kern_range)(unsigned long, unsigned long);
        void (*coherent_user_range)(unsigned long, unsigned long);
-       void (*flush_kern_dcache_page)(void *);
+       void (*flush_kern_dcache_area)(void *, size_t);
 
        void (*dma_inv_range)(const void *, const void *);
        void (*dma_clean_range)(const void *, const void *);
@@ -236,7 +236,7 @@ extern struct cpu_cache_fns cpu_cache;
 #define __cpuc_flush_user_range                cpu_cache.flush_user_range
 #define __cpuc_coherent_kern_range     cpu_cache.coherent_kern_range
 #define __cpuc_coherent_user_range     cpu_cache.coherent_user_range
-#define __cpuc_flush_dcache_page       cpu_cache.flush_kern_dcache_page
+#define __cpuc_flush_dcache_area       cpu_cache.flush_kern_dcache_area
 
 /*
  * These are private to the dma-mapping API.  Do not use directly.
@@ -255,14 +255,14 @@ extern struct cpu_cache_fns cpu_cache;
 #define __cpuc_flush_user_range                __glue(_CACHE,_flush_user_cache_range)
 #define __cpuc_coherent_kern_range     __glue(_CACHE,_coherent_kern_range)
 #define __cpuc_coherent_user_range     __glue(_CACHE,_coherent_user_range)
-#define __cpuc_flush_dcache_page       __glue(_CACHE,_flush_kern_dcache_page)
+#define __cpuc_flush_dcache_area       __glue(_CACHE,_flush_kern_dcache_area)
 
 extern void __cpuc_flush_kern_all(void);
 extern void __cpuc_flush_user_all(void);
 extern void __cpuc_flush_user_range(unsigned long, unsigned long, unsigned int);
 extern void __cpuc_coherent_kern_range(unsigned long, unsigned long);
 extern void __cpuc_coherent_user_range(unsigned long, unsigned long);
-extern void __cpuc_flush_dcache_page(void *);
+extern void __cpuc_flush_dcache_area(void *, size_t);
 
 /*
  * These are private to the dma-mapping API.  Do not use directly.
@@ -448,7 +448,7 @@ static inline void flush_kernel_dcache_page(struct page *page)
 {
        /* highmem pages are always flushed upon kunmap already */
        if ((cache_is_vivt() || cache_is_vipt_aliasing()) && !PageHighMem(page))
-               __cpuc_flush_dcache_page(page_address(page));
+               __cpuc_flush_dcache_area(page_address(page), PAGE_SIZE);
 }
 
 #define flush_dcache_mmap_lock(mapping) \
@@ -465,13 +465,6 @@ static inline void flush_kernel_dcache_page(struct page *page)
  */
 #define flush_icache_page(vma,page)    do { } while (0)
 
-static inline void flush_ioremap_region(unsigned long phys, void __iomem *virt,
-       unsigned offset, size_t size)
-{
-       const void *start = (void __force *)virt + offset;
-       dmac_inv_range(start, start + size);
-}
-
 /*
  * flush_cache_vmap() is used when creating mappings (eg, via vmap,
  * vmalloc, ioremap etc) in kernel space for pages.  On non-VIPT
diff --git a/arch/arm/include/asm/mach-types.h b/arch/arm/include/asm/mach-types.h
new file mode 100644 (file)
index 0000000..948178c
--- /dev/null
@@ -0,0 +1 @@
+#include <generated/mach-types.h>
index 8bf09ae5b347dd19351a491d0c55d4c27ea0f614..f6c6196a51fa489cb1338a9ced5a06e0e6f52cb9 100644 (file)
@@ -52,6 +52,12 @@ config MACH_OPENRD_BASE
          Say 'Y' here if you want your kernel to support the
          Marvell OpenRD Base Board.
 
+config MACH_NETSPACE_V2
+       bool "LaCie Network Space v2 NAS Board"
+       help
+         Say 'Y' here if you want your kernel to support the
+         LaCie Network Space v2 NAS.
+
 endmenu
 
 endif
index 9f2f67b2b63d92aafc166a73ff86906ec837a12f..d4d7f53b0fb9d51c6b4cba7174c6749944e4bdc9 100644 (file)
@@ -8,5 +8,6 @@ obj-$(CONFIG_MACH_SHEEVAPLUG)           += sheevaplug-setup.o
 obj-$(CONFIG_MACH_TS219)               += ts219-setup.o tsx1x-common.o
 obj-$(CONFIG_MACH_TS41X)               += ts41x-setup.o tsx1x-common.o
 obj-$(CONFIG_MACH_OPENRD_BASE)         += openrd_base-setup.o
+obj-$(CONFIG_MACH_NETSPACE_V2)         += netspace_v2-setup.o
 
 obj-$(CONFIG_CPU_IDLE)                 += cpuidle.o
diff --git a/arch/arm/mach-kirkwood/netspace_v2-setup.c b/arch/arm/mach-kirkwood/netspace_v2-setup.c
new file mode 100644 (file)
index 0000000..9a06406
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+ * arch/arm/mach-kirkwood/netspace_v2-setup.c
+ *
+ * LaCie Network Space v2 board setup
+ *
+ * Copyright (C) 2009 Simon Guinot <sguinot@lacie.com>
+ * Copyright (C) 2009 Benoît Canet <benoit.canet@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/physmap.h>
+#include <linux/spi/flash.h>
+#include <linux/spi/spi.h>
+#include <linux/ata_platform.h>
+#include <linux/mv643xx_eth.h>
+#include <linux/i2c.h>
+#include <linux/i2c/at24.h>
+#include <linux/input.h>
+#include <linux/gpio.h>
+#include <linux/gpio_keys.h>
+#include <linux/leds.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <mach/kirkwood.h>
+#include <plat/time.h>
+#include "common.h"
+#include "mpp.h"
+
+/*****************************************************************************
+ * 512KB SPI Flash on Boot Device (MACRONIX MX25L4005)
+ ****************************************************************************/
+
+static struct mtd_partition netspace_v2_flash_parts[] = {
+       {
+               .name = "u-boot",
+               .size = MTDPART_SIZ_FULL,
+               .offset = 0,
+               .mask_flags = MTD_WRITEABLE, /* force read-only */
+       },
+};
+
+static const struct flash_platform_data netspace_v2_flash = {
+       .type           = "mx25l4005a",
+       .name           = "spi_flash",
+       .parts          = netspace_v2_flash_parts,
+       .nr_parts       = ARRAY_SIZE(netspace_v2_flash_parts),
+};
+
+static struct spi_board_info __initdata netspace_v2_spi_slave_info[] = {
+       {
+               .modalias       = "m25p80",
+               .platform_data  = &netspace_v2_flash,
+               .irq            = -1,
+               .max_speed_hz   = 20000000,
+               .bus_num        = 0,
+               .chip_select    = 0,
+       },
+};
+
+/*****************************************************************************
+ * Ethernet
+ ****************************************************************************/
+
+static struct mv643xx_eth_platform_data netspace_v2_ge00_data = {
+       .phy_addr       = MV643XX_ETH_PHY_ADDR(8),
+};
+
+/*****************************************************************************
+ * I2C devices
+ ****************************************************************************/
+
+static struct at24_platform_data at24c04 = {
+       .byte_len       = SZ_4K / 8,
+       .page_size      = 16,
+};
+
+/*
+ * i2c addr | chip         | description
+ * 0x50     | HT24LC04     | eeprom (512B)
+ */
+
+static struct i2c_board_info __initdata netspace_v2_i2c_info[] = {
+       {
+               I2C_BOARD_INFO("24c04", 0x50),
+               .platform_data  = &at24c04,
+       }
+};
+
+/*****************************************************************************
+ * SATA
+ ****************************************************************************/
+
+static struct mv_sata_platform_data netspace_v2_sata_data = {
+       .n_ports        = 2,
+};
+
+#define NETSPACE_V2_GPIO_SATA0_POWER   16
+#define NETSPACE_V2_GPIO_SATA1_POWER   17
+
+static void __init netspace_v2_sata_power_init(void)
+{
+       int err;
+
+       err = gpio_request(NETSPACE_V2_GPIO_SATA0_POWER, "SATA0 power");
+       if (err == 0) {
+               err = gpio_direction_output(NETSPACE_V2_GPIO_SATA0_POWER, 1);
+               if (err)
+                       gpio_free(NETSPACE_V2_GPIO_SATA0_POWER);
+       }
+       if (err)
+               pr_err("netspace_v2: failed to setup SATA0 power\n");
+}
+
+/*****************************************************************************
+ * GPIO keys
+ ****************************************************************************/
+
+#define NETSPACE_V2_PUSH_BUTTON                32
+
+static struct gpio_keys_button netspace_v2_buttons[] = {
+       [0] = {
+               .code           = KEY_POWER,
+               .gpio           = NETSPACE_V2_PUSH_BUTTON,
+               .desc           = "Power push button",
+               .active_low     = 0,
+       },
+};
+
+static struct gpio_keys_platform_data netspace_v2_button_data = {
+       .buttons        = netspace_v2_buttons,
+       .nbuttons       = ARRAY_SIZE(netspace_v2_buttons),
+};
+
+static struct platform_device netspace_v2_gpio_buttons = {
+       .name           = "gpio-keys",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &netspace_v2_button_data,
+       },
+};
+
+/*****************************************************************************
+ * GPIO LEDs
+ ****************************************************************************/
+
+/*
+ * The blue front LED is wired to a CPLD and can blink in relation with the
+ * SATA activity.
+ *
+ * The following array detail the different LED registers and the combination
+ * of their possible values:
+ *
+ *  cmd_led   |  slow_led  | /SATA active | LED state
+ *            |            |              |
+ *     1      |     0      |      x       |  off
+ *     -      |     1      |      x       |  on
+ *     0      |     0      |      1       |  on
+ *     0      |     0      |      0       |  blink (rate 300ms)
+ */
+
+#define NETSPACE_V2_GPIO_RED_LED       12
+#define NETSPACE_V2_GPIO_BLUE_LED_SLOW 29
+#define NETSPACE_V2_GPIO_BLUE_LED_CMD  30
+
+
+static struct gpio_led netspace_v2_gpio_led_pins[] = {
+       {
+               .name   = "ns_v2:red:fail",
+               .gpio   = NETSPACE_V2_GPIO_RED_LED,
+       },
+};
+
+static struct gpio_led_platform_data netspace_v2_gpio_leds_data = {
+       .num_leds       = ARRAY_SIZE(netspace_v2_gpio_led_pins),
+       .leds           = netspace_v2_gpio_led_pins,
+};
+
+static struct platform_device netspace_v2_gpio_leds = {
+       .name           = "leds-gpio",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &netspace_v2_gpio_leds_data,
+       },
+};
+
+static void __init netspace_v2_gpio_leds_init(void)
+{
+       platform_device_register(&netspace_v2_gpio_leds);
+
+       /*
+        * Configure the front blue LED to blink in relation with the SATA
+        * activity.
+        */
+       if (gpio_request(NETSPACE_V2_GPIO_BLUE_LED_SLOW,
+                        "SATA blue LED slow") != 0)
+               return;
+       if (gpio_direction_output(NETSPACE_V2_GPIO_BLUE_LED_SLOW, 0) != 0)
+               goto err_free_1;
+       if (gpio_request(NETSPACE_V2_GPIO_BLUE_LED_CMD,
+                        "SATA blue LED command") != 0)
+               goto err_free_1;
+       if (gpio_direction_output(NETSPACE_V2_GPIO_BLUE_LED_CMD, 0) != 0)
+               goto err_free_2;
+
+       return;
+
+err_free_2:
+       gpio_free(NETSPACE_V2_GPIO_BLUE_LED_CMD);
+err_free_1:
+       gpio_free(NETSPACE_V2_GPIO_BLUE_LED_SLOW);
+       pr_err("netspace_v2: failed to configure SATA blue LED\n");
+}
+
+/*****************************************************************************
+ * Timer
+ ****************************************************************************/
+
+static void netspace_v2_timer_init(void)
+{
+       kirkwood_tclk = 166666667;
+       orion_time_init(IRQ_KIRKWOOD_BRIDGE, kirkwood_tclk);
+}
+
+struct sys_timer netspace_v2_timer = {
+       .init = netspace_v2_timer_init,
+};
+
+/*****************************************************************************
+ * General Setup
+ ****************************************************************************/
+
+static unsigned int netspace_v2_mpp_config[] __initdata = {
+       MPP0_SPI_SCn,
+       MPP1_SPI_MOSI,
+       MPP2_SPI_SCK,
+       MPP3_SPI_MISO,
+       MPP4_NF_IO6,
+       MPP5_NF_IO7,
+       MPP6_SYSRST_OUTn,
+       MPP8_TW_SDA,
+       MPP9_TW_SCK,
+       MPP10_UART0_TXD,
+       MPP11_UART0_RXD,
+       MPP12_GPO,              /* Red led */
+       MPP14_GPIO,             /* USB fuse */
+       MPP16_GPIO,             /* SATA 0 power */
+       MPP18_NF_IO0,
+       MPP19_NF_IO1,
+       MPP20_SATA1_ACTn,
+       MPP21_SATA0_ACTn,
+       MPP24_GPIO,             /* USB mode select */
+       MPP25_GPIO,             /* Fan rotation fail */
+       MPP26_GPIO,             /* USB device vbus */
+       MPP28_GPIO,             /* USB enable host vbus */
+       MPP29_GPIO,             /* Blue led (slow register) */
+       MPP30_GPIO,             /* Blue led (command register) */
+       MPP31_GPIO,             /* Board power off */
+       MPP32_GPIO,             /* Power button (0 = Released, 1 = Pushed) */
+       0
+};
+
+#define NETSPACE_V2_GPIO_POWER_OFF     31
+
+static void netspace_v2_power_off(void)
+{
+       gpio_set_value(NETSPACE_V2_GPIO_POWER_OFF, 1);
+}
+
+static void __init netspace_v2_init(void)
+{
+       /*
+        * Basic setup. Needs to be called early.
+        */
+       kirkwood_init();
+       kirkwood_mpp_conf(netspace_v2_mpp_config);
+
+       netspace_v2_sata_power_init();
+
+       kirkwood_ehci_init();
+       kirkwood_ge00_init(&netspace_v2_ge00_data);
+       kirkwood_sata_init(&netspace_v2_sata_data);
+       kirkwood_uart0_init();
+       spi_register_board_info(netspace_v2_spi_slave_info,
+                               ARRAY_SIZE(netspace_v2_spi_slave_info));
+       kirkwood_spi_init();
+       kirkwood_i2c_init();
+       i2c_register_board_info(0, netspace_v2_i2c_info,
+                               ARRAY_SIZE(netspace_v2_i2c_info));
+
+       netspace_v2_gpio_leds_init();
+       platform_device_register(&netspace_v2_gpio_buttons);
+
+       if (gpio_request(NETSPACE_V2_GPIO_POWER_OFF, "power-off") == 0 &&
+           gpio_direction_output(NETSPACE_V2_GPIO_POWER_OFF, 0) == 0)
+               pm_power_off = netspace_v2_power_off;
+       else
+               pr_err("netspace_v2: failed to configure power-off GPIO\n");
+}
+
+MACHINE_START(NETSPACE_V2, "LaCie Network Space v2")
+       .phys_io        = KIRKWOOD_REGS_PHYS_BASE,
+       .io_pg_offst    = ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
+       .boot_params    = 0x00000100,
+       .init_machine   = netspace_v2_init,
+       .map_io         = kirkwood_map_io,
+       .init_irq       = kirkwood_init_irq,
+       .timer          = &netspace_v2_timer,
+MACHINE_END
index e6d8e10ae5d1fe74c8e8b17414a325c69a763f6c..8a0837ea0294218a6f9ed85d43ba4862d4afc3fd 100644 (file)
@@ -110,6 +110,8 @@ config MACH_CM_X300
        bool "CompuLab CM-X300 modules"
        select PXA3xx
        select CPU_PXA300
+       select CPU_PXA310
+       select HAVE_PWM
 
 config ARCH_GUMSTIX
        bool "Gumstix XScale 255 boards"
@@ -240,7 +242,6 @@ config MACH_COLIBRI300
        select PXA3xx
        select CPU_PXA300
        select CPU_PXA310
-       select HAVE_PWM
 
 config MACH_COLIBRI320
        bool "Toradex Colibri PXA320"
index 3395463bb5a654e6327a51028c17a4ce0dfd6301..8e10db148f1b2cccdc70b07ba0785b280a80dcfc 100644 (file)
@@ -4,7 +4,6 @@
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 
-#include <mach/hardware.h>
 #include <mach/udc.h>
 #include <mach/pxafb.h>
 #include <mach/mmc.h>
@@ -14,6 +13,7 @@
 #include <mach/pxa2xx_spi.h>
 #include <mach/camera.h>
 #include <mach/audio.h>
+#include <mach/hardware.h>
 #include <plat/i2c.h>
 #include <plat/pxa3xx_nand.h>
 
index 193b39d654edc41b4ef9569b5d2927c29751f87d..4d9588373aa55a624de6ac4e8c451fe7dca0759e 100644 (file)
@@ -18,6 +18,8 @@ struct s3c2410_spi_info {
        unsigned int             num_cs;        /* total chipselects */
        int                      bus_num;       /* bus number to use. */
 
+       unsigned int             use_fiq:1;     /* use fiq */
+
        void (*gpio_setup)(struct s3c2410_spi_info *spi, int enable);
        void (*set_cs)(struct s3c2410_spi_info *spi, int cs, int pol);
 };
index b63a8f7b95cf5a2575f012b91324cc2e273563cf..a89444a3c016f0c2ecee35d38655b109664bc91b 100644 (file)
@@ -127,15 +127,16 @@ ENTRY(fa_coherent_user_range)
        mov     pc, lr
 
 /*
- *     flush_kern_dcache_page(kaddr)
+ *     flush_kern_dcache_area(void *addr, size_t size)
  *
  *     Ensure that the data held in the page kaddr is written back
  *     to the page in question.
  *
- *     - kaddr   - kernel address (guaranteed to be page aligned)
+ *     - addr  - kernel address
+ *     - size  - size of region
  */
-ENTRY(fa_flush_kern_dcache_page)
-       add     r1, r0, #PAGE_SZ
+ENTRY(fa_flush_kern_dcache_area)
+       add     r1, r0, r1
 1:     mcr     p15, 0, r0, c7, c14, 1          @ clean & invalidate D line
        add     r0, r0, #CACHE_DLINESIZE
        cmp     r0, r1
@@ -213,7 +214,7 @@ ENTRY(fa_cache_fns)
        .long   fa_flush_user_cache_range
        .long   fa_coherent_kern_range
        .long   fa_coherent_user_range
-       .long   fa_flush_kern_dcache_page
+       .long   fa_flush_kern_dcache_area
        .long   fa_dma_inv_range
        .long   fa_dma_clean_range
        .long   fa_dma_flush_range
index 747f9a9021bb9d97de9e22d13b04bb5c38ecc15b..cb8fc6573b1b2c9dedbeeec0f9a87c491a78ba85 100644 (file)
 static void __iomem *l2x0_base;
 static DEFINE_SPINLOCK(l2x0_lock);
 
-static inline void sync_writel(unsigned long val, unsigned long reg,
-                              unsigned long complete_mask)
+static inline void cache_wait(void __iomem *reg, unsigned long mask)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&l2x0_lock, flags);
-       writel(val, l2x0_base + reg);
        /* wait for the operation to complete */
-       while (readl(l2x0_base + reg) & complete_mask)
+       while (readl(reg) & mask)
                ;
-       spin_unlock_irqrestore(&l2x0_lock, flags);
 }
 
 static inline void cache_sync(void)
 {
-       sync_writel(0, L2X0_CACHE_SYNC, 1);
+       void __iomem *base = l2x0_base;
+       writel(0, base + L2X0_CACHE_SYNC);
+       cache_wait(base + L2X0_CACHE_SYNC, 1);
 }
 
 static inline void l2x0_inv_all(void)
 {
+       unsigned long flags;
+
        /* invalidate all ways */
-       sync_writel(0xff, L2X0_INV_WAY, 0xff);
+       spin_lock_irqsave(&l2x0_lock, flags);
+       writel(0xff, l2x0_base + L2X0_INV_WAY);
+       cache_wait(l2x0_base + L2X0_INV_WAY, 0xff);
        cache_sync();
+       spin_unlock_irqrestore(&l2x0_lock, flags);
 }
 
 static void l2x0_inv_range(unsigned long start, unsigned long end)
 {
-       unsigned long addr;
+       void __iomem *base = l2x0_base;
+       unsigned long flags;
 
+       spin_lock_irqsave(&l2x0_lock, flags);
        if (start & (CACHE_LINE_SIZE - 1)) {
                start &= ~(CACHE_LINE_SIZE - 1);
-               sync_writel(start, L2X0_CLEAN_INV_LINE_PA, 1);
+               cache_wait(base + L2X0_CLEAN_INV_LINE_PA, 1);
+               writel(start, base + L2X0_CLEAN_INV_LINE_PA);
                start += CACHE_LINE_SIZE;
        }
 
        if (end & (CACHE_LINE_SIZE - 1)) {
                end &= ~(CACHE_LINE_SIZE - 1);
-               sync_writel(end, L2X0_CLEAN_INV_LINE_PA, 1);
+               cache_wait(base + L2X0_CLEAN_INV_LINE_PA, 1);
+               writel(end, base + L2X0_CLEAN_INV_LINE_PA);
        }
 
-       for (addr = start; addr < end; addr += CACHE_LINE_SIZE)
-               sync_writel(addr, L2X0_INV_LINE_PA, 1);
+       while (start < end) {
+               unsigned long blk_end = start + min(end - start, 4096UL);
+
+               while (start < blk_end) {
+                       cache_wait(base + L2X0_INV_LINE_PA, 1);
+                       writel(start, base + L2X0_INV_LINE_PA);
+                       start += CACHE_LINE_SIZE;
+               }
+
+               if (blk_end < end) {
+                       spin_unlock_irqrestore(&l2x0_lock, flags);
+                       spin_lock_irqsave(&l2x0_lock, flags);
+               }
+       }
+       cache_wait(base + L2X0_INV_LINE_PA, 1);
        cache_sync();
+       spin_unlock_irqrestore(&l2x0_lock, flags);
 }
 
 static void l2x0_clean_range(unsigned long start, unsigned long end)
 {
-       unsigned long addr;
+       void __iomem *base = l2x0_base;
+       unsigned long flags;
 
+       spin_lock_irqsave(&l2x0_lock, flags);
        start &= ~(CACHE_LINE_SIZE - 1);
-       for (addr = start; addr < end; addr += CACHE_LINE_SIZE)
-               sync_writel(addr, L2X0_CLEAN_LINE_PA, 1);
+       while (start < end) {
+               unsigned long blk_end = start + min(end - start, 4096UL);
+
+               while (start < blk_end) {
+                       cache_wait(base + L2X0_CLEAN_LINE_PA, 1);
+                       writel(start, base + L2X0_CLEAN_LINE_PA);
+                       start += CACHE_LINE_SIZE;
+               }
+
+               if (blk_end < end) {
+                       spin_unlock_irqrestore(&l2x0_lock, flags);
+                       spin_lock_irqsave(&l2x0_lock, flags);
+               }
+       }
+       cache_wait(base + L2X0_CLEAN_LINE_PA, 1);
        cache_sync();
+       spin_unlock_irqrestore(&l2x0_lock, flags);
 }
 
 static void l2x0_flush_range(unsigned long start, unsigned long end)
 {
-       unsigned long addr;
+       void __iomem *base = l2x0_base;
+       unsigned long flags;
 
+       spin_lock_irqsave(&l2x0_lock, flags);
        start &= ~(CACHE_LINE_SIZE - 1);
-       for (addr = start; addr < end; addr += CACHE_LINE_SIZE)
-               sync_writel(addr, L2X0_CLEAN_INV_LINE_PA, 1);
+       while (start < end) {
+               unsigned long blk_end = start + min(end - start, 4096UL);
+
+               while (start < blk_end) {
+                       cache_wait(base + L2X0_CLEAN_INV_LINE_PA, 1);
+                       writel(start, base + L2X0_CLEAN_INV_LINE_PA);
+                       start += CACHE_LINE_SIZE;
+               }
+
+               if (blk_end < end) {
+                       spin_unlock_irqrestore(&l2x0_lock, flags);
+                       spin_lock_irqsave(&l2x0_lock, flags);
+               }
+       }
+       cache_wait(base + L2X0_CLEAN_INV_LINE_PA, 1);
        cache_sync();
+       spin_unlock_irqrestore(&l2x0_lock, flags);
 }
 
 void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
index 8a4abebc478a29617a55efeabd871480ca4ab9c2..2a482731ea36914f2f6ca2b6bb4299e7dee84742 100644 (file)
@@ -72,14 +72,15 @@ ENTRY(v3_coherent_user_range)
        mov     pc, lr
 
 /*
- *     flush_kern_dcache_page(void *page)
+ *     flush_kern_dcache_area(void *page, size_t size)
  *
  *     Ensure no D cache aliasing occurs, either with itself or
  *     the I cache
  *
- *     - addr  - page aligned address
+ *     - addr  - kernel address
+ *     - size  - region size
  */
-ENTRY(v3_flush_kern_dcache_page)
+ENTRY(v3_flush_kern_dcache_area)
        /* FALLTHROUGH */
 
 /*
@@ -129,7 +130,7 @@ ENTRY(v3_cache_fns)
        .long   v3_flush_user_cache_range
        .long   v3_coherent_kern_range
        .long   v3_coherent_user_range
-       .long   v3_flush_kern_dcache_page
+       .long   v3_flush_kern_dcache_area
        .long   v3_dma_inv_range
        .long   v3_dma_clean_range
        .long   v3_dma_flush_range
index 3668611cb400325d9368e2707f41a25d0da93c50..5c7da3e372e94faa6f85a07b2c154730140f44b6 100644 (file)
@@ -82,14 +82,15 @@ ENTRY(v4_coherent_user_range)
        mov     pc, lr
 
 /*
- *     flush_kern_dcache_page(void *page)
+ *     flush_kern_dcache_area(void *addr, size_t size)
  *
  *     Ensure no D cache aliasing occurs, either with itself or
  *     the I cache
  *
- *     - addr  - page aligned address
+ *     - addr  - kernel address
+ *     - size  - region size
  */
-ENTRY(v4_flush_kern_dcache_page)
+ENTRY(v4_flush_kern_dcache_area)
        /* FALLTHROUGH */
 
 /*
@@ -141,7 +142,7 @@ ENTRY(v4_cache_fns)
        .long   v4_flush_user_cache_range
        .long   v4_coherent_kern_range
        .long   v4_coherent_user_range
-       .long   v4_flush_kern_dcache_page
+       .long   v4_flush_kern_dcache_area
        .long   v4_dma_inv_range
        .long   v4_dma_clean_range
        .long   v4_dma_flush_range
index 2ebc1b3bf856ff454f5a0c114ef0dea9e9fbcaed..3dbedf1ec0e7790612385b34def041378af5f0d9 100644 (file)
@@ -114,15 +114,16 @@ ENTRY(v4wb_flush_user_cache_range)
        mov     pc, lr
 
 /*
- *     flush_kern_dcache_page(void *page)
+ *     flush_kern_dcache_area(void *addr, size_t size)
  *
  *     Ensure no D cache aliasing occurs, either with itself or
  *     the I cache
  *
- *     - addr  - page aligned address
+ *     - addr  - kernel address
+ *     - size  - region size
  */
-ENTRY(v4wb_flush_kern_dcache_page)
-       add     r1, r0, #PAGE_SZ
+ENTRY(v4wb_flush_kern_dcache_area)
+       add     r1, r0, r1
        /* fall through */
 
 /*
@@ -224,7 +225,7 @@ ENTRY(v4wb_cache_fns)
        .long   v4wb_flush_user_cache_range
        .long   v4wb_coherent_kern_range
        .long   v4wb_coherent_user_range
-       .long   v4wb_flush_kern_dcache_page
+       .long   v4wb_flush_kern_dcache_area
        .long   v4wb_dma_inv_range
        .long   v4wb_dma_clean_range
        .long   v4wb_dma_flush_range
index c54fa2cc40e6e2f8ebfa2c60c7849ea94682bd70..b3b7410270b48e6bf3414de930e2eff0010cf6b3 100644 (file)
@@ -117,17 +117,18 @@ ENTRY(v4wt_coherent_user_range)
        mov     pc, lr
 
 /*
- *     flush_kern_dcache_page(void *page)
+ *     flush_kern_dcache_area(void *addr, size_t size)
  *
  *     Ensure no D cache aliasing occurs, either with itself or
  *     the I cache
  *
- *     - addr  - page aligned address
+ *     - addr  - kernel address
+ *     - size  - region size
  */
-ENTRY(v4wt_flush_kern_dcache_page)
+ENTRY(v4wt_flush_kern_dcache_area)
        mov     r2, #0
        mcr     p15, 0, r2, c7, c5, 0           @ invalidate I cache
-       add     r1, r0, #PAGE_SZ
+       add     r1, r0, r1
        /* fallthrough */
 
 /*
@@ -180,7 +181,7 @@ ENTRY(v4wt_cache_fns)
        .long   v4wt_flush_user_cache_range
        .long   v4wt_coherent_kern_range
        .long   v4wt_coherent_user_range
-       .long   v4wt_flush_kern_dcache_page
+       .long   v4wt_flush_kern_dcache_area
        .long   v4wt_dma_inv_range
        .long   v4wt_dma_clean_range
        .long   v4wt_dma_flush_range
index 295e25dd6381f69da0eaf59c8e9da1854434ddd8..4ba0a24ce6f58341bcf0a78aef56531709e7b774 100644 (file)
@@ -159,15 +159,16 @@ ENDPROC(v6_coherent_user_range)
 ENDPROC(v6_coherent_kern_range)
 
 /*
- *     v6_flush_kern_dcache_page(kaddr)
+ *     v6_flush_kern_dcache_area(void *addr, size_t size)
  *
  *     Ensure that the data held in the page kaddr is written back
  *     to the page in question.
  *
- *     - kaddr   - kernel address (guaranteed to be page aligned)
+ *     - addr  - kernel address
+ *     - size  - region size
  */
-ENTRY(v6_flush_kern_dcache_page)
-       add     r1, r0, #PAGE_SZ
+ENTRY(v6_flush_kern_dcache_area)
+       add     r1, r0, r1
 1:
 #ifdef HARVARD_CACHE
        mcr     p15, 0, r0, c7, c14, 1          @ clean & invalidate D line
@@ -271,7 +272,7 @@ ENTRY(v6_cache_fns)
        .long   v6_flush_user_cache_range
        .long   v6_coherent_kern_range
        .long   v6_coherent_user_range
-       .long   v6_flush_kern_dcache_page
+       .long   v6_flush_kern_dcache_area
        .long   v6_dma_inv_range
        .long   v6_dma_clean_range
        .long   v6_dma_flush_range
index e1bd9759617f16cce4d8b59c738e340afa22b2e2..9073db849fb46a75f08c18c1ae9790614696e377 100644 (file)
@@ -186,16 +186,17 @@ ENDPROC(v7_coherent_kern_range)
 ENDPROC(v7_coherent_user_range)
 
 /*
- *     v7_flush_kern_dcache_page(kaddr)
+ *     v7_flush_kern_dcache_area(void *addr, size_t size)
  *
  *     Ensure that the data held in the page kaddr is written back
  *     to the page in question.
  *
- *     - kaddr   - kernel address (guaranteed to be page aligned)
+ *     - addr  - kernel address
+ *     - size  - region size
  */
-ENTRY(v7_flush_kern_dcache_page)
+ENTRY(v7_flush_kern_dcache_area)
        dcache_line_size r2, r3
-       add     r1, r0, #PAGE_SZ
+       add     r1, r0, r1
 1:
        mcr     p15, 0, r0, c7, c14, 1          @ clean & invalidate D line / unified line
        add     r0, r0, r2
@@ -203,7 +204,7 @@ ENTRY(v7_flush_kern_dcache_page)
        blo     1b
        dsb
        mov     pc, lr
-ENDPROC(v7_flush_kern_dcache_page)
+ENDPROC(v7_flush_kern_dcache_area)
 
 /*
  *     v7_dma_inv_range(start,end)
@@ -279,7 +280,7 @@ ENTRY(v7_cache_fns)
        .long   v7_flush_user_cache_range
        .long   v7_coherent_kern_range
        .long   v7_coherent_user_range
-       .long   v7_flush_kern_dcache_page
+       .long   v7_flush_kern_dcache_area
        .long   v7_dma_inv_range
        .long   v7_dma_clean_range
        .long   v7_dma_flush_range
index 329594e760cdb09e868b1e1ad42a30dfda78f429..6f3a4b7a3b8276e5c442e4bbfc8273c8e9745f54 100644 (file)
@@ -131,7 +131,7 @@ void __flush_dcache_page(struct address_space *mapping, struct page *page)
         */
        if (addr)
 #endif
-               __cpuc_flush_dcache_page(addr);
+               __cpuc_flush_dcache_area(addr, PAGE_SIZE);
 
        /*
         * If this is a page cache page, and we have an aliasing VIPT cache,
@@ -258,5 +258,5 @@ void __flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned l
         * in this mapping of the page.  FIXME: this is overkill
         * since we actually ask for a write-back and invalidate.
         */
-       __cpuc_flush_dcache_page(page_address(page));
+       __cpuc_flush_dcache_area(page_address(page), PAGE_SIZE);
 }
index 30f82fb5918c9e2a8b3cce49849ff4fd7d97c2dc..2be1ec7c1b41acea66987a3ef532e96020b71c5b 100644 (file)
@@ -79,7 +79,7 @@ void kunmap_atomic(void *kvaddr, enum km_type type)
        unsigned int idx = type + KM_TYPE_NR * smp_processor_id();
 
        if (kvaddr >= (void *)FIXADDR_START) {
-               __cpuc_flush_dcache_page((void *)vaddr);
+               __cpuc_flush_dcache_area((void *)vaddr, PAGE_SIZE);
 #ifdef CONFIG_DEBUG_HIGHMEM
                BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
                set_pte_ext(TOP_PTE(vaddr), __pte(0), 0);
index 900811cc9130669b0377f7a155b95cd57c64ca34..374a8311bc84b0eeadaa37a14004ee53f499ab67 100644 (file)
@@ -61,7 +61,7 @@ void setup_mm_for_reboot(char mode)
 
 void flush_dcache_page(struct page *page)
 {
-       __cpuc_flush_dcache_page(page_address(page));
+       __cpuc_flush_dcache_area(page_address(page), PAGE_SIZE);
 }
 EXPORT_SYMBOL(flush_dcache_page);
 
index d9fb4b98c49ff8866a1d36288d431ce364ad1180..8012e24282b2d0ffbbab5a38cd963c6cb9acf6e5 100644 (file)
@@ -231,17 +231,18 @@ ENTRY(arm1020_coherent_user_range)
        mov     pc, lr
 
 /*
- *     flush_kern_dcache_page(void *page)
+ *     flush_kern_dcache_area(void *addr, size_t size)
  *
  *     Ensure no D cache aliasing occurs, either with itself or
  *     the I cache
  *
- *     - page  - page aligned address
+ *     - addr  - kernel address
+ *     - size  - region size
  */
-ENTRY(arm1020_flush_kern_dcache_page)
+ENTRY(arm1020_flush_kern_dcache_area)
        mov     ip, #0
 #ifndef CONFIG_CPU_DCACHE_DISABLE
-       add     r1, r0, #PAGE_SZ
+       add     r1, r0, r1
 1:     mcr     p15, 0, r0, c7, c14, 1          @ clean+invalidate D entry
        mcr     p15, 0, ip, c7, c10, 4          @ drain WB
        add     r0, r0, #CACHE_DLINESIZE
@@ -335,7 +336,7 @@ ENTRY(arm1020_cache_fns)
        .long   arm1020_flush_user_cache_range
        .long   arm1020_coherent_kern_range
        .long   arm1020_coherent_user_range
-       .long   arm1020_flush_kern_dcache_page
+       .long   arm1020_flush_kern_dcache_area
        .long   arm1020_dma_inv_range
        .long   arm1020_dma_clean_range
        .long   arm1020_dma_flush_range
index 7453b75dcea5f1527790e940263f113a70aec417..41fe25d234f50b76b563c6b5516a258d45c014fe 100644 (file)
@@ -225,17 +225,18 @@ ENTRY(arm1020e_coherent_user_range)
        mov     pc, lr
 
 /*
- *     flush_kern_dcache_page(void *page)
+ *     flush_kern_dcache_area(void *addr, size_t size)
  *
  *     Ensure no D cache aliasing occurs, either with itself or
  *     the I cache
  *
- *     - page  - page aligned address
+ *     - addr  - kernel address
+ *     - size  - region size
  */
-ENTRY(arm1020e_flush_kern_dcache_page)
+ENTRY(arm1020e_flush_kern_dcache_area)
        mov     ip, #0
 #ifndef CONFIG_CPU_DCACHE_DISABLE
-       add     r1, r0, #PAGE_SZ
+       add     r1, r0, r1
 1:     mcr     p15, 0, r0, c7, c14, 1          @ clean+invalidate D entry
        add     r0, r0, #CACHE_DLINESIZE
        cmp     r0, r1
@@ -321,7 +322,7 @@ ENTRY(arm1020e_cache_fns)
        .long   arm1020e_flush_user_cache_range
        .long   arm1020e_coherent_kern_range
        .long   arm1020e_coherent_user_range
-       .long   arm1020e_flush_kern_dcache_page
+       .long   arm1020e_flush_kern_dcache_area
        .long   arm1020e_dma_inv_range
        .long   arm1020e_dma_clean_range
        .long   arm1020e_dma_flush_range
index 8eb72d75a8b6fe2757e0c6c8bcfa7325519c2a11..20a5b1b31a706051ac2c1b6cb58b293b3b2794a2 100644 (file)
@@ -214,17 +214,18 @@ ENTRY(arm1022_coherent_user_range)
        mov     pc, lr
 
 /*
- *     flush_kern_dcache_page(void *page)
+ *     flush_kern_dcache_area(void *addr, size_t size)
  *
  *     Ensure no D cache aliasing occurs, either with itself or
  *     the I cache
  *
- *     - page  - page aligned address
+ *     - addr  - kernel address
+ *     - size  - region size
  */
-ENTRY(arm1022_flush_kern_dcache_page)
+ENTRY(arm1022_flush_kern_dcache_area)
        mov     ip, #0
 #ifndef CONFIG_CPU_DCACHE_DISABLE
-       add     r1, r0, #PAGE_SZ
+       add     r1, r0, r1
 1:     mcr     p15, 0, r0, c7, c14, 1          @ clean+invalidate D entry
        add     r0, r0, #CACHE_DLINESIZE
        cmp     r0, r1
@@ -310,7 +311,7 @@ ENTRY(arm1022_cache_fns)
        .long   arm1022_flush_user_cache_range
        .long   arm1022_coherent_kern_range
        .long   arm1022_coherent_user_range
-       .long   arm1022_flush_kern_dcache_page
+       .long   arm1022_flush_kern_dcache_area
        .long   arm1022_dma_inv_range
        .long   arm1022_dma_clean_range
        .long   arm1022_dma_flush_range
index 3b59f0d6713962d3e83222d1d05dc2c10606157c..96aedb10fcc418c528f536fb9a06f77185a3fa9c 100644 (file)
@@ -208,17 +208,18 @@ ENTRY(arm1026_coherent_user_range)
        mov     pc, lr
 
 /*
- *     flush_kern_dcache_page(void *page)
+ *     flush_kern_dcache_area(void *addr, size_t size)
  *
  *     Ensure no D cache aliasing occurs, either with itself or
  *     the I cache
  *
- *     - page  - page aligned address
+ *     - addr  - kernel address
+ *     - size  - region size
  */
-ENTRY(arm1026_flush_kern_dcache_page)
+ENTRY(arm1026_flush_kern_dcache_area)
        mov     ip, #0
 #ifndef CONFIG_CPU_DCACHE_DISABLE
-       add     r1, r0, #PAGE_SZ
+       add     r1, r0, r1
 1:     mcr     p15, 0, r0, c7, c14, 1          @ clean+invalidate D entry
        add     r0, r0, #CACHE_DLINESIZE
        cmp     r0, r1
@@ -304,7 +305,7 @@ ENTRY(arm1026_cache_fns)
        .long   arm1026_flush_user_cache_range
        .long   arm1026_coherent_kern_range
        .long   arm1026_coherent_user_range
-       .long   arm1026_flush_kern_dcache_page
+       .long   arm1026_flush_kern_dcache_area
        .long   arm1026_dma_inv_range
        .long   arm1026_dma_clean_range
        .long   arm1026_dma_flush_range
index 2b7c197cc58d2ab4babcf39920220b96a973570e..471669e2d7cb458567d9233a805dd8ce772bf719 100644 (file)
@@ -207,15 +207,16 @@ ENTRY(arm920_coherent_user_range)
        mov     pc, lr
 
 /*
- *     flush_kern_dcache_page(void *page)
+ *     flush_kern_dcache_area(void *addr, size_t size)
  *
  *     Ensure no D cache aliasing occurs, either with itself or
  *     the I cache
  *
- *     - addr  - page aligned address
+ *     - addr  - kernel address
+ *     - size  - region size
  */
-ENTRY(arm920_flush_kern_dcache_page)
-       add     r1, r0, #PAGE_SZ
+ENTRY(arm920_flush_kern_dcache_area)
+       add     r1, r0, r1
 1:     mcr     p15, 0, r0, c7, c14, 1          @ clean+invalidate D entry
        add     r0, r0, #CACHE_DLINESIZE
        cmp     r0, r1
@@ -293,7 +294,7 @@ ENTRY(arm920_cache_fns)
        .long   arm920_flush_user_cache_range
        .long   arm920_coherent_kern_range
        .long   arm920_coherent_user_range
-       .long   arm920_flush_kern_dcache_page
+       .long   arm920_flush_kern_dcache_area
        .long   arm920_dma_inv_range
        .long   arm920_dma_clean_range
        .long   arm920_dma_flush_range
index 06a1aa4e33989976465155586fe0390e19109bb9..ee111b00fa41951619593c758fe22eb06a4e4ee4 100644 (file)
@@ -209,15 +209,16 @@ ENTRY(arm922_coherent_user_range)
        mov     pc, lr
 
 /*
- *     flush_kern_dcache_page(void *page)
+ *     flush_kern_dcache_area(void *addr, size_t size)
  *
  *     Ensure no D cache aliasing occurs, either with itself or
  *     the I cache
  *
- *     - addr  - page aligned address
+ *     - addr  - kernel address
+ *     - size  - region size
  */
-ENTRY(arm922_flush_kern_dcache_page)
-       add     r1, r0, #PAGE_SZ
+ENTRY(arm922_flush_kern_dcache_area)
+       add     r1, r0, r1
 1:     mcr     p15, 0, r0, c7, c14, 1          @ clean+invalidate D entry
        add     r0, r0, #CACHE_DLINESIZE
        cmp     r0, r1
@@ -295,7 +296,7 @@ ENTRY(arm922_cache_fns)
        .long   arm922_flush_user_cache_range
        .long   arm922_coherent_kern_range
        .long   arm922_coherent_user_range
-       .long   arm922_flush_kern_dcache_page
+       .long   arm922_flush_kern_dcache_area
        .long   arm922_dma_inv_range
        .long   arm922_dma_clean_range
        .long   arm922_dma_flush_range
index cb53435a85aee2120f2e97f6b01c24561f32e860..8deb5bde58e4883765e1d7bb6b81b10e0388911b 100644 (file)
@@ -251,15 +251,16 @@ ENTRY(arm925_coherent_user_range)
        mov     pc, lr
 
 /*
- *     flush_kern_dcache_page(void *page)
+ *     flush_kern_dcache_area(void *addr, size_t size)
  *
  *     Ensure no D cache aliasing occurs, either with itself or
  *     the I cache
  *
- *     - addr  - page aligned address
+ *     - addr  - kernel address
+ *     - size  - region size
  */
-ENTRY(arm925_flush_kern_dcache_page)
-       add     r1, r0, #PAGE_SZ
+ENTRY(arm925_flush_kern_dcache_area)
+       add     r1, r0, r1
 1:     mcr     p15, 0, r0, c7, c14, 1          @ clean+invalidate D entry
        add     r0, r0, #CACHE_DLINESIZE
        cmp     r0, r1
@@ -346,7 +347,7 @@ ENTRY(arm925_cache_fns)
        .long   arm925_flush_user_cache_range
        .long   arm925_coherent_kern_range
        .long   arm925_coherent_user_range
-       .long   arm925_flush_kern_dcache_page
+       .long   arm925_flush_kern_dcache_area
        .long   arm925_dma_inv_range
        .long   arm925_dma_clean_range
        .long   arm925_dma_flush_range
index 1c4848704bb358c98a0e4c87141f7326e802d3fb..64db6e275a442f610239fe9b692753c4d88d14f9 100644 (file)
@@ -214,15 +214,16 @@ ENTRY(arm926_coherent_user_range)
        mov     pc, lr
 
 /*
- *     flush_kern_dcache_page(void *page)
+ *     flush_kern_dcache_area(void *addr, size_t size)
  *
  *     Ensure no D cache aliasing occurs, either with itself or
  *     the I cache
  *
- *     - addr  - page aligned address
+ *     - addr  - kernel address
+ *     - size  - region size
  */
-ENTRY(arm926_flush_kern_dcache_page)
-       add     r1, r0, #PAGE_SZ
+ENTRY(arm926_flush_kern_dcache_area)
+       add     r1, r0, r1
 1:     mcr     p15, 0, r0, c7, c14, 1          @ clean+invalidate D entry
        add     r0, r0, #CACHE_DLINESIZE
        cmp     r0, r1
@@ -309,7 +310,7 @@ ENTRY(arm926_cache_fns)
        .long   arm926_flush_user_cache_range
        .long   arm926_coherent_kern_range
        .long   arm926_coherent_user_range
-       .long   arm926_flush_kern_dcache_page
+       .long   arm926_flush_kern_dcache_area
        .long   arm926_dma_inv_range
        .long   arm926_dma_clean_range
        .long   arm926_dma_flush_range
index 5b0f8464c8f29f9cc908cd2bbff5a820652f7751..8196b9f401fb53f17cd0a215c384a872330e054d 100644 (file)
@@ -141,14 +141,15 @@ ENTRY(arm940_coherent_user_range)
        /* FALLTHROUGH */
 
 /*
- *     flush_kern_dcache_page(void *page)
+ *     flush_kern_dcache_area(void *addr, size_t size)
  *
  *     Ensure no D cache aliasing occurs, either with itself or
  *     the I cache
  *
- *     - addr  - page aligned address
+ *     - addr  - kernel address
+ *     - size  - region size
  */
-ENTRY(arm940_flush_kern_dcache_page)
+ENTRY(arm940_flush_kern_dcache_area)
        mov     ip, #0
        mov     r1, #(CACHE_DSEGMENTS - 1) << 4 @ 4 segments
 1:     orr     r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries
@@ -238,7 +239,7 @@ ENTRY(arm940_cache_fns)
        .long   arm940_flush_user_cache_range
        .long   arm940_coherent_kern_range
        .long   arm940_coherent_user_range
-       .long   arm940_flush_kern_dcache_page
+       .long   arm940_flush_kern_dcache_area
        .long   arm940_dma_inv_range
        .long   arm940_dma_clean_range
        .long   arm940_dma_flush_range
index 40c0449a139b829a709525984442b36561494e13..9a951239c86c0a1b93dcefdf6687312b6c3c51c7 100644 (file)
@@ -183,16 +183,17 @@ ENTRY(arm946_coherent_user_range)
        mov     pc, lr
 
 /*
- *     flush_kern_dcache_page(void *page)
+ *     flush_kern_dcache_area(void *addr, size_t size)
  *
  *     Ensure no D cache aliasing occurs, either with itself or
  *     the I cache
  *
- *     - addr  - page aligned address
+ *     - addr  - kernel address
+ *     - size  - region size
  * (same as arm926)
  */
-ENTRY(arm946_flush_kern_dcache_page)
-       add     r1, r0, #PAGE_SZ
+ENTRY(arm946_flush_kern_dcache_area)
+       add     r1, r0, r1
 1:     mcr     p15, 0, r0, c7, c14, 1          @ clean+invalidate D entry
        add     r0, r0, #CACHE_DLINESIZE
        cmp     r0, r1
@@ -280,7 +281,7 @@ ENTRY(arm946_cache_fns)
        .long   arm946_flush_user_cache_range
        .long   arm946_coherent_kern_range
        .long   arm946_coherent_user_range
-       .long   arm946_flush_kern_dcache_page
+       .long   arm946_flush_kern_dcache_area
        .long   arm946_dma_inv_range
        .long   arm946_dma_clean_range
        .long   arm946_dma_flush_range
index d0d7795200fc143a0362312c960f334deb5f1957..dbc39383e66aaf0d2ec0e5865f15e21dafb02ec7 100644 (file)
@@ -226,16 +226,17 @@ ENTRY(feroceon_coherent_user_range)
        mov     pc, lr
 
 /*
- *     flush_kern_dcache_page(void *page)
+ *     flush_kern_dcache_area(void *addr, size_t size)
  *
  *     Ensure no D cache aliasing occurs, either with itself or
  *     the I cache
  *
- *     - addr  - page aligned address
+ *     - addr  - kernel address
+ *     - size  - region size
  */
        .align  5
-ENTRY(feroceon_flush_kern_dcache_page)
-       add     r1, r0, #PAGE_SZ
+ENTRY(feroceon_flush_kern_dcache_area)
+       add     r1, r0, r1
 1:     mcr     p15, 0, r0, c7, c14, 1          @ clean+invalidate D entry
        add     r0, r0, #CACHE_DLINESIZE
        cmp     r0, r1
@@ -246,7 +247,7 @@ ENTRY(feroceon_flush_kern_dcache_page)
        mov     pc, lr
 
        .align  5
-ENTRY(feroceon_range_flush_kern_dcache_page)
+ENTRY(feroceon_range_flush_kern_dcache_area)
        mrs     r2, cpsr
        add     r1, r0, #PAGE_SZ - CACHE_DLINESIZE      @ top addr is inclusive
        orr     r3, r2, #PSR_I_BIT
@@ -372,7 +373,7 @@ ENTRY(feroceon_cache_fns)
        .long   feroceon_flush_user_cache_range
        .long   feroceon_coherent_kern_range
        .long   feroceon_coherent_user_range
-       .long   feroceon_flush_kern_dcache_page
+       .long   feroceon_flush_kern_dcache_area
        .long   feroceon_dma_inv_range
        .long   feroceon_dma_clean_range
        .long   feroceon_dma_flush_range
@@ -383,7 +384,7 @@ ENTRY(feroceon_range_cache_fns)
        .long   feroceon_flush_user_cache_range
        .long   feroceon_coherent_kern_range
        .long   feroceon_coherent_user_range
-       .long   feroceon_range_flush_kern_dcache_page
+       .long   feroceon_range_flush_kern_dcache_area
        .long   feroceon_range_dma_inv_range
        .long   feroceon_range_dma_clean_range
        .long   feroceon_range_dma_flush_range
index 52b5fd74fbb3fcbfe3295d570a2e121001318562..9674d36cc97d4c1a6489599d2047b3c29ef58110 100644 (file)
@@ -186,15 +186,16 @@ ENTRY(mohawk_coherent_user_range)
        mov     pc, lr
 
 /*
- *     flush_kern_dcache_page(void *page)
+ *     flush_kern_dcache_area(void *addr, size_t size)
  *
  *     Ensure no D cache aliasing occurs, either with itself or
  *     the I cache
  *
- *     - addr  - page aligned address
+ *     - addr  - kernel address
+ *     - size  - region size
  */
-ENTRY(mohawk_flush_kern_dcache_page)
-       add     r1, r0, #PAGE_SZ
+ENTRY(mohawk_flush_kern_dcache_area)
+       add     r1, r0, r1
 1:     mcr     p15, 0, r0, c7, c14, 1          @ clean+invalidate D entry
        add     r0, r0, #CACHE_DLINESIZE
        cmp     r0, r1
@@ -273,7 +274,7 @@ ENTRY(mohawk_cache_fns)
        .long   mohawk_flush_user_cache_range
        .long   mohawk_coherent_kern_range
        .long   mohawk_coherent_user_range
-       .long   mohawk_flush_kern_dcache_page
+       .long   mohawk_flush_kern_dcache_area
        .long   mohawk_dma_inv_range
        .long   mohawk_dma_clean_range
        .long   mohawk_dma_flush_range
index ac5c80062b704b791d0d9af9be34e7484f8d4311..3e6210b4d6d4cc713ba524ab3966760ad1d6f6f8 100644 (file)
@@ -27,8 +27,7 @@ EXPORT_SYMBOL(__cpuc_flush_kern_all);
 EXPORT_SYMBOL(__cpuc_flush_user_all);
 EXPORT_SYMBOL(__cpuc_flush_user_range);
 EXPORT_SYMBOL(__cpuc_coherent_kern_range);
-EXPORT_SYMBOL(__cpuc_flush_dcache_page);
-EXPORT_SYMBOL(dmac_inv_range);  /* because of flush_ioremap_region() */
+EXPORT_SYMBOL(__cpuc_flush_dcache_area);
 #else
 EXPORT_SYMBOL(cpu_cache);
 #endif
index 5485c821101ca1a9d242f28eedef1b02e1be47ff..395cc90c6613d616f56c502102747464baa2b159 100644 (file)
@@ -254,10 +254,9 @@ __pj4_v6_proc_info:
        .long   0x560f5810
        .long   0xff0ffff0
        .long   PMD_TYPE_SECT | \
-               PMD_SECT_BUFFERABLE | \
-               PMD_SECT_CACHEABLE | \
                PMD_SECT_AP_WRITE | \
-               PMD_SECT_AP_READ
+               PMD_SECT_AP_READ | \
+               PMD_FLAGS
        .long   PMD_TYPE_SECT | \
                PMD_SECT_XN | \
                PMD_SECT_AP_WRITE | \
index fab134e29826d626c3ec7b5ca0da5ac37d203f40..96456f5487986f349513b154be2ed22de1bd9eab 100644 (file)
@@ -226,15 +226,16 @@ ENTRY(xsc3_coherent_user_range)
        mov     pc, lr
 
 /*
- *     flush_kern_dcache_page(void *page)
+ *     flush_kern_dcache_area(void *addr, size_t size)
  *
  *     Ensure no D cache aliasing occurs, either with itself or
  *     the I cache.
  *
- *     - addr  - page aligned address
+ *     - addr  - kernel address
+ *     - size  - region size
  */
-ENTRY(xsc3_flush_kern_dcache_page)
-       add     r1, r0, #PAGE_SZ
+ENTRY(xsc3_flush_kern_dcache_area)
+       add     r1, r0, r1
 1:     mcr     p15, 0, r0, c7, c14, 1          @ clean/invalidate L1 D line
        add     r0, r0, #CACHELINESIZE
        cmp     r0, r1
@@ -309,7 +310,7 @@ ENTRY(xsc3_cache_fns)
        .long   xsc3_flush_user_cache_range
        .long   xsc3_coherent_kern_range
        .long   xsc3_coherent_user_range
-       .long   xsc3_flush_kern_dcache_page
+       .long   xsc3_flush_kern_dcache_area
        .long   xsc3_dma_inv_range
        .long   xsc3_dma_clean_range
        .long   xsc3_dma_flush_range
index f056c283682db09b37b3b282a1cded25d9683367..93df47265f2dfda487fcb7c11425d14b0a9ea02f 100644 (file)
@@ -284,15 +284,16 @@ ENTRY(xscale_coherent_user_range)
        mov     pc, lr
 
 /*
- *     flush_kern_dcache_page(void *page)
+ *     flush_kern_dcache_area(void *addr, size_t size)
  *
  *     Ensure no D cache aliasing occurs, either with itself or
  *     the I cache
  *
- *     - addr  - page aligned address
+ *     - addr  - kernel address
+ *     - size  - region size
  */
-ENTRY(xscale_flush_kern_dcache_page)
-       add     r1, r0, #PAGE_SZ
+ENTRY(xscale_flush_kern_dcache_area)
+       add     r1, r0, r1
 1:     mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
        mcr     p15, 0, r0, c7, c6, 1           @ invalidate D entry
        add     r0, r0, #CACHELINESIZE
@@ -368,7 +369,7 @@ ENTRY(xscale_cache_fns)
        .long   xscale_flush_user_cache_range
        .long   xscale_coherent_kern_range
        .long   xscale_coherent_user_range
-       .long   xscale_flush_kern_dcache_page
+       .long   xscale_flush_kern_dcache_area
        .long   xscale_dma_inv_range
        .long   xscale_dma_clean_range
        .long   xscale_dma_flush_range
@@ -392,7 +393,7 @@ ENTRY(xscale_80200_A0_A1_cache_fns)
        .long   xscale_flush_user_cache_range
        .long   xscale_coherent_kern_range
        .long   xscale_coherent_user_range
-       .long   xscale_flush_kern_dcache_page
+       .long   xscale_flush_kern_dcache_area
        .long   xscale_dma_flush_range
        .long   xscale_dma_clean_range
        .long   xscale_dma_flush_range
index 1dbaa29ac4d7b3658f4f40e22ba35db1413c2db4..635cb1865e4d56af08b8579eb72dbaadfa77f211 100644 (file)
@@ -4,7 +4,7 @@
 # Copyright (C) 2001 Russell King
 #
 
-include/asm-arm/mach-types.h: $(src)/gen-mach-types $(src)/mach-types
+include/generated/mach-types.h: $(src)/gen-mach-types $(src)/mach-types
        @echo '  Generating $@'
        @mkdir -p $(dir $@)
        $(Q)$(AWK) -f $^ > $@ || { rm -f $@; /bin/false; }
index ce319ef64bc108c6df94ac2b7b2c02e888050d35..04fef71d7be964f9cdaea5f30c80929e89befe78 100644 (file)
@@ -1,6 +1,6 @@
 #!/bin/awk
 #
-# Awk script to generate include/asm-arm/mach-types.h
+# Awk script to generate include/generated/mach-types.h
 #
 BEGIN  { nr = 0 }
 /^#/   { next }
index 07b976da617418d32b6c0a7d2d84a4ffeb7a5ace..c3a74ce24ef6c16f101bb5898a0c23056e0ee9e8 100644 (file)
@@ -12,7 +12,7 @@
 #
 #   http://www.arm.linux.org.uk/developer/machines/?action=new
 #
-# Last update: Wed Nov 25 22:14:58 2009
+# Last update: Wed Dec 16 20:06:34 2009
 #
 # machine_is_xxx       CONFIG_xxxx             MACH_TYPE_xxx           number
 #
@@ -1776,6 +1776,7 @@ cybook3                   MACH_CYBOOK3            CYBOOK3                 1784
 wdg002                 MACH_WDG002             WDG002                  1785
 sg560adsl              MACH_SG560ADSL          SG560ADSL               1786
 nextio_n2800_ica       MACH_NEXTIO_N2800_ICA   NEXTIO_N2800_ICA        1787
+dove_db                        MACH_DOVE_DB            DOVE_DB                 1788
 marvell_newdb          MACH_MARVELL_NEWDB      MARVELL_NEWDB           1789
 vandihud               MACH_VANDIHUD           VANDIHUD                1790
 magx_e8                        MACH_MAGX_E8            MAGX_E8                 1791
@@ -2536,3 +2537,44 @@ c3ax03                   MACH_C3AX03             C3AX03                  2549
 mxt_td60               MACH_MXT_TD60           MXT_TD60                2550
 esyx                   MACH_ESYX               ESYX                    2551
 bulldog                        MACH_BULLDOG            BULLDOG                 2553
+derell_me2000          MACH_DERELL_ME2000      DERELL_ME2000           2554
+bcmring_base           MACH_BCMRING_BASE       BCMRING_BASE            2555
+bcmring_evm            MACH_BCMRING_EVM        BCMRING_EVM             2556
+bcmring_evm_jazz       MACH_BCMRING_EVM_JAZZ   BCMRING_EVM_JAZZ        2557
+bcmring_sp             MACH_BCMRING_SP         BCMRING_SP              2558
+bcmring_sv             MACH_BCMRING_SV         BCMRING_SV              2559
+bcmring_sv_jazz                MACH_BCMRING_SV_JAZZ    BCMRING_SV_JAZZ         2560
+bcmring_tablet         MACH_BCMRING_TABLET     BCMRING_TABLET          2561
+bcmring_vp             MACH_BCMRING_VP         BCMRING_VP              2562
+bcmring_evm_seikor     MACH_BCMRING_EVM_SEIKOR BCMRING_EVM_SEIKOR      2563
+bcmring_sp_wqvga       MACH_BCMRING_SP_WQVGA   BCMRING_SP_WQVGA        2564
+bcmring_custom         MACH_BCMRING_CUSTOM     BCMRING_CUSTOM          2565
+acer_s200              MACH_ACER_S200          ACER_S200               2566
+bt270                  MACH_BT270              BT270                   2567
+iseo                   MACH_ISEO               ISEO                    2568
+cezanne                        MACH_CEZANNE            CEZANNE                 2569
+lucca                  MACH_LUCCA              LUCCA                   2570
+supersmart             MACH_SUPERSMART         SUPERSMART              2571
+magnolia2              MACH_MAGNOLIA2          MAGNOLIA2               2573
+emxx                   MACH_EMXX               EMXX                    2574
+outlaw                 MACH_OUTLAW             OUTLAW                  2575
+riot_bei2              MACH_RIOT_BEI2          RIOT_BEI2               2576
+riot_vox               MACH_RIOT_VOX           RIOT_VOX                2577
+riot_x37               MACH_RIOT_X37           RIOT_X37                2578
+mega25mx               MACH_MEGA25MX           MEGA25MX                2579
+benzina2               MACH_BENZINA2           BENZINA2                2580
+ignite                 MACH_IGNITE             IGNITE                  2581
+foggia                 MACH_FOGGIA             FOGGIA                  2582
+arezzo                 MACH_AREZZO             AREZZO                  2583
+leica_skywalker                MACH_LEICA_SKYWALKER    LEICA_SKYWALKER         2584
+jacinto2_jamr          MACH_JACINTO2_JAMR      JACINTO2_JAMR           2585
+gts_nova               MACH_GTS_NOVA           GTS_NOVA                2586
+p3600                  MACH_P3600              P3600                   2587
+dlt2                   MACH_DLT2               DLT2                    2588
+df3120                 MACH_DF3120             DF3120                  2589
+ecucore_9g20           MACH_ECUCORE_9G20       ECUCORE_9G20            2590
+nautel_lpc3240         MACH_NAUTEL_LPC3240     NAUTEL_LPC3240          2591
+glacier                        MACH_GLACIER            GLACIER                 2592
+phrazer_bulldog                MACH_PHRAZER_BULLDOG    PHRAZER_BULLDOG         2593
+omap3_bulldog          MACH_OMAP3_BULLDOG      OMAP3_BULLDOG           2594
+pca101                 MACH_PCA101             PCA101                  2595
diff --git a/arch/avr32/include/asm/asm-offsets.h b/arch/avr32/include/asm/asm-offsets.h
new file mode 100644 (file)
index 0000000..d370ee3
--- /dev/null
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
diff --git a/arch/blackfin/include/asm/asm-offsets.h b/arch/blackfin/include/asm/asm-offsets.h
new file mode 100644 (file)
index 0000000..d370ee3
--- /dev/null
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
index 3db478eb515505ca3be2ff1253871cb51a1dedcf..76266f80a5f127431955ac75e764948a9a2b829c 100644 (file)
@@ -10,7 +10,6 @@
  * The macros found in mmu_defs_asm.h uses the ## concatenation operator, so
  * -traditional must not be used when assembling this file.
  */
-#include <linux/autoconf.h>
 #include <arch/memmap.h>
 #include <hwregs/reg_rdwr.h>
 #include <hwregs/intr_vect.h>
diff --git a/arch/cris/include/asm/asm-offsets.h b/arch/cris/include/asm/asm-offsets.h
new file mode 100644 (file)
index 0000000..d370ee3
--- /dev/null
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
index ddd6fbbe75de61123abcae19978faaaae4ec7be6..dd7b8e983221e50104360d3ff11db0391625a77b 100644 (file)
@@ -1,6 +1,5 @@
 #include <linux/sched.h>
 #include <asm/thread_info.h>
-#include <linux/autoconf.h>
 
 /*
  * Generate definitions needed by assembly language modules.
index bbfda67d2907009c34af0d1b3f3ecd35ec03e47e..d49d17d2a14f5a36be1e4da6670897734565b4b8 100644 (file)
@@ -8,7 +8,6 @@
  * the kernel has booted.
  */
 
-#include <linux/autoconf.h>
 #include <asm-generic/vmlinux.lds.h>
 #include <asm/page.h>
 
diff --git a/arch/frv/include/asm/asm-offsets.h b/arch/frv/include/asm/asm-offsets.h
new file mode 100644 (file)
index 0000000..d370ee3
--- /dev/null
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
index 55e4fab7c0bc7f3929729e8a20a07a0b8be80bd5..75cf7f4b2fa81d8e0bd18cf6d0ff3ae4d64f8004 100644 (file)
@@ -10,7 +10,7 @@
  * 2 of the License, or (at your option) any later version.
  */
 
-#include <linux/utsrelease.h>
+#include <generated/utsrelease.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/delay.h>
diff --git a/arch/h8300/include/asm/asm-offsets.h b/arch/h8300/include/asm/asm-offsets.h
new file mode 100644 (file)
index 0000000..d370ee3
--- /dev/null
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
index e7cbaa02cd0b432fa99c43d0c8de742b2c11d485..475e2725fbde6feb6c9d64c024a52a2fd211af35 100644 (file)
@@ -103,4 +103,4 @@ archprepare: make_nr_irqs_h FORCE
 PHONY += make_nr_irqs_h FORCE
 
 make_nr_irqs_h: FORCE
-       $(Q)$(MAKE) $(build)=arch/ia64/kernel include/asm-ia64/nr-irqs.h
+       $(Q)$(MAKE) $(build)=arch/ia64/kernel include/generated/nr-irqs.h
diff --git a/arch/ia64/include/asm/asm-offsets.h b/arch/ia64/include/asm/asm-offsets.h
new file mode 100644 (file)
index 0000000..d370ee3
--- /dev/null
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
index 5282546cdf8201d460645ee70bad4e13f4066e21..91b920fd7d534099073c1ca44c69938cc445c9d4 100644 (file)
@@ -13,7 +13,7 @@
 
 #include <linux/types.h>
 #include <linux/cpumask.h>
-#include <asm-ia64/nr-irqs.h>
+#include <generated/nr-irqs.h>
 
 static __inline__ int
 irq_canonicalize (int irq)
index 6b7edcab0cb52ee24b8852b067f881b05ddf5d1e..2a75e937ae8daa8797e53f92cfc9a138a76e62a2 100644 (file)
@@ -81,17 +81,14 @@ define cmd_nr_irqs
 endef
 
 # We use internal kbuild rules to avoid the "is up to date" message from make
-arch/$(SRCARCH)/kernel/nr-irqs.s: $(srctree)/arch/$(SRCARCH)/kernel/nr-irqs.c \
-                               $(wildcard $(srctree)/include/asm-ia64/*/irq.h)
+arch/$(SRCARCH)/kernel/nr-irqs.s: arch/$(SRCARCH)/kernel/nr-irqs.c
        $(Q)mkdir -p $(dir $@)
        $(call if_changed_dep,cc_s_c)
 
-include/asm-ia64/nr-irqs.h: arch/$(SRCARCH)/kernel/nr-irqs.s
+include/generated/nr-irqs.h: arch/$(SRCARCH)/kernel/nr-irqs.s
        $(Q)mkdir -p $(dir $@)
        $(call cmd,nr_irqs)
 
-clean-files += $(objtree)/include/asm-ia64/nr-irqs.h
-
 #
 # native ivt.S, entry.S and fsys.S
 #
index 0c3564a7a033a25b2df4996c3b7f14169dcc8064..9324c875caf534e2e9908c618188d0a863cd5e9b 100644 (file)
@@ -22,7 +22,6 @@
  *
  */
 
-#include <linux/autoconf.h>
 #include <linux/kvm_host.h>
 #include <linux/kbuild.h>
 
diff --git a/arch/m68k/include/asm/asm-offsets.h b/arch/m68k/include/asm/asm-offsets.h
new file mode 100644 (file)
index 0000000..d370ee3
--- /dev/null
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
index 86edb5fbcfc354116093b4d3daf462ed53d11e6a..ef54128baa0b66cac9017df92ac9eb64f51d27de 100644 (file)
  * for them and trying to understand what they mean.
  *
  * CONFIG_xxx: These are the obvious machine configuration defines created
- * during configuration.  These are defined in include/linux/autoconf.h.
+ * during configuration.  These are defined in autoconf.h.
  *
  * CONSOLE:    There is support for head.S console in this file.  This
  * console can talk to a Mac frame buffer, but could easily be extrapolated
diff --git a/arch/microblaze/include/asm/asm-offsets.h b/arch/microblaze/include/asm/asm-offsets.h
new file mode 100644 (file)
index 0000000..d370ee3
--- /dev/null
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
diff --git a/arch/mips/include/asm/asm-offsets.h b/arch/mips/include/asm/asm-offsets.h
new file mode 100644 (file)
index 0000000..d370ee3
--- /dev/null
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
index 7c6681aa2ab877a02f3dff8577c96bd2d9b11509..e482fe90fe8850609ed05f79d4caa9423e31031a 100644 (file)
@@ -19,7 +19,7 @@
 #define FASYNC         0x1000  /* fcntl, for BSD compatibility */
 #define O_LARGEFILE    0x2000  /* allow large file opens */
 /*
- * Before Linux 2.6.32 only O_DSYNC semantics were implemented, but using
+ * Before Linux 2.6.33 only O_DSYNC semantics were implemented, but using
  * the O_SYNC flag.  We continue to use the existing numerical value
  * for O_DSYNC semantics now, but using the correct symbolic name for it.
  * This new value is used to request true Posix O_SYNC semantics.  It is
diff --git a/arch/mn10300/include/asm/asm-offsets.h b/arch/mn10300/include/asm/asm-offsets.h
new file mode 100644 (file)
index 0000000..d370ee3
--- /dev/null
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
diff --git a/arch/parisc/include/asm/asm-offsets.h b/arch/parisc/include/asm/asm-offsets.h
new file mode 100644 (file)
index 0000000..d370ee3
--- /dev/null
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
diff --git a/arch/powerpc/include/asm/asm-offsets.h b/arch/powerpc/include/asm/asm-offsets.h
new file mode 100644 (file)
index 0000000..d370ee3
--- /dev/null
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
index bcc69e1f77c10d800a40432522f121e80119314f..45c0cb9b67e6774958c621b6e3c8055d43e46163 100644 (file)
@@ -10,7 +10,7 @@
  */
 
 #include <linux/init.h>
-#include <linux/utsrelease.h>
+#include <generated/utsrelease.h>
 #include <linux/pci.h>
 #include <linux/of.h>
 #include <asm/prom.h>
index 9290a7a442d0af9d2736a81e4431ffd367df92b0..fb4eb0df054c0a701fe74df78990d40bd480e2df 100644 (file)
@@ -14,7 +14,7 @@
 
 #include <linux/kernel.h>
 #include <linux/seq_file.h>
-#include <linux/utsrelease.h>
+#include <generated/utsrelease.h>
 
 #include <asm/machdep.h>
 #include <asm/cputable.h>
index b93f877ba5046bded97844766dee257534194b1b..b9d5d678aa44ccf2481cef76586c8dbb1f3c0ab3 100644 (file)
@@ -13,10 +13,8 @@ SPU_CC               := $(SPU_CROSS)gcc
 SPU_AS         := $(SPU_CROSS)gcc
 SPU_LD         := $(SPU_CROSS)ld
 SPU_OBJCOPY    := $(SPU_CROSS)objcopy
-SPU_CFLAGS     := -O2 -Wall -I$(srctree)/include \
-                  -I$(objtree)/include2 -D__KERNEL__
-SPU_AFLAGS     := -c -D__ASSEMBLY__ -I$(srctree)/include \
-                  -I$(objtree)/include2 -D__KERNEL__
+SPU_CFLAGS     := -O2 -Wall -I$(srctree)/include -D__KERNEL__
+SPU_AFLAGS     := -c -D__ASSEMBLY__ -I$(srctree)/include -D__KERNEL__
 SPU_LDFLAGS    := -N -Ttext=0x0
 
 $(obj)/switch.o: $(obj)/spu_save_dump.h $(obj)/spu_restore_dump.h
index 52f3df3b4ca0a6a196e1712e6038a303661b7aed..8f41685d8f42b5669ee2a7e2492b5755e6919986 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/reboot.h>
 #include <linux/init.h>
 #include <linux/pci.h>
-#include <linux/utsrelease.h>
+#include <generated/utsrelease.h>
 #include <linux/adb.h>
 #include <linux/module.h>
 #include <linux/delay.h>
index cf660916ae0b0101ac36824fd3a2db8fd3e13997..9dd789a7370d8b210d2c7907d2c3a5e97238d735 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/init.h>
-#include <linux/utsrelease.h>
+#include <generated/utsrelease.h>
 #include <asm/sections.h>
 #include <asm/prom.h>
 #include <asm/page.h>
diff --git a/arch/s390/include/asm/asm-offsets.h b/arch/s390/include/asm/asm-offsets.h
new file mode 100644 (file)
index 0000000..d370ee3
--- /dev/null
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
diff --git a/arch/score/include/asm/asm-offsets.h b/arch/score/include/asm/asm-offsets.h
new file mode 100644 (file)
index 0000000..d370ee3
--- /dev/null
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
index caaba24036e345e4ca04a61a5444c9b30f2eb4f5..1d545d0ce206feefbc58e1693584dc9a5275ae3c 100644 (file)
@@ -14,10 +14,12 @@ extern void flush_cache_sigtramp(unsigned long addr);
 extern void flush_icache_all(void);
 extern void flush_icache_range(unsigned long start, unsigned long end);
 extern void flush_dcache_range(unsigned long start, unsigned long end);
+extern void flush_dcache_page(struct page *page);
+
+#define PG_dcache_dirty         PG_arch_1
 
 #define flush_cache_dup_mm(mm)                 do {} while (0)
 #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
-#define flush_dcache_page(page)                        do {} while (0)
 #define flush_dcache_mmap_lock(mapping)                do {} while (0)
 #define flush_dcache_mmap_unlock(mapping)      do {} while (0)
 #define flush_cache_vmap(start, end)           do {} while (0)
index 6726ec199dc02afbbe1f8ea379eba4e8309ab882..529e494712a5a46aee7b3431771df8416c62107d 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _ASM_SCORE_DELAY_H
 #define _ASM_SCORE_DELAY_H
 
+#include <asm-generic/param.h>
+
 static inline void __delay(unsigned long loops)
 {
        /* 3 cycles per loop. */
index d92a5a2d36d40c434ee833543275b6e296ef192b..1e9ade8e77e69e1dfd3c1f0d0595db5af853c90c 100644 (file)
@@ -74,7 +74,7 @@ extern unsigned long max_pfn;
 #define page_to_bus(page)      (page_to_phys(page))
 #define phys_to_page(paddr)    (pfn_to_page(phys_to_pfn(paddr)))
 
-#define pfn_valid(pfn)         ((pfn) >= min_low_pfn && (pfn) < max_mapnr)
+#define pfn_valid(pfn)         (((pfn) >= min_low_pfn) && ((pfn) < max_low_pfn))
 
 #define ARCH_PFN_OFFSET                (PAGE_OFFSET >> PAGE_SHIFT)
 
index 6a2503c75c4ef113f06421a41d09d962118d1368..6f898c0578781cf0862863d6e23a931c60b12c17 100644 (file)
@@ -49,6 +49,7 @@ static void __init bootmem_init(void)
 
        min_low_pfn = PFN_UP(MEMORY_START);
        max_low_pfn = PFN_UP(MEMORY_START + MEMORY_SIZE);
+       max_mapnr = max_low_pfn - min_low_pfn;
 
        /* Initialize the boot-time allocator with low memory only. */
        bootmap_size = init_bootmem_node(NODE_DATA(0), start_pfn,
index dbac9d9dfddd3d3e30a305f294fc9e99d39d9e34..b25e957436000a1f94f51e8d4264e9500a84469b 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/sched.h>
+#include <linux/fs.h>
 
 #include <asm/mmu_context.h>
 
@@ -51,6 +52,27 @@ static void flush_data_cache_page(unsigned long addr)
        }
 }
 
+void flush_dcache_page(struct page *page)
+{
+       struct address_space *mapping = page_mapping(page);
+       unsigned long addr;
+
+       if (PageHighMem(page))
+               return;
+       if (mapping && !mapping_mapped(mapping)) {
+               set_bit(PG_dcache_dirty, &(page)->flags);
+               return;
+       }
+
+       /*
+        * We could delay the flush for the !page_mapping case too.  But that
+        * case is for exec env/arg pages and those are %99 certainly going to
+        * get faulted into the tlb (and thus flushed) anyways.
+        */
+       addr = (unsigned long) page_address(page);
+       flush_data_cache_page(addr);
+}
+
 /* called by update_mmu_cache. */
 void __update_cache(struct vm_area_struct *vma, unsigned long address,
                pte_t pte)
@@ -63,11 +85,11 @@ void __update_cache(struct vm_area_struct *vma, unsigned long address,
        if (unlikely(!pfn_valid(pfn)))
                return;
        page = pfn_to_page(pfn);
-       if (page_mapping(page) && test_bit(PG_arch_1, &page->flags)) {
+       if (page_mapping(page) && test_bit(PG_dcache_dirty, &(page)->flags)) {
                addr = (unsigned long) page_address(page);
                if (exec)
                        flush_data_cache_page(addr);
-               clear_bit(PG_arch_1, &page->flags);
+               clear_bit(PG_dcache_dirty, &(page)->flags);
        }
 }
 
index 4e3dcd0c4716d85a413972472f10f0b39aa6c86b..8c15b2c85d5a1d6afb6d7996f16b08948a21baee 100644 (file)
@@ -83,7 +83,6 @@ void __init mem_init(void)
        unsigned long codesize, reservedpages, datasize, initsize;
        unsigned long tmp, ram = 0;
 
-       max_mapnr = max_low_pfn;
        high_memory = (void *) __va(max_low_pfn << PAGE_SHIFT);
        totalram_pages += free_all_bootmem();
        totalram_pages -= setup_zero_page();    /* Setup zeroed pages. */
@@ -101,10 +100,6 @@ void __init mem_init(void)
        datasize = (unsigned long) &_edata - (unsigned long) &_etext;
        initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
 
-       kclist_add(&kcore_mem, __va(0), max_low_pfn << PAGE_SHIFT);
-       kclist_add(&kcore_vmalloc, (void *) VMALLOC_START,
-                       VMALLOC_END - VMALLOC_START);
-
        printk(KERN_INFO "Memory: %luk/%luk available (%ldk kernel code, "
                        "%ldk reserved, %ldk data, %ldk init, %ldk highmem)\n",
                        (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
index ac17c5ac550e6d21a84a46ebc67ada146abec89f..db91925c79d1185665dafc0216c01f7df8c346af 100644 (file)
@@ -205,10 +205,7 @@ libs-$(CONFIG_SUPERH64)            := arch/sh/lib64/ $(libs-y)
 
 BOOT_TARGETS = uImage uImage.bz2 uImage.gz uImage.lzma uImage.srec uImage.bin \
               zImage vmlinux.srec romImage
-PHONY += maketools $(BOOT_TARGETS) FORCE
-
-maketools:  include/linux/version.h FORCE
-       $(Q)$(MAKE) $(build)=arch/sh/tools include/asm-sh/machtypes.h
+PHONY += $(BOOT_TARGETS)
 
 all: $(KBUILD_IMAGE)
 
@@ -217,7 +214,8 @@ $(BOOT_TARGETS): vmlinux
 
 compressed: zImage
 
-archprepare: maketools
+archprepare:
+       $(Q)$(MAKE) $(build)=arch/sh/tools include/generated/machtypes.h
 
 archclean:
        $(Q)$(MAKE) $(clean)=$(boot)
@@ -234,5 +232,3 @@ define archhelp
        @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 052b354236dcf02e039d539254c3a5e66e00e0de..7898f14d6641e701dc8438a53b539d4a89fa624b 100644 (file)
@@ -15,7 +15,7 @@
 #include <mach/lboxre2.h>
 #include <mach/r2d.h>
 #include "pci-sh4.h"
-#include <asm/machtypes.h>
+#include <generated/machtypes.h>
 
 #define PCIMCR_MRSET_OFF       0xBFFFFFFF
 #define PCIMCR_RFSH_OFF                0xFFFFFFFB
diff --git a/arch/sh/include/asm/.gitignore b/arch/sh/include/asm/.gitignore
deleted file mode 100644 (file)
index 378db77..0000000
+++ /dev/null
@@ -1 +0,0 @@
-machtypes.h
diff --git a/arch/sh/include/asm/asm-offsets.h b/arch/sh/include/asm/asm-offsets.h
new file mode 100644 (file)
index 0000000..d370ee3
--- /dev/null
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
index 84dd37761f563ee56aef820e97d6d1cc844f0936..9c30955630ffb8882064a53a54c76e9d810af659 100644 (file)
@@ -12,7 +12,7 @@
 
 #include <linux/types.h>
 #include <linux/time.h>
-#include <asm/machtypes.h>
+#include <generated/machtypes.h>
 
 struct sh_machine_vector {
        void (*mv_setup)(char **cmdline_p);
index 567516b58acca40ff99ada5fd9bd1bd100b91496..558a56bcc7cff69d0e5fbd7035ed9a717ab94061 100644 (file)
@@ -10,7 +10,7 @@
 # Shamelessly cloned from ARM.
 #
 
-include/asm-sh/machtypes.h: $(src)/gen-mach-types $(src)/mach-types
+include/generated/machtypes.h: $(src)/gen-mach-types $(src)/mach-types
        @echo '  Generating $@'
-       $(Q)if [ ! -d include/asm-sh ]; then mkdir -p include/asm-sh; fi
+       $(Q)mkdir -p $(dir $@)
        $(Q)$(AWK) -f $^ > $@ || { rm -f $@; /bin/false; }
index 65161e368353609fe58081a4fb6034aa3168a6de..f5ff7c5d8913cd23b1dd6f178827008d11efba96 100644 (file)
@@ -1,6 +1,6 @@
 #!/bin/awk
 #
-# Awk script to generate include/asm-sh/machtypes.h
+# Awk script to generate include/generated/machtypes.h
 # Heavily based on arch/arm/tools/gen-mach-types
 #
 BEGIN  { nr = 0 }
diff --git a/arch/sparc/include/asm/asm-offsets.h b/arch/sparc/include/asm/asm-offsets.h
new file mode 100644 (file)
index 0000000..d370ee3
--- /dev/null
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
index 3b9cfb39175e7dba1122ce9d8250b28eaa994c78..38f37b333cc7f5b277ea29646e2a0f14cfcfe325 100644 (file)
@@ -19,7 +19,7 @@
 #define O_NOATIME      0x200000
 #define O_CLOEXEC      0x400000
 /*
- * Before Linux 2.6.32 only O_DSYNC semantics were implemented, but using
+ * Before Linux 2.6.33 only O_DSYNC semantics were implemented, but using
  * the O_SYNC flag.  We continue to use the existing numerical value
  * for O_DSYNC semantics now, but using the correct symbolic name for it.
  * This new value is used to request true Posix O_SYNC semantics.  It is
index fc633dbacf84b818e1f6ac64fff887852431526d..fab8121d2b32a2059ea24ac2a70b5da3c221a888 100644 (file)
@@ -149,6 +149,6 @@ $(SHARED_HEADERS)/user_constants.h: $(ARCH_DIR)/sys-$(SUBARCH)/user-offsets.s
 
 $(SHARED_HEADERS)/kern_constants.h:
        $(Q)mkdir -p $(dir $@)
-       $(Q)echo '#include "../../../../include/asm/asm-offsets.h"' >$@
+       $(Q)echo '#include "../../../../include/generated/asm-offsets.h"' >$@
 
 export SUBARCH USER_CFLAGS CFLAGS_NO_HARDENING OS HEADER_ARCH DEV_NULL_PATH
diff --git a/arch/um/include/asm/asm-offsets.h b/arch/um/include/asm/asm-offsets.h
new file mode 100644 (file)
index 0000000..d370ee3
--- /dev/null
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
index b31cc54b46410f89b4120702b1d1b018a79e204d..93e689f4bd86f78730e4feb4f1f08c4e1f4d6dae 100644 (file)
@@ -16,7 +16,7 @@
  */
 
 #include <asm/segment.h>
-#include <linux/utsrelease.h>
+#include <generated/utsrelease.h>
 #include <asm/boot.h>
 #include <asm/e820.h>
 #include <asm/page_types.h>
index 2723d9b5ce432b4d229a9d3cbe47f9b8fdf08a2c..2b15aa488ffb2af8d446a20f26eab07b8e21d8d5 100644 (file)
@@ -13,8 +13,8 @@
  */
 
 #include "boot.h"
-#include <linux/utsrelease.h>
-#include <linux/compile.h>
+#include <generated/utsrelease.h>
+#include <generated/compile.h>
 
 const char kernel_version[] =
        UTS_RELEASE " (" LINUX_COMPILE_BY "@" LINUX_COMPILE_HOST ") "
diff --git a/arch/x86/include/asm/asm-offsets.h b/arch/x86/include/asm/asm-offsets.h
new file mode 100644 (file)
index 0000000..d370ee3
--- /dev/null
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
index 2779321046bd53e789847b10c18c99893e054e31..017d937639fef87694eea7cd3cbbf95efb163d37 100644 (file)
@@ -509,14 +509,14 @@ static int genregs_get(struct task_struct *target,
 {
        if (kbuf) {
                unsigned long *k = kbuf;
-               while (count > 0) {
+               while (count >= sizeof(*k)) {
                        *k++ = getreg(target, pos);
                        count -= sizeof(*k);
                        pos += sizeof(*k);
                }
        } else {
                unsigned long __user *u = ubuf;
-               while (count > 0) {
+               while (count >= sizeof(*u)) {
                        if (__put_user(getreg(target, pos), u++))
                                return -EFAULT;
                        count -= sizeof(*u);
@@ -535,14 +535,14 @@ static int genregs_set(struct task_struct *target,
        int ret = 0;
        if (kbuf) {
                const unsigned long *k = kbuf;
-               while (count > 0 && !ret) {
+               while (count >= sizeof(*k) && !ret) {
                        ret = putreg(target, pos, *k++);
                        count -= sizeof(*k);
                        pos += sizeof(*k);
                }
        } else {
                const unsigned long  __user *u = ubuf;
-               while (count > 0 && !ret) {
+               while (count >= sizeof(*u) && !ret) {
                        unsigned long word;
                        ret = __get_user(word, u++);
                        if (ret)
@@ -1458,14 +1458,14 @@ static int genregs32_get(struct task_struct *target,
 {
        if (kbuf) {
                compat_ulong_t *k = kbuf;
-               while (count > 0) {
+               while (count >= sizeof(*k)) {
                        getreg32(target, pos, k++);
                        count -= sizeof(*k);
                        pos += sizeof(*k);
                }
        } else {
                compat_ulong_t __user *u = ubuf;
-               while (count > 0) {
+               while (count >= sizeof(*u)) {
                        compat_ulong_t word;
                        getreg32(target, pos, &word);
                        if (__put_user(word, u++))
@@ -1486,14 +1486,14 @@ static int genregs32_set(struct task_struct *target,
        int ret = 0;
        if (kbuf) {
                const compat_ulong_t *k = kbuf;
-               while (count > 0 && !ret) {
+               while (count >= sizeof(*k) && !ret) {
                        ret = putreg32(target, pos, *k++);
                        count -= sizeof(*k);
                        pos += sizeof(*k);
                }
        } else {
                const compat_ulong_t __user *u = ubuf;
-               while (count > 0 && !ret) {
+               while (count >= sizeof(*u) && !ret) {
                        compat_ulong_t word;
                        ret = __get_user(word, u++);
                        if (ret)
diff --git a/arch/xtensa/include/asm/asm-offsets.h b/arch/xtensa/include/asm/asm-offsets.h
new file mode 100644 (file)
index 0000000..d370ee3
--- /dev/null
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
index d672cfe7ca5960997949ebede8bda6cd1088bbb8..cb423f5aef24b12247b1c604e021c421581cb4a9 100644 (file)
@@ -21,7 +21,6 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/autoconf.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
index 27ae750ca878436ec156dfedec7c0d26ce366adf..bf31592eaf79dc32757296f47191e6e66f1d2477 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef __HID_LG_H
 #define __HID_LG_H
 
-#include <linux/autoconf.h>
-
 #ifdef CONFIG_LOGITECH_FF
 int lgff_init(struct hid_device *hdev);
 #else
index 95ccbe377f9c91398dd0f20300d9dd430eb4deeb..bf28945c610d14cb933f2cb7fd50cdbc4946d27c 100644 (file)
@@ -998,6 +998,23 @@ config SENSORS_LIS3_SPI
          will be called lis3lv02d and a specific module for the SPI transport
          is called lis3lv02d_spi.
 
+config SENSORS_LIS3_I2C
+       tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (I2C)"
+       depends on I2C && INPUT
+       select INPUT_POLLDEV
+       default n
+       help
+         This driver provides support for the LIS3LV02Dx accelerometer connected
+         via I2C. The accelerometer data is readable via
+         /sys/devices/platform/lis3lv02d.
+
+         This driver also provides an absolute input class device, allowing
+         the device to act as a pinball machine-esque joystick.
+
+         This driver can also be built as modules.  If so, the core module
+         will be called lis3lv02d and a specific module for the I2C transport
+         is called lis3lv02d_i2c.
+
 config SENSORS_APPLESMC
        tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)"
        depends on INPUT && X86
index 33c2ee105284124ee1247823fc391c4611577771..4131e253f96a17b551c6d5fccfb5323d73029296 100644 (file)
@@ -55,6 +55,7 @@ obj-$(CONFIG_SENSORS_IT87)    += it87.o
 obj-$(CONFIG_SENSORS_K8TEMP)   += k8temp.o
 obj-$(CONFIG_SENSORS_LIS3LV02D) += lis3lv02d.o hp_accel.o
 obj-$(CONFIG_SENSORS_LIS3_SPI) += lis3lv02d.o lis3lv02d_spi.o
+obj-$(CONFIG_SENSORS_LIS3_I2C) += lis3lv02d.o lis3lv02d_i2c.o
 obj-$(CONFIG_SENSORS_LM63)     += lm63.o
 obj-$(CONFIG_SENSORS_LM70)     += lm70.o
 obj-$(CONFIG_SENSORS_LM73)     += lm73.o
diff --git a/drivers/hwmon/lis3lv02d_i2c.c b/drivers/hwmon/lis3lv02d_i2c.c
new file mode 100644 (file)
index 0000000..dc1f540
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * drivers/hwmon/lis3lv02d_i2c.c
+ *
+ * Implements I2C interface for lis3lv02d (STMicroelectronics) accelerometer.
+ * Driver is based on corresponding SPI driver written by Daniel Mack
+ * (lis3lv02d_spi.c (C) 2009 Daniel Mack <daniel@caiaq.de> ).
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: Samu Onkalo <samu.p.onkalo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include "lis3lv02d.h"
+
+#define DRV_NAME       "lis3lv02d_i2c"
+
+static inline s32 lis3_i2c_write(struct lis3lv02d *lis3, int reg, u8 value)
+{
+       struct i2c_client *c = lis3->bus_priv;
+       return i2c_smbus_write_byte_data(c, reg, value);
+}
+
+static inline s32 lis3_i2c_read(struct lis3lv02d *lis3, int reg, u8 *v)
+{
+       struct i2c_client *c = lis3->bus_priv;
+       *v = i2c_smbus_read_byte_data(c, reg);
+       return 0;
+}
+
+static int lis3_i2c_init(struct lis3lv02d *lis3)
+{
+       u8 reg;
+       int ret;
+
+       /* power up the device */
+       ret = lis3->read(lis3, CTRL_REG1, &reg);
+       if (ret < 0)
+               return ret;
+
+       reg |= CTRL1_PD0;
+       return lis3->write(lis3, CTRL_REG1, reg);
+}
+
+/* Default axis mapping but it can be overwritten by platform data */
+static struct axis_conversion lis3lv02d_axis_map = { LIS3_DEV_X,
+                                                    LIS3_DEV_Y,
+                                                    LIS3_DEV_Z };
+
+static int __devinit lis3lv02d_i2c_probe(struct i2c_client *client,
+                                       const struct i2c_device_id *id)
+{
+       int ret = 0;
+       struct lis3lv02d_platform_data *pdata = client->dev.platform_data;
+
+       if (pdata) {
+               if (pdata->axis_x)
+                       lis3lv02d_axis_map.x = pdata->axis_x;
+
+               if (pdata->axis_y)
+                       lis3lv02d_axis_map.y = pdata->axis_y;
+
+               if (pdata->axis_z)
+                       lis3lv02d_axis_map.z = pdata->axis_z;
+
+               if (pdata->setup_resources)
+                       ret = pdata->setup_resources();
+
+               if (ret)
+                       goto fail;
+       }
+
+       lis3_dev.pdata    = pdata;
+       lis3_dev.bus_priv = client;
+       lis3_dev.init     = lis3_i2c_init;
+       lis3_dev.read     = lis3_i2c_read;
+       lis3_dev.write    = lis3_i2c_write;
+       lis3_dev.irq      = client->irq;
+       lis3_dev.ac       = lis3lv02d_axis_map;
+
+       i2c_set_clientdata(client, &lis3_dev);
+       ret = lis3lv02d_init_device(&lis3_dev);
+fail:
+       return ret;
+}
+
+static int __devexit lis3lv02d_i2c_remove(struct i2c_client *client)
+{
+       struct lis3lv02d *lis3 = i2c_get_clientdata(client);
+       struct lis3lv02d_platform_data *pdata = client->dev.platform_data;
+
+       if (pdata && pdata->release_resources)
+               pdata->release_resources();
+
+       lis3lv02d_joystick_disable();
+       lis3lv02d_poweroff(lis3);
+
+       return lis3lv02d_remove_fs(&lis3_dev);
+}
+
+#ifdef CONFIG_PM
+static int lis3lv02d_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+       struct lis3lv02d *lis3 = i2c_get_clientdata(client);
+
+       if (!lis3->pdata->wakeup_flags)
+               lis3lv02d_poweroff(lis3);
+       return 0;
+}
+
+static int lis3lv02d_i2c_resume(struct i2c_client *client)
+{
+       struct lis3lv02d *lis3 = i2c_get_clientdata(client);
+
+       if (!lis3->pdata->wakeup_flags)
+               lis3lv02d_poweron(lis3);
+       return 0;
+}
+
+static void lis3lv02d_i2c_shutdown(struct i2c_client *client)
+{
+       lis3lv02d_i2c_suspend(client, PMSG_SUSPEND);
+}
+#else
+#define lis3lv02d_i2c_suspend  NULL
+#define lis3lv02d_i2c_resume   NULL
+#define lis3lv02d_i2c_shutdown NULL
+#endif
+
+static const struct i2c_device_id lis3lv02d_id[] = {
+       {"lis3lv02d", 0 },
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, lis3lv02d_id);
+
+static struct i2c_driver lis3lv02d_i2c_driver = {
+       .driver  = {
+               .name   = DRV_NAME,
+               .owner  = THIS_MODULE,
+       },
+       .suspend = lis3lv02d_i2c_suspend,
+       .shutdown = lis3lv02d_i2c_shutdown,
+       .resume = lis3lv02d_i2c_resume,
+       .probe  = lis3lv02d_i2c_probe,
+       .remove = __devexit_p(lis3lv02d_i2c_remove),
+       .id_table = lis3lv02d_id,
+};
+
+static int __init lis3lv02d_init(void)
+{
+       return i2c_add_driver(&lis3lv02d_i2c_driver);
+}
+
+static void __exit lis3lv02d_exit(void)
+{
+       i2c_del_driver(&lis3lv02d_i2c_driver);
+}
+
+MODULE_AUTHOR("Nokia Corporation");
+MODULE_DESCRIPTION("lis3lv02d I2C interface");
+MODULE_LICENSE("GPL");
+
+module_init(lis3lv02d_init);
+module_exit(lis3lv02d_exit);
index e4f599f20e38f5804da67013cc5936834de3e2e1..8a0e1ec95e4aaf03bf3d8a91fd6a6ef32db07ec7 100644 (file)
@@ -229,6 +229,12 @@ config LEDS_PWM
        help
          This option enables support for pwm driven LEDs
 
+config LEDS_REGULATOR
+       tristate "REGULATOR driven LED support"
+       depends on LEDS_CLASS && REGULATOR
+       help
+         This option enables support for regulator driven LEDs.
+
 config LEDS_BD2802
        tristate "LED driver for BD2802 RGB LED"
        depends on LEDS_CLASS && I2C
@@ -236,6 +242,33 @@ config LEDS_BD2802
          This option enables support for BD2802GU RGB LED driver chips
          accessed via the I2C bus.
 
+config LEDS_INTEL_SS4200
+       tristate "LED driver for Intel NAS SS4200 series"
+       depends on LEDS_CLASS && PCI && DMI
+       help
+         This option enables support for the Intel SS4200 series of
+         Network Attached Storage servers.  You may control the hard
+         drive or power LEDs on the front panel.  Using this driver
+         can stop the front LED from blinking after startup.
+
+config LEDS_LT3593
+       tristate "LED driver for LT3593 controllers"
+       depends on LEDS_CLASS && GENERIC_GPIO
+       help
+         This option enables support for LEDs driven by a Linear Technology
+         LT3593 controller. This controller uses a special one-wire pulse
+         coding protocol to set the brightness.
+
+config LEDS_ADP5520
+       tristate "LED Support for ADP5520/ADP5501 PMIC"
+       depends on LEDS_CLASS && PMIC_ADP5520
+       help
+         This option enables support for on-chip LED drivers found
+         on Analog Devices ADP5520/ADP5501 PMICs.
+
+         To compile this driver as a module, choose M here: the module will
+         be called leds-adp5520.
+
 comment "LED Triggers"
 
 config LEDS_TRIGGERS
index 46d72704d60651c43031a220f7dc416043b63774..9e63869d7c0d1bfd2e211d890f5b57371c4e1f65 100644 (file)
@@ -29,6 +29,10 @@ obj-$(CONFIG_LEDS_DA903X)            += leds-da903x.o
 obj-$(CONFIG_LEDS_WM831X_STATUS)       += leds-wm831x-status.o
 obj-$(CONFIG_LEDS_WM8350)              += leds-wm8350.o
 obj-$(CONFIG_LEDS_PWM)                 += leds-pwm.o
+obj-$(CONFIG_LEDS_REGULATOR)           += leds-regulator.o
+obj-$(CONFIG_LEDS_INTEL_SS4200)                += leds-ss4200.o
+obj-$(CONFIG_LEDS_LT3593)              += leds-lt3593.o
+obj-$(CONFIG_LEDS_ADP5520)             += leds-adp5520.o
 
 # LED SPI Drivers
 obj-$(CONFIG_LEDS_DAC124S085)          += leds-dac124s085.o
diff --git a/drivers/leds/leds-adp5520.c b/drivers/leds/leds-adp5520.c
new file mode 100644 (file)
index 0000000..a8f3159
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * LEDs driver for Analog Devices ADP5520/ADP5501 MFD PMICs
+ *
+ * Copyright 2009 Analog Devices Inc.
+ *
+ * Loosely derived from leds-da903x:
+ * Copyright (C) 2008 Compulab, Ltd.
+ *     Mike Rapoport <mike@compulab.co.il>
+ *
+ * Copyright (C) 2006-2008 Marvell International Ltd.
+ *     Eric Miao <eric.miao@marvell.com>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/workqueue.h>
+#include <linux/mfd/adp5520.h>
+
+struct adp5520_led {
+       struct led_classdev     cdev;
+       struct work_struct      work;
+       struct device           *master;
+       enum led_brightness     new_brightness;
+       int                     id;
+       int                     flags;
+};
+
+static void adp5520_led_work(struct work_struct *work)
+{
+       struct adp5520_led *led = container_of(work, struct adp5520_led, work);
+       adp5520_write(led->master, ADP5520_LED1_CURRENT + led->id - 1,
+                        led->new_brightness >> 2);
+}
+
+static void adp5520_led_set(struct led_classdev *led_cdev,
+                          enum led_brightness value)
+{
+       struct adp5520_led *led;
+
+       led = container_of(led_cdev, struct adp5520_led, cdev);
+       led->new_brightness = value;
+       schedule_work(&led->work);
+}
+
+static int adp5520_led_setup(struct adp5520_led *led)
+{
+       struct device *dev = led->master;
+       int flags = led->flags;
+       int ret = 0;
+
+       switch (led->id) {
+       case FLAG_ID_ADP5520_LED1_ADP5501_LED0:
+               ret |= adp5520_set_bits(dev, ADP5520_LED_TIME,
+                                       (flags >> ADP5520_FLAG_OFFT_SHIFT) &
+                                       ADP5520_FLAG_OFFT_MASK);
+               ret |= adp5520_set_bits(dev, ADP5520_LED_CONTROL,
+                                       ADP5520_LED1_EN);
+               break;
+       case FLAG_ID_ADP5520_LED2_ADP5501_LED1:
+               ret |= adp5520_set_bits(dev,  ADP5520_LED_TIME,
+                                       ((flags >> ADP5520_FLAG_OFFT_SHIFT) &
+                                       ADP5520_FLAG_OFFT_MASK) << 2);
+               ret |= adp5520_clr_bits(dev, ADP5520_LED_CONTROL,
+                                        ADP5520_R3_MODE);
+               ret |= adp5520_set_bits(dev, ADP5520_LED_CONTROL,
+                                       ADP5520_LED2_EN);
+               break;
+       case FLAG_ID_ADP5520_LED3_ADP5501_LED2:
+               ret |= adp5520_set_bits(dev,  ADP5520_LED_TIME,
+                                       ((flags >> ADP5520_FLAG_OFFT_SHIFT) &
+                                       ADP5520_FLAG_OFFT_MASK) << 4);
+               ret |= adp5520_clr_bits(dev, ADP5520_LED_CONTROL,
+                                       ADP5520_C3_MODE);
+               ret |= adp5520_set_bits(dev, ADP5520_LED_CONTROL,
+                                       ADP5520_LED3_EN);
+               break;
+       }
+
+       return ret;
+}
+
+static int __devinit adp5520_led_prepare(struct platform_device *pdev)
+{
+       struct adp5520_leds_platform_data *pdata = pdev->dev.platform_data;
+       struct device *dev = pdev->dev.parent;
+       int ret = 0;
+
+       ret |= adp5520_write(dev, ADP5520_LED1_CURRENT, 0);
+       ret |= adp5520_write(dev, ADP5520_LED2_CURRENT, 0);
+       ret |= adp5520_write(dev, ADP5520_LED3_CURRENT, 0);
+       ret |= adp5520_write(dev, ADP5520_LED_TIME, pdata->led_on_time << 6);
+       ret |= adp5520_write(dev, ADP5520_LED_FADE, FADE_VAL(pdata->fade_in,
+                pdata->fade_out));
+
+       return ret;
+}
+
+static int __devinit adp5520_led_probe(struct platform_device *pdev)
+{
+       struct adp5520_leds_platform_data *pdata = pdev->dev.platform_data;
+       struct adp5520_led *led, *led_dat;
+       struct led_info *cur_led;
+       int ret, i;
+
+       if (pdata == NULL) {
+               dev_err(&pdev->dev, "missing platform data\n");
+               return -ENODEV;
+       }
+
+       if (pdata->num_leds > ADP5520_01_MAXLEDS) {
+               dev_err(&pdev->dev, "can't handle more than %d LEDS\n",
+                                ADP5520_01_MAXLEDS);
+               return -EFAULT;
+       }
+
+       led = kzalloc(sizeof(*led) * pdata->num_leds, GFP_KERNEL);
+       if (led == NULL) {
+               dev_err(&pdev->dev, "failed to alloc memory\n");
+               return -ENOMEM;
+       }
+
+       ret = adp5520_led_prepare(pdev);
+
+       if (ret) {
+               dev_err(&pdev->dev, "failed to write\n");
+               goto err_free;
+       }
+
+       for (i = 0; i < pdata->num_leds; ++i) {
+               cur_led = &pdata->leds[i];
+               led_dat = &led[i];
+
+               led_dat->cdev.name = cur_led->name;
+               led_dat->cdev.default_trigger = cur_led->default_trigger;
+               led_dat->cdev.brightness_set = adp5520_led_set;
+               led_dat->cdev.brightness = LED_OFF;
+
+               if (cur_led->flags & ADP5520_FLAG_LED_MASK)
+                       led_dat->flags = cur_led->flags;
+               else
+                       led_dat->flags = i + 1;
+
+               led_dat->id = led_dat->flags & ADP5520_FLAG_LED_MASK;
+
+               led_dat->master = pdev->dev.parent;
+               led_dat->new_brightness = LED_OFF;
+
+               INIT_WORK(&led_dat->work, adp5520_led_work);
+
+               ret = led_classdev_register(led_dat->master, &led_dat->cdev);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to register LED %d\n",
+                               led_dat->id);
+                       goto err;
+               }
+
+               ret = adp5520_led_setup(led_dat);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to write\n");
+                       i++;
+                       goto err;
+               }
+       }
+
+       platform_set_drvdata(pdev, led);
+       return 0;
+
+err:
+       if (i > 0) {
+               for (i = i - 1; i >= 0; i--) {
+                       led_classdev_unregister(&led[i].cdev);
+                       cancel_work_sync(&led[i].work);
+               }
+       }
+
+err_free:
+       kfree(led);
+       return ret;
+}
+
+static int __devexit adp5520_led_remove(struct platform_device *pdev)
+{
+       struct adp5520_leds_platform_data *pdata = pdev->dev.platform_data;
+       struct adp5520_led *led;
+       int i;
+
+       led = platform_get_drvdata(pdev);
+
+       adp5520_clr_bits(led->master, ADP5520_LED_CONTROL,
+                ADP5520_LED1_EN | ADP5520_LED2_EN | ADP5520_LED3_EN);
+
+       for (i = 0; i < pdata->num_leds; i++) {
+               led_classdev_unregister(&led[i].cdev);
+               cancel_work_sync(&led[i].work);
+       }
+
+       kfree(led);
+       return 0;
+}
+
+static struct platform_driver adp5520_led_driver = {
+       .driver = {
+               .name   = "adp5520-led",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = adp5520_led_probe,
+       .remove         = __devexit_p(adp5520_led_remove),
+};
+
+static int __init adp5520_led_init(void)
+{
+       return platform_driver_register(&adp5520_led_driver);
+}
+module_init(adp5520_led_init);
+
+static void __exit adp5520_led_exit(void)
+{
+       platform_driver_unregister(&adp5520_led_driver);
+}
+module_exit(adp5520_led_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("LEDS ADP5520(01) Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:adp5520-led");
index 731d4eef342590dca6566f229d60d7f8add6b872..f59ffadf51253991451adbbc7b51eb25142ad937 100644 (file)
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/string.h>
+#include <linux/pci.h>
 
 static int force = 0;
 module_param(force, bool, 0444);
 MODULE_PARM_DESC(force, "Assume system has ALIX.2/ALIX.3 style LEDs");
 
+#define MSR_LBAR_GPIO          0x5140000C
+#define CS5535_GPIO_SIZE       256
+
+static u32 gpio_base;
+
+static struct pci_device_id divil_pci[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_NS,  PCI_DEVICE_ID_NS_CS5535_ISA) },
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) },
+       { } /* NULL entry */
+};
+MODULE_DEVICE_TABLE(pci, divil_pci);
+
 struct alix_led {
        struct led_classdev cdev;
        unsigned short port;
@@ -30,9 +43,9 @@ static void alix_led_set(struct led_classdev *led_cdev,
                container_of(led_cdev, struct alix_led, cdev);
 
        if (brightness)
-               outl(led_dev->on_value, led_dev->port);
+               outl(led_dev->on_value, gpio_base + led_dev->port);
        else
-               outl(led_dev->off_value, led_dev->port);
+               outl(led_dev->off_value, gpio_base + led_dev->port);
 }
 
 static struct alix_led alix_leds[] = {
@@ -41,7 +54,7 @@ static struct alix_led alix_leds[] = {
                        .name = "alix:1",
                        .brightness_set = alix_led_set,
                },
-               .port = 0x6100,
+               .port = 0x00,
                .on_value = 1 << 22,
                .off_value = 1 << 6,
        },
@@ -50,7 +63,7 @@ static struct alix_led alix_leds[] = {
                        .name = "alix:2",
                        .brightness_set = alix_led_set,
                },
-               .port = 0x6180,
+               .port = 0x80,
                .on_value = 1 << 25,
                .off_value = 1 << 9,
        },
@@ -59,7 +72,7 @@ static struct alix_led alix_leds[] = {
                        .name = "alix:3",
                        .brightness_set = alix_led_set,
                },
-               .port = 0x6180,
+               .port = 0x80,
                .on_value = 1 << 27,
                .off_value = 1 << 11,
        },
@@ -101,64 +114,104 @@ static struct platform_driver alix_led_driver = {
        },
 };
 
-static int __init alix_present(void)
+static int __init alix_present(unsigned long bios_phys,
+                               const char *alix_sig,
+                               size_t alix_sig_len)
 {
-       const unsigned long bios_phys = 0x000f0000;
        const size_t bios_len = 0x00010000;
-       const char alix_sig[] = "PC Engines ALIX.";
-       const size_t alix_sig_len = sizeof(alix_sig) - 1;
-
        const char *bios_virt;
        const char *scan_end;
        const char *p;
-       int ret = 0;
+       char name[64];
 
        if (force) {
                printk(KERN_NOTICE "%s: forced to skip BIOS test, "
                       "assume system has ALIX.2 style LEDs\n",
                       KBUILD_MODNAME);
-               ret = 1;
-               goto out;
+               return 1;
        }
 
        bios_virt = phys_to_virt(bios_phys);
        scan_end = bios_virt + bios_len - (alix_sig_len + 2);
        for (p = bios_virt; p < scan_end; p++) {
                const char *tail;
+               char *a;
 
-               if (memcmp(p, alix_sig, alix_sig_len) != 0) {
+               if (memcmp(p, alix_sig, alix_sig_len) != 0)
                        continue;
-               }
+
+               memcpy(name, p, sizeof(name));
+
+               /* remove the first \0 character from string */
+               a = strchr(name, '\0');
+               if (a)
+                       *a = ' ';
+
+               /* cut the string at a newline */
+               a = strchr(name, '\r');
+               if (a)
+                       *a = '\0';
 
                tail = p + alix_sig_len;
-               if ((tail[0] == '2' || tail[0] == '3') && tail[1] == '\0') {
+               if ((tail[0] == '2' || tail[0] == '3')) {
                        printk(KERN_INFO
                               "%s: system is recognized as \"%s\"\n",
-                              KBUILD_MODNAME, p);
-                       ret = 1;
-                       break;
+                              KBUILD_MODNAME, name);
+                       return 1;
                }
        }
 
-out:
-       return ret;
+       return 0;
 }
 
 static struct platform_device *pdev;
 
-static int __init alix_led_init(void)
+static int __init alix_pci_led_init(void)
 {
-       int ret;
+       u32 low, hi;
 
-       if (!alix_present()) {
-               ret = -ENODEV;
-               goto out;
+       if (pci_dev_present(divil_pci) == 0) {
+               printk(KERN_WARNING KBUILD_MODNAME": DIVIL not found\n");
+               return -ENODEV;
        }
 
-       /* enable output on GPIO for LED 1,2,3 */
-       outl(1 << 6, 0x6104);
-       outl(1 << 9, 0x6184);
-       outl(1 << 11, 0x6184);
+       /* Grab the GPIO I/O range */
+       rdmsr(MSR_LBAR_GPIO, low, hi);
+
+       /* Check the mask and whether GPIO is enabled (sanity check) */
+       if (hi != 0x0000f001) {
+               printk(KERN_WARNING KBUILD_MODNAME": GPIO not enabled\n");
+               return -ENODEV;
+       }
+
+       /* Mask off the IO base address */
+       gpio_base = low & 0x0000ff00;
+
+       if (!request_region(gpio_base, CS5535_GPIO_SIZE, KBUILD_MODNAME)) {
+               printk(KERN_ERR KBUILD_MODNAME": can't allocate I/O for GPIO\n");
+               return -ENODEV;
+       }
+
+       /* Set GPIO function to output */
+       outl(1 << 6, gpio_base + 0x04);
+       outl(1 << 9, gpio_base + 0x84);
+       outl(1 << 11, gpio_base + 0x84);
+
+       return 0;
+}
+
+static int __init alix_led_init(void)
+{
+       int ret = -ENODEV;
+       const char tinybios_sig[] = "PC Engines ALIX.";
+       const char coreboot_sig[] = "PC Engines\0ALIX.";
+
+       if (alix_present(0xf0000, tinybios_sig, sizeof(tinybios_sig) - 1) ||
+           alix_present(0x500, coreboot_sig, sizeof(coreboot_sig) - 1))
+               ret = alix_pci_led_init();
+
+       if (ret < 0)
+               return ret;
 
        pdev = platform_device_register_simple(KBUILD_MODNAME, -1, NULL, 0);
        if (!IS_ERR(pdev)) {
@@ -168,7 +221,6 @@ static int __init alix_led_init(void)
        } else
                ret = PTR_ERR(pdev);
 
-out:
        return ret;
 }
 
@@ -176,6 +228,7 @@ static void __exit alix_led_exit(void)
 {
        platform_device_unregister(pdev);
        platform_driver_unregister(&alix_led_driver);
+       release_region(gpio_base, CS5535_GPIO_SIZE);
 }
 
 module_init(alix_led_init);
index 8816806accd24a380c3877785f3bd71e5ddbbbf7..da5fb016b1a550fabfee5114bb11727a22c01749 100644 (file)
@@ -31,7 +31,7 @@ static struct led_classdev qube_front_led = {
        .name                   = "qube::front",
        .brightness             = LED_FULL,
        .brightness_set         = qube_front_led_set,
-       .default_trigger        = "ide-disk",
+       .default_trigger        = "default-on",
 };
 
 static int __devinit cobalt_qube_led_probe(struct platform_device *pdev)
@@ -43,7 +43,7 @@ static int __devinit cobalt_qube_led_probe(struct platform_device *pdev)
        if (!res)
                return -EBUSY;
 
-       led_port = ioremap(res->start, res->end - res->start + 1);
+       led_port = ioremap(res->start, resource_size(res));
        if (!led_port)
                return -ENOMEM;
 
index defc212105f3e4b12c216fadebbd82d1b9ab31ec..438d48384636f2d188e06a1ee648c41c190ce00c 100644 (file)
@@ -84,7 +84,7 @@ static int __devinit cobalt_raq_led_probe(struct platform_device *pdev)
        if (!res)
                return -EBUSY;
 
-       led_port = ioremap(res->start, res->end - res->start + 1);
+       led_port = ioremap(res->start, resource_size(res));
        if (!led_port)
                return -ENOMEM;
 
diff --git a/drivers/leds/leds-lt3593.c b/drivers/leds/leds-lt3593.c
new file mode 100644 (file)
index 0000000..fee40a8
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * LEDs driver for LT3593 controllers
+ *
+ * See the datasheet at http://cds.linear.com/docs/Datasheet/3593f.pdf
+ *
+ * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
+ *
+ * Based on leds-gpio.c,
+ *
+ *   Copyright (C) 2007 8D Technologies inc.
+ *   Raphael Assenat <raph@8d.com>
+ *   Copyright (C) 2008 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+
+struct lt3593_led_data {
+       struct led_classdev cdev;
+       unsigned gpio;
+       struct work_struct work;
+       u8 new_level;
+};
+
+static void lt3593_led_work(struct work_struct *work)
+{
+       int pulses;
+       struct lt3593_led_data *led_dat =
+               container_of(work, struct lt3593_led_data, work);
+
+       /*
+        * The LT3593 resets its internal current level register to the maximum
+        * level on the first falling edge on the control pin. Each following
+        * falling edge decreases the current level by 625uA. Up to 32 pulses
+        * can be sent, so the maximum power reduction is 20mA.
+        * After a timeout of 128us, the value is taken from the register and
+        * applied is to the output driver.
+        */
+
+       if (led_dat->new_level == 0) {
+               gpio_set_value_cansleep(led_dat->gpio, 0);
+               return;
+       }
+
+       pulses = 32 - (led_dat->new_level * 32) / 255;
+
+       if (pulses == 0) {
+               gpio_set_value_cansleep(led_dat->gpio, 0);
+               mdelay(1);
+               gpio_set_value_cansleep(led_dat->gpio, 1);
+               return;
+       }
+
+       gpio_set_value_cansleep(led_dat->gpio, 1);
+
+       while (pulses--) {
+               gpio_set_value_cansleep(led_dat->gpio, 0);
+               udelay(1);
+               gpio_set_value_cansleep(led_dat->gpio, 1);
+               udelay(1);
+       }
+}
+
+static void lt3593_led_set(struct led_classdev *led_cdev,
+       enum led_brightness value)
+{
+       struct lt3593_led_data *led_dat =
+               container_of(led_cdev, struct lt3593_led_data, cdev);
+
+       led_dat->new_level = value;
+       schedule_work(&led_dat->work);
+}
+
+static int __devinit create_lt3593_led(const struct gpio_led *template,
+       struct lt3593_led_data *led_dat, struct device *parent)
+{
+       int ret, state;
+
+       /* skip leds on GPIOs that aren't available */
+       if (!gpio_is_valid(template->gpio)) {
+               printk(KERN_INFO "%s: skipping unavailable LT3593 LED at gpio %d (%s)\n",
+                               KBUILD_MODNAME, template->gpio, template->name);
+               return 0;
+       }
+
+       ret = gpio_request(template->gpio, template->name);
+       if (ret < 0)
+               return ret;
+
+       led_dat->cdev.name = template->name;
+       led_dat->cdev.default_trigger = template->default_trigger;
+       led_dat->gpio = template->gpio;
+
+       led_dat->cdev.brightness_set = lt3593_led_set;
+
+       state = (template->default_state == LEDS_GPIO_DEFSTATE_ON);
+       led_dat->cdev.brightness = state ? LED_FULL : LED_OFF;
+
+       if (!template->retain_state_suspended)
+               led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
+
+       ret = gpio_direction_output(led_dat->gpio, state);
+       if (ret < 0)
+               goto err;
+
+       INIT_WORK(&led_dat->work, lt3593_led_work);
+
+       ret = led_classdev_register(parent, &led_dat->cdev);
+       if (ret < 0)
+               goto err;
+
+       printk(KERN_INFO "%s: registered LT3593 LED '%s' at GPIO %d\n",
+               KBUILD_MODNAME, template->name, template->gpio);
+
+       return 0;
+
+err:
+       gpio_free(led_dat->gpio);
+       return ret;
+}
+
+static void delete_lt3593_led(struct lt3593_led_data *led)
+{
+       if (!gpio_is_valid(led->gpio))
+               return;
+
+       led_classdev_unregister(&led->cdev);
+       cancel_work_sync(&led->work);
+       gpio_free(led->gpio);
+}
+
+static int __devinit lt3593_led_probe(struct platform_device *pdev)
+{
+       struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
+       struct lt3593_led_data *leds_data;
+       int i, ret = 0;
+
+       if (!pdata)
+               return -EBUSY;
+
+       leds_data = kzalloc(sizeof(struct lt3593_led_data) * pdata->num_leds,
+                               GFP_KERNEL);
+       if (!leds_data)
+               return -ENOMEM;
+
+       for (i = 0; i < pdata->num_leds; i++) {
+               ret = create_lt3593_led(&pdata->leds[i], &leds_data[i],
+                                     &pdev->dev);
+               if (ret < 0)
+                       goto err;
+       }
+
+       platform_set_drvdata(pdev, leds_data);
+
+       return 0;
+
+err:
+       for (i = i - 1; i >= 0; i--)
+               delete_lt3593_led(&leds_data[i]);
+
+       kfree(leds_data);
+
+       return ret;
+}
+
+static int __devexit lt3593_led_remove(struct platform_device *pdev)
+{
+       int i;
+       struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
+       struct lt3593_led_data *leds_data;
+
+       leds_data = platform_get_drvdata(pdev);
+
+       for (i = 0; i < pdata->num_leds; i++)
+               delete_lt3593_led(&leds_data[i]);
+
+       kfree(leds_data);
+
+       return 0;
+}
+
+static struct platform_driver lt3593_led_driver = {
+       .probe          = lt3593_led_probe,
+       .remove         = __devexit_p(lt3593_led_remove),
+       .driver         = {
+               .name   = "leds-lt3593",
+               .owner  = THIS_MODULE,
+       },
+};
+
+MODULE_ALIAS("platform:leds-lt3593");
+
+static int __init lt3593_led_init(void)
+{
+       return platform_driver_register(&lt3593_led_driver);
+}
+
+static void __exit lt3593_led_exit(void)
+{
+       platform_driver_unregister(&lt3593_led_driver);
+}
+
+module_init(lt3593_led_init);
+module_exit(lt3593_led_exit);
+
+MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
+MODULE_DESCRIPTION("LED driver for LT3593 controllers");
+MODULE_LICENSE("GPL");
index cdfdc8714e1056962506519ee56d63d043410f3f..88b1dd091cfb9f3887ec052f75a3f4e0620d69ad 100644 (file)
@@ -27,7 +27,6 @@ struct led_pwm_data {
        struct pwm_device       *pwm;
        unsigned int            active_low;
        unsigned int            period;
-       unsigned int            max_brightness;
 };
 
 static void led_pwm_set(struct led_classdev *led_cdev,
@@ -35,7 +34,7 @@ static void led_pwm_set(struct led_classdev *led_cdev,
 {
        struct led_pwm_data *led_dat =
                container_of(led_cdev, struct led_pwm_data, cdev);
-       unsigned int max = led_dat->max_brightness;
+       unsigned int max = led_dat->cdev.max_brightness;
        unsigned int period =  led_dat->period;
 
        if (brightness == 0) {
@@ -77,10 +76,10 @@ static int led_pwm_probe(struct platform_device *pdev)
                led_dat->cdev.name = cur_led->name;
                led_dat->cdev.default_trigger = cur_led->default_trigger;
                led_dat->active_low = cur_led->active_low;
-               led_dat->max_brightness = cur_led->max_brightness;
                led_dat->period = cur_led->pwm_period_ns;
                led_dat->cdev.brightness_set = led_pwm_set;
                led_dat->cdev.brightness = LED_OFF;
+               led_dat->cdev.max_brightness = cur_led->max_brightness;
                led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
 
                ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
diff --git a/drivers/leds/leds-regulator.c b/drivers/leds/leds-regulator.c
new file mode 100644 (file)
index 0000000..7f00de3
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * leds-regulator.c - LED class driver for regulator driven LEDs.
+ *
+ * Copyright (C) 2009 Antonio Ospite <ospite@studenti.unina.it>
+ *
+ * Inspired by leds-wm8350 driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/workqueue.h>
+#include <linux/leds.h>
+#include <linux/leds-regulator.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+
+#define to_regulator_led(led_cdev) \
+       container_of(led_cdev, struct regulator_led, cdev)
+
+struct regulator_led {
+       struct led_classdev cdev;
+       enum led_brightness value;
+       int enabled;
+       struct mutex mutex;
+       struct work_struct work;
+
+       struct regulator *vcc;
+};
+
+static inline int led_regulator_get_max_brightness(struct regulator *supply)
+{
+       int ret;
+       int voltage = regulator_list_voltage(supply, 0);
+
+       if (voltage <= 0)
+               return 1;
+
+       /* even if regulator can't change voltages,
+        * we still assume it can change status
+        * and the LED can be turned on and off.
+        */
+       ret = regulator_set_voltage(supply, voltage, voltage);
+       if (ret < 0)
+               return 1;
+
+       return regulator_count_voltages(supply);
+}
+
+static int led_regulator_get_voltage(struct regulator *supply,
+               enum led_brightness brightness)
+{
+       if (brightness == 0)
+               return -EINVAL;
+
+       return regulator_list_voltage(supply, brightness - 1);
+}
+
+
+static void regulator_led_enable(struct regulator_led *led)
+{
+       int ret;
+
+       if (led->enabled)
+               return;
+
+       ret = regulator_enable(led->vcc);
+       if (ret != 0) {
+               dev_err(led->cdev.dev, "Failed to enable vcc: %d\n", ret);
+               return;
+       }
+
+       led->enabled = 1;
+}
+
+static void regulator_led_disable(struct regulator_led *led)
+{
+       int ret;
+
+       if (!led->enabled)
+               return;
+
+       ret = regulator_disable(led->vcc);
+       if (ret != 0) {
+               dev_err(led->cdev.dev, "Failed to disable vcc: %d\n", ret);
+               return;
+       }
+
+       led->enabled = 0;
+}
+
+static void regulator_led_set_value(struct regulator_led *led)
+{
+       int voltage;
+       int ret;
+
+       mutex_lock(&led->mutex);
+
+       if (led->value == LED_OFF) {
+               regulator_led_disable(led);
+               goto out;
+       }
+
+       if (led->cdev.max_brightness > 1) {
+               voltage = led_regulator_get_voltage(led->vcc, led->value);
+               dev_dbg(led->cdev.dev, "brightness: %d voltage: %d\n",
+                               led->value, voltage);
+
+               ret = regulator_set_voltage(led->vcc, voltage, voltage);
+               if (ret != 0)
+                       dev_err(led->cdev.dev, "Failed to set voltage %d: %d\n",
+                               voltage, ret);
+       }
+
+       regulator_led_enable(led);
+
+out:
+       mutex_unlock(&led->mutex);
+}
+
+static void led_work(struct work_struct *work)
+{
+       struct regulator_led *led;
+
+       led = container_of(work, struct regulator_led, work);
+       regulator_led_set_value(led);
+}
+
+static void regulator_led_brightness_set(struct led_classdev *led_cdev,
+                          enum led_brightness value)
+{
+       struct regulator_led *led = to_regulator_led(led_cdev);
+
+       led->value = value;
+       schedule_work(&led->work);
+}
+
+static int __devinit regulator_led_probe(struct platform_device *pdev)
+{
+       struct led_regulator_platform_data *pdata = pdev->dev.platform_data;
+       struct regulator_led *led;
+       struct regulator *vcc;
+       int ret = 0;
+
+       if (pdata == NULL) {
+               dev_err(&pdev->dev, "no platform data\n");
+               return -ENODEV;
+       }
+
+       vcc = regulator_get_exclusive(&pdev->dev, "vled");
+       if (IS_ERR(vcc)) {
+               dev_err(&pdev->dev, "Cannot get vcc for %s\n", pdata->name);
+               return PTR_ERR(vcc);
+       }
+
+       led = kzalloc(sizeof(*led), GFP_KERNEL);
+       if (led == NULL) {
+               ret = -ENOMEM;
+               goto err_vcc;
+       }
+
+       led->cdev.max_brightness = led_regulator_get_max_brightness(vcc);
+       if (pdata->brightness > led->cdev.max_brightness) {
+               dev_err(&pdev->dev, "Invalid default brightness %d\n",
+                               pdata->brightness);
+               ret = -EINVAL;
+               goto err_led;
+       }
+       led->value = pdata->brightness;
+
+       led->cdev.brightness_set = regulator_led_brightness_set;
+       led->cdev.name = pdata->name;
+       led->cdev.flags |= LED_CORE_SUSPENDRESUME;
+       led->vcc = vcc;
+
+       mutex_init(&led->mutex);
+       INIT_WORK(&led->work, led_work);
+
+       platform_set_drvdata(pdev, led);
+
+       ret = led_classdev_register(&pdev->dev, &led->cdev);
+       if (ret < 0) {
+               cancel_work_sync(&led->work);
+               goto err_led;
+       }
+
+       /* to expose the default value to userspace */
+       led->cdev.brightness = led->value;
+
+       /* Set the default led status */
+       regulator_led_set_value(led);
+
+       return 0;
+
+err_led:
+       kfree(led);
+err_vcc:
+       regulator_put(vcc);
+       return ret;
+}
+
+static int __devexit regulator_led_remove(struct platform_device *pdev)
+{
+       struct regulator_led *led = platform_get_drvdata(pdev);
+
+       led_classdev_unregister(&led->cdev);
+       cancel_work_sync(&led->work);
+       regulator_led_disable(led);
+       regulator_put(led->vcc);
+       kfree(led);
+       return 0;
+}
+
+static struct platform_driver regulator_led_driver = {
+       .driver = {
+                  .name  = "leds-regulator",
+                  .owner = THIS_MODULE,
+                  },
+       .probe  = regulator_led_probe,
+       .remove = __devexit_p(regulator_led_remove),
+};
+
+static int __init regulator_led_init(void)
+{
+       return platform_driver_register(&regulator_led_driver);
+}
+module_init(regulator_led_init);
+
+static void __exit regulator_led_exit(void)
+{
+       platform_driver_unregister(&regulator_led_driver);
+}
+module_exit(regulator_led_exit);
+
+MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>");
+MODULE_DESCRIPTION("Regulator driven LED driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:leds-regulator");
diff --git a/drivers/leds/leds-ss4200.c b/drivers/leds/leds-ss4200.c
new file mode 100644 (file)
index 0000000..97f0498
--- /dev/null
@@ -0,0 +1,556 @@
+/*
+ * SS4200-E Hardware API
+ * Copyright (c) 2009, Intel Corporation.
+ * Copyright IBM Corporation, 2009
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Author: Dave Hansen <dave@sr71.net>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/dmi.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+
+MODULE_AUTHOR("Rodney Girod <rgirod@confocus.com>, Dave Hansen <dave@sr71.net>");
+MODULE_DESCRIPTION("Intel NAS/Home Server ICH7 GPIO Driver");
+MODULE_LICENSE("GPL");
+
+/*
+ * ICH7 LPC/GPIO PCI Config register offsets
+ */
+#define PMBASE         0x040
+#define GPIO_BASE      0x048
+#define GPIO_CTRL      0x04c
+#define GPIO_EN                0x010
+
+/*
+ * The ICH7 GPIO register block is 64 bytes in size.
+ */
+#define ICH7_GPIO_SIZE 64
+
+/*
+ * Define register offsets within the ICH7 register block.
+ */
+#define GPIO_USE_SEL   0x000
+#define GP_IO_SEL      0x004
+#define GP_LVL         0x00c
+#define GPO_BLINK      0x018
+#define GPI_INV                0x030
+#define GPIO_USE_SEL2  0x034
+#define GP_IO_SEL2     0x038
+#define GP_LVL2                0x03c
+
+/*
+ * PCI ID of the Intel ICH7 LPC Device within which the GPIO block lives.
+ */
+static struct pci_device_id ich7_lpc_pci_id[] =
+{
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_30) },
+       { } /* NULL entry */
+};
+
+MODULE_DEVICE_TABLE(pci, ich7_lpc_pci_id);
+
+static int __init ss4200_led_dmi_callback(const struct dmi_system_id *id)
+{
+       pr_info("detected '%s'\n", id->ident);
+       return 1;
+}
+
+static unsigned int __initdata nodetect;
+module_param_named(nodetect, nodetect, bool, 0);
+MODULE_PARM_DESC(nodetect, "Skip DMI-based hardware detection");
+
+/*
+ * struct nas_led_whitelist - List of known good models
+ *
+ * Contains the known good models this driver is compatible with.
+ * When adding a new model try to be as strict as possible. This
+ * makes it possible to keep the false positives (the model is
+ * detected as working, but in reality it is not) as low as
+ * possible.
+ */
+static struct dmi_system_id __initdata nas_led_whitelist[] = {
+       {
+               .callback = ss4200_led_dmi_callback,
+               .ident = "Intel SS4200-E",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Intel"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "SS4200-E"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "1.00.00")
+               }
+       },
+};
+
+/*
+ * Base I/O address assigned to the Power Management register block
+ */
+static u32 g_pm_io_base;
+
+/*
+ * Base I/O address assigned to the ICH7 GPIO register block
+ */
+static u32 nas_gpio_io_base;
+
+/*
+ * When we successfully register a region, we are returned a resource.
+ * We use these to identify which regions we need to release on our way
+ * back out.
+ */
+static struct resource *gp_gpio_resource;
+
+struct nasgpio_led {
+       char *name;
+       u32 gpio_bit;
+       struct led_classdev led_cdev;
+};
+
+/*
+ * gpio_bit(s) are the ICH7 GPIO bit assignments
+ */
+static struct nasgpio_led nasgpio_leds[] = {
+       { .name = "hdd1:blue:sata",     .gpio_bit = 0 },
+       { .name = "hdd1:amber:sata",    .gpio_bit = 1 },
+       { .name = "hdd2:blue:sata",     .gpio_bit = 2 },
+       { .name = "hdd2:amber:sata",    .gpio_bit = 3 },
+       { .name = "hdd3:blue:sata",     .gpio_bit = 4 },
+       { .name = "hdd3:amber:sata",    .gpio_bit = 5 },
+       { .name = "hdd4:blue:sata",     .gpio_bit = 6 },
+       { .name = "hdd4:amber:sata",    .gpio_bit = 7 },
+       { .name = "power:blue:power",   .gpio_bit = 27},
+       { .name = "power:amber:power",  .gpio_bit = 28},
+};
+
+#define NAS_RECOVERY   0x00000400      /* GPIO10 */
+
+static struct nasgpio_led *
+led_classdev_to_nasgpio_led(struct led_classdev *led_cdev)
+{
+       return container_of(led_cdev, struct nasgpio_led, led_cdev);
+}
+
+static struct nasgpio_led *get_led_named(char *name)
+{
+       int i;
+       for (i = 0; i < ARRAY_SIZE(nasgpio_leds); i++) {
+               if (strcmp(nasgpio_leds[i].name, name))
+                       continue;
+               return &nasgpio_leds[i];
+       }
+       return NULL;
+}
+
+/*
+ * This protects access to the gpio ports.
+ */
+static DEFINE_SPINLOCK(nasgpio_gpio_lock);
+
+/*
+ * There are two gpio ports, one for blinking and the other
+ * for power.  @port tells us if we're doing blinking or
+ * power control.
+ *
+ * Caller must hold nasgpio_gpio_lock
+ */
+static void __nasgpio_led_set_attr(struct led_classdev *led_cdev,
+                                  u32 port, u32 value)
+{
+       struct nasgpio_led *led = led_classdev_to_nasgpio_led(led_cdev);
+       u32 gpio_out;
+
+       gpio_out = inl(nas_gpio_io_base + port);
+       if (value)
+               gpio_out |= (1<<led->gpio_bit);
+       else
+               gpio_out &= ~(1<<led->gpio_bit);
+
+       outl(gpio_out, nas_gpio_io_base + port);
+}
+
+static void nasgpio_led_set_attr(struct led_classdev *led_cdev,
+                                u32 port, u32 value)
+{
+       spin_lock(&nasgpio_gpio_lock);
+       __nasgpio_led_set_attr(led_cdev, port, value);
+       spin_unlock(&nasgpio_gpio_lock);
+}
+
+u32 nasgpio_led_get_attr(struct led_classdev *led_cdev, u32 port)
+{
+       struct nasgpio_led *led = led_classdev_to_nasgpio_led(led_cdev);
+       u32 gpio_in;
+
+       spin_lock(&nasgpio_gpio_lock);
+       gpio_in = inl(nas_gpio_io_base + port);
+       spin_unlock(&nasgpio_gpio_lock);
+       if (gpio_in & (1<<led->gpio_bit))
+               return 1;
+       return 0;
+}
+
+/*
+ * There is actual brightness control in the hardware,
+ * but it is via smbus commands and not implemented
+ * in this driver.
+ */
+static void nasgpio_led_set_brightness(struct led_classdev *led_cdev,
+                                      enum led_brightness brightness)
+{
+       u32 setting = 0;
+       if (brightness >= LED_HALF)
+               setting = 1;
+       /*
+        * Hold the lock across both operations.  This ensures
+        * consistency so that both the "turn off blinking"
+        * and "turn light off" operations complete as a set.
+        */
+       spin_lock(&nasgpio_gpio_lock);
+       /*
+        * LED class documentation asks that past blink state
+        * be disabled when brightness is turned to zero.
+        */
+       if (brightness == 0)
+               __nasgpio_led_set_attr(led_cdev, GPO_BLINK, 0);
+       __nasgpio_led_set_attr(led_cdev, GP_LVL, setting);
+       spin_unlock(&nasgpio_gpio_lock);
+}
+
+static int nasgpio_led_set_blink(struct led_classdev *led_cdev,
+                                unsigned long *delay_on,
+                                unsigned long *delay_off)
+{
+       u32 setting = 1;
+       if (!(*delay_on == 0 && *delay_off == 0) &&
+           !(*delay_on == 500 && *delay_off == 500))
+               return -EINVAL;
+       /*
+        * These are very approximate.
+        */
+       *delay_on = 500;
+       *delay_off = 500;
+
+       nasgpio_led_set_attr(led_cdev, GPO_BLINK, setting);
+
+       return 0;
+}
+
+
+/*
+ * Initialize the ICH7 GPIO registers for NAS usage.  The BIOS should have
+ * already taken care of this, but we will do so in a non destructive manner
+ * so that we have what we need whether the BIOS did it or not.
+ */
+static int __devinit ich7_gpio_init(struct device *dev)
+{
+       int i;
+       u32 config_data = 0;
+       u32 all_nas_led = 0;
+
+       for (i = 0; i < ARRAY_SIZE(nasgpio_leds); i++)
+               all_nas_led |= (1<<nasgpio_leds[i].gpio_bit);
+
+       spin_lock(&nasgpio_gpio_lock);
+       /*
+        * We need to enable all of the GPIO lines used by the NAS box,
+        * so we will read the current Use Selection and add our usage
+        * to it.  This should be benign with regard to the original
+        * BIOS configuration.
+        */
+       config_data = inl(nas_gpio_io_base + GPIO_USE_SEL);
+       dev_dbg(dev, ": Data read from GPIO_USE_SEL = 0x%08x\n", config_data);
+       config_data |= all_nas_led + NAS_RECOVERY;
+       outl(config_data, nas_gpio_io_base + GPIO_USE_SEL);
+       config_data = inl(nas_gpio_io_base + GPIO_USE_SEL);
+       dev_dbg(dev, ": GPIO_USE_SEL = 0x%08x\n\n", config_data);
+
+       /*
+        * The LED GPIO outputs need to be configured for output, so we
+        * will ensure that all LED lines are cleared for output and the
+        * RECOVERY line ready for input.  This too should be benign with
+        * regard to BIOS configuration.
+        */
+       config_data = inl(nas_gpio_io_base + GP_IO_SEL);
+       dev_dbg(dev, ": Data read from GP_IO_SEL = 0x%08x\n",
+                                       config_data);
+       config_data &= ~all_nas_led;
+       config_data |= NAS_RECOVERY;
+       outl(config_data, nas_gpio_io_base + GP_IO_SEL);
+       config_data = inl(nas_gpio_io_base + GP_IO_SEL);
+       dev_dbg(dev, ": GP_IO_SEL = 0x%08x\n", config_data);
+
+       /*
+        * In our final system, the BIOS will initialize the state of all
+        * of the LEDs.  For now, we turn them all off (or Low).
+        */
+       config_data = inl(nas_gpio_io_base + GP_LVL);
+       dev_dbg(dev, ": Data read from GP_LVL = 0x%08x\n", config_data);
+       /*
+        * In our final system, the BIOS will initialize the blink state of all
+        * of the LEDs.  For now, we turn blink off for all of them.
+        */
+       config_data = inl(nas_gpio_io_base + GPO_BLINK);
+       dev_dbg(dev, ": Data read from GPO_BLINK = 0x%08x\n", config_data);
+
+       /*
+        * At this moment, I am unsure if anything needs to happen with GPI_INV
+        */
+       config_data = inl(nas_gpio_io_base + GPI_INV);
+       dev_dbg(dev, ": Data read from GPI_INV = 0x%08x\n", config_data);
+
+       spin_unlock(&nasgpio_gpio_lock);
+       return 0;
+}
+
+static void ich7_lpc_cleanup(struct device *dev)
+{
+       /*
+        * If we were given exclusive use of the GPIO
+        * I/O Address range, we must return it.
+        */
+       if (gp_gpio_resource) {
+               dev_dbg(dev, ": Releasing GPIO I/O addresses\n");
+               release_region(nas_gpio_io_base, ICH7_GPIO_SIZE);
+               gp_gpio_resource = NULL;
+       }
+}
+
+/*
+ * The OS has determined that the LPC of the Intel ICH7 Southbridge is present
+ * so we can retrive the required operational information and prepare the GPIO.
+ */
+static struct pci_dev *nas_gpio_pci_dev;
+static int __devinit ich7_lpc_probe(struct pci_dev *dev,
+                                   const struct pci_device_id *id)
+{
+       int status;
+       u32 gc = 0;
+
+       status = pci_enable_device(dev);
+       if (status) {
+               dev_err(&dev->dev, "pci_enable_device failed\n");
+               return -EIO;
+       }
+
+       nas_gpio_pci_dev = dev;
+       status = pci_read_config_dword(dev, PMBASE, &g_pm_io_base);
+       if (status)
+               goto out;
+       g_pm_io_base &= 0x00000ff80;
+
+       status = pci_read_config_dword(dev, GPIO_CTRL, &gc);
+       if (!(GPIO_EN & gc)) {
+               status = -EEXIST;
+               dev_info(&dev->dev,
+                          "ERROR: The LPC GPIO Block has not been enabled.\n");
+               goto out;
+       }
+
+       status = pci_read_config_dword(dev, GPIO_BASE, &nas_gpio_io_base);
+       if (0 > status) {
+               dev_info(&dev->dev, "Unable to read GPIOBASE.\n");
+               goto out;
+       }
+       dev_dbg(&dev->dev, ": GPIOBASE = 0x%08x\n", nas_gpio_io_base);
+       nas_gpio_io_base &= 0x00000ffc0;
+
+       /*
+        * Insure that we have exclusive access to the GPIO I/O address range.
+        */
+       gp_gpio_resource = request_region(nas_gpio_io_base, ICH7_GPIO_SIZE,
+                                         KBUILD_MODNAME);
+       if (NULL == gp_gpio_resource) {
+               dev_info(&dev->dev,
+                        "ERROR Unable to register GPIO I/O addresses.\n");
+               status = -1;
+               goto out;
+       }
+
+       /*
+        * Initialize the GPIO for NAS/Home Server Use
+        */
+       ich7_gpio_init(&dev->dev);
+
+out:
+       if (status) {
+               ich7_lpc_cleanup(&dev->dev);
+               pci_disable_device(dev);
+       }
+       return status;
+}
+
+static void ich7_lpc_remove(struct pci_dev *dev)
+{
+       ich7_lpc_cleanup(&dev->dev);
+       pci_disable_device(dev);
+}
+
+/*
+ * pci_driver structure passed to the PCI modules
+ */
+static struct pci_driver nas_gpio_pci_driver = {
+       .name = KBUILD_MODNAME,
+       .id_table = ich7_lpc_pci_id,
+       .probe = ich7_lpc_probe,
+       .remove = ich7_lpc_remove,
+};
+
+static struct led_classdev *get_classdev_for_led_nr(int nr)
+{
+       struct nasgpio_led *nas_led = &nasgpio_leds[nr];
+       struct led_classdev *led = &nas_led->led_cdev;
+       return led;
+}
+
+
+static void set_power_light_amber_noblink(void)
+{
+       struct nasgpio_led *amber = get_led_named("power:amber:power");
+       struct nasgpio_led *blue = get_led_named("power:blue:power");
+
+       if (!amber || !blue)
+               return;
+       /*
+        * LED_OFF implies disabling future blinking
+        */
+       pr_debug("setting blue off and amber on\n");
+
+       nasgpio_led_set_brightness(&blue->led_cdev, LED_OFF);
+       nasgpio_led_set_brightness(&amber->led_cdev, LED_FULL);
+}
+
+static ssize_t nas_led_blink_show(struct device *dev,
+                                 struct device_attribute *attr, char *buf)
+{
+       struct led_classdev *led = dev_get_drvdata(dev);
+       int blinking = 0;
+       if (nasgpio_led_get_attr(led, GPO_BLINK))
+               blinking = 1;
+       return sprintf(buf, "%u\n", blinking);
+}
+
+static ssize_t nas_led_blink_store(struct device *dev,
+                                  struct device_attribute *attr,
+                                  const char *buf, size_t size)
+{
+       int ret;
+       struct led_classdev *led = dev_get_drvdata(dev);
+       unsigned long blink_state;
+
+       ret = strict_strtoul(buf, 10, &blink_state);
+       if (ret)
+               return ret;
+
+       nasgpio_led_set_attr(led, GPO_BLINK, blink_state);
+
+       return size;
+}
+
+static DEVICE_ATTR(blink, 0644, nas_led_blink_show, nas_led_blink_store);
+
+static int register_nasgpio_led(int led_nr)
+{
+       int ret;
+       struct nasgpio_led *nas_led = &nasgpio_leds[led_nr];
+       struct led_classdev *led = get_classdev_for_led_nr(led_nr);
+
+       led->name = nas_led->name;
+       led->brightness = LED_OFF;
+       if (nasgpio_led_get_attr(led, GP_LVL))
+               led->brightness = LED_FULL;
+       led->brightness_set = nasgpio_led_set_brightness;
+       led->blink_set = nasgpio_led_set_blink;
+       ret = led_classdev_register(&nas_gpio_pci_dev->dev, led);
+       if (ret)
+               return ret;
+       ret = device_create_file(led->dev, &dev_attr_blink);
+       if (ret)
+               led_classdev_unregister(led);
+       return ret;
+}
+
+static void unregister_nasgpio_led(int led_nr)
+{
+       struct led_classdev *led = get_classdev_for_led_nr(led_nr);
+       led_classdev_unregister(led);
+       device_remove_file(led->dev, &dev_attr_blink);
+}
+/*
+ * module load/initialization
+ */
+static int __init nas_gpio_init(void)
+{
+       int i;
+       int ret = 0;
+       int nr_devices = 0;
+
+       nr_devices = dmi_check_system(nas_led_whitelist);
+       if (nodetect) {
+               pr_info("skipping hardware autodetection\n");
+               pr_info("Please send 'dmidecode' output to dave@sr71.net\n");
+               nr_devices++;
+       }
+
+       if (nr_devices <= 0) {
+               pr_info("no LED devices found\n");
+               return -ENODEV;
+       }
+
+       pr_info("registering PCI driver\n");
+       ret = pci_register_driver(&nas_gpio_pci_driver);
+       if (ret)
+               return ret;
+       for (i = 0; i < ARRAY_SIZE(nasgpio_leds); i++) {
+               ret = register_nasgpio_led(i);
+               if (ret)
+                       goto out_err;
+       }
+       /*
+        * When the system powers on, the BIOS leaves the power
+        * light blue and blinking.  This will turn it solid
+        * amber once the driver is loaded.
+        */
+       set_power_light_amber_noblink();
+       return 0;
+out_err:
+       for (; i >= 0; i--)
+               unregister_nasgpio_led(i);
+       pci_unregister_driver(&nas_gpio_pci_driver);
+       return ret;
+}
+
+/*
+ * module unload
+ */
+static void __exit nas_gpio_exit(void)
+{
+       int i;
+       pr_info("Unregistering driver\n");
+       for (i = 0; i < ARRAY_SIZE(nasgpio_leds); i++)
+               unregister_nasgpio_led(i);
+       pci_unregister_driver(&nas_gpio_pci_driver);
+}
+
+module_init(nas_gpio_init);
+module_exit(nas_gpio_exit);
index 1a7a9fc50ea1019fc74965daf6de40fff65b0f47..e3551d20464fe8f56c9edecfd9babe8c496e1aec 100644 (file)
@@ -203,6 +203,7 @@ config CS5535_MFGPT
 
 config CS5535_MFGPT_DEFAULT_IRQ
        int
+       depends on CS5535_MFGPT
        default 7
        help
          MFGPTs on the CS5535 require an interrupt.  The selected IRQ
index cdb845b68ab5e37222048b47769014fa32186b8a..06b64085a355b3aed5198548b406ddcc79174a48 100644 (file)
@@ -516,7 +516,8 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
         * The number of functions on the card is encoded inside
         * the ocr.
         */
-       card->sdio_funcs = funcs = (ocr & 0x70000000) >> 28;
+       funcs = (ocr & 0x70000000) >> 28;
+       card->sdio_funcs = 0;
 
        /*
         * If needed, disconnect card detection pull-up resistor.
@@ -528,7 +529,7 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
        /*
         * Initialize (but don't add) all present functions.
         */
-       for (i = 0;i < funcs;i++) {
+       for (i = 0; i < funcs; i++, card->sdio_funcs++) {
                err = sdio_init_func(host->card, i + 1);
                if (err)
                        goto remove;
index d37464e296a507deb743182c3764714f83cdda9c..9e060c87e64db6775fc5aa7b8aa07033dae7e365 100644 (file)
@@ -248,12 +248,15 @@ int sdio_add_func(struct sdio_func *func)
 /*
  * Unregister a SDIO function with the driver model, and
  * (eventually) free it.
+ * This function can be called through error paths where sdio_add_func() was
+ * never executed (because a failure occurred at an earlier point).
  */
 void sdio_remove_func(struct sdio_func *func)
 {
-       if (sdio_func_present(func))
-               device_del(&func->dev);
+       if (!sdio_func_present(func))
+               return;
 
+       device_del(&func->dev);
        put_device(&func->dev);
 }
 
index 9d405b1817812407469f1cf2b778639237acd940..ce1d28884e2987a059f9cba3ead143d041fc9a57 100644 (file)
@@ -44,6 +44,19 @@ config MMC_SDHCI_IO_ACCESSORS
          This is silent Kconfig symbol that is selected by the drivers that
          need to overwrite SDHCI IO memory accessors.
 
+config MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
+       bool
+       select MMC_SDHCI_IO_ACCESSORS
+       help
+         This option is selected by drivers running on big endian hosts
+         and performing I/O to a SDHCI controller through a bus that
+         implements a hardware byte swapper using a 32-bit datum.
+         This endian mapping mode is called "data invariance" and
+         has the effect of scrambling the addresses and formats of data
+         accessed in sizes other than the datum size.
+
+         This is the case for the Freescale eSDHC and Nintendo Wii SDHCI.
+
 config MMC_SDHCI_PCI
        tristate "SDHCI support on PCI bus"
        depends on MMC_SDHCI && PCI
@@ -75,11 +88,29 @@ config MMC_RICOH_MMC
 config MMC_SDHCI_OF
        tristate "SDHCI support on OpenFirmware platforms"
        depends on MMC_SDHCI && PPC_OF
-       select MMC_SDHCI_IO_ACCESSORS
        help
          This selects the OF support for Secure Digital Host Controller
-         Interfaces. So far, only the Freescale eSDHC controller is known
-         to exist on OF platforms.
+         Interfaces.
+
+         If unsure, say N.
+
+config MMC_SDHCI_OF_ESDHC
+       bool "SDHCI OF support for the Freescale eSDHC controller"
+       depends on MMC_SDHCI_OF
+       select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
+       help
+         This selects the Freescale eSDHC controller support.
+
+         If unsure, say N.
+
+config MMC_SDHCI_OF_HLWD
+       bool "SDHCI OF support for the Nintendo Wii SDHCI controllers"
+       depends on MMC_SDHCI_OF
+       select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
+       help
+         This selects the Secure Digital Host Controller Interface (SDHCI)
+         found in the "Hollywood" chipset of the Nintendo Wii video game
+         console.
 
          If unsure, say N.
 
index ded4d8cdd9d7d371baf3ce225abbe197cedbe4b0..3d253dd4240fee2c7d8fbb42f631563af370fb36 100644 (file)
@@ -13,7 +13,6 @@ obj-$(CONFIG_MMC_MXC)         += mxcmmc.o
 obj-$(CONFIG_MMC_SDHCI)                += sdhci.o
 obj-$(CONFIG_MMC_SDHCI_PCI)    += sdhci-pci.o
 obj-$(CONFIG_MMC_RICOH_MMC)    += ricoh_mmc.o
-obj-$(CONFIG_MMC_SDHCI_OF)     += sdhci-of.o
 obj-$(CONFIG_MMC_SDHCI_PLTFM)  += sdhci-pltfm.o
 obj-$(CONFIG_MMC_SDHCI_S3C)    += sdhci-s3c.o
 obj-$(CONFIG_MMC_WBSD)         += wbsd.o
@@ -37,6 +36,11 @@ obj-$(CONFIG_MMC_CB710)      += cb710-mmc.o
 obj-$(CONFIG_MMC_VIA_SDMMC)    += via-sdmmc.o
 obj-$(CONFIG_SDH_BFIN)         += bfin_sdh.o
 
+obj-$(CONFIG_MMC_SDHCI_OF)     += sdhci-of.o
+sdhci-of-y                             := sdhci-of-core.o
+sdhci-of-$(CONFIG_MMC_SDHCI_OF_ESDHC)  += sdhci-of-esdhc.o
+sdhci-of-$(CONFIG_MMC_SDHCI_OF_HLWD)   += sdhci-of-hlwd.o
+
 ifeq ($(CONFIG_CB710_DEBUG),y)
        CFLAGS-cb710-mmc        += -DDEBUG
 endif
similarity index 58%
rename from drivers/mmc/host/sdhci-of.c
rename to drivers/mmc/host/sdhci-of-core.c
index 01ab916c2802dc90e21bc7aa7513c2d5c0fa2cb6..55e33135edb4dbc60b800e9207b7ae1b0e3b8139 100644 (file)
 #include <linux/of_platform.h>
 #include <linux/mmc/host.h>
 #include <asm/machdep.h>
+#include "sdhci-of.h"
 #include "sdhci.h"
 
-struct sdhci_of_data {
-       unsigned int quirks;
-       struct sdhci_ops ops;
-};
-
-struct sdhci_of_host {
-       unsigned int clock;
-       u16 xfer_mode_shadow;
-};
+#ifdef CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
 
 /*
- * Ops and quirks for the Freescale eSDHC controller.
+ * These accessors are designed for big endian hosts doing I/O to
+ * little endian controllers incorporating a 32-bit hardware byte swapper.
  */
 
-#define ESDHC_DMA_SYSCTL       0x40c
-#define ESDHC_DMA_SNOOP                0x00000040
-
-#define ESDHC_SYSTEM_CONTROL   0x2c
-#define ESDHC_CLOCK_MASK       0x0000fff0
-#define ESDHC_PREDIV_SHIFT     8
-#define ESDHC_DIVIDER_SHIFT    4
-#define ESDHC_CLOCK_PEREN      0x00000004
-#define ESDHC_CLOCK_HCKEN      0x00000002
-#define ESDHC_CLOCK_IPGEN      0x00000001
-
-#define ESDHC_HOST_CONTROL_RES 0x05
-
-static u32 esdhc_readl(struct sdhci_host *host, int reg)
+u32 sdhci_be32bs_readl(struct sdhci_host *host, int reg)
 {
        return in_be32(host->ioaddr + reg);
 }
 
-static u16 esdhc_readw(struct sdhci_host *host, int reg)
+u16 sdhci_be32bs_readw(struct sdhci_host *host, int reg)
 {
-       u16 ret;
-
-       if (unlikely(reg == SDHCI_HOST_VERSION))
-               ret = in_be16(host->ioaddr + reg);
-       else
-               ret = in_be16(host->ioaddr + (reg ^ 0x2));
-       return ret;
+       return in_be16(host->ioaddr + (reg ^ 0x2));
 }
 
-static u8 esdhc_readb(struct sdhci_host *host, int reg)
+u8 sdhci_be32bs_readb(struct sdhci_host *host, int reg)
 {
        return in_8(host->ioaddr + (reg ^ 0x3));
 }
 
-static void esdhc_writel(struct sdhci_host *host, u32 val, int reg)
+void sdhci_be32bs_writel(struct sdhci_host *host, u32 val, int reg)
 {
        out_be32(host->ioaddr + reg, val);
 }
 
-static void esdhc_writew(struct sdhci_host *host, u16 val, int reg)
+void sdhci_be32bs_writew(struct sdhci_host *host, u16 val, int reg)
 {
        struct sdhci_of_host *of_host = sdhci_priv(host);
        int base = reg & ~0x3;
@@ -92,106 +67,21 @@ static void esdhc_writew(struct sdhci_host *host, u16 val, int reg)
                of_host->xfer_mode_shadow = val;
                return;
        case SDHCI_COMMAND:
-               esdhc_writel(host, val << 16 | of_host->xfer_mode_shadow,
-                            SDHCI_TRANSFER_MODE);
+               sdhci_be32bs_writel(host, val << 16 | of_host->xfer_mode_shadow,
+                                   SDHCI_TRANSFER_MODE);
                return;
-       case SDHCI_BLOCK_SIZE:
-               /*
-                * Two last DMA bits are reserved, and first one is used for
-                * non-standard blksz of 4096 bytes that we don't support
-                * yet. So clear the DMA boundary bits.
-                */
-               val &= ~SDHCI_MAKE_BLKSZ(0x7, 0);
-               /* fall through */
        }
        clrsetbits_be32(host->ioaddr + base, 0xffff << shift, val << shift);
 }
 
-static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)
+void sdhci_be32bs_writeb(struct sdhci_host *host, u8 val, int reg)
 {
        int base = reg & ~0x3;
        int shift = (reg & 0x3) * 8;
 
-       /* Prevent SDHCI core from writing reserved bits (e.g. HISPD). */
-       if (reg == SDHCI_HOST_CONTROL)
-               val &= ~ESDHC_HOST_CONTROL_RES;
-
        clrsetbits_be32(host->ioaddr + base , 0xff << shift, val << shift);
 }
-
-static void esdhc_set_clock(struct sdhci_host *host, unsigned int clock)
-{
-       int pre_div = 2;
-       int div = 1;
-
-       clrbits32(host->ioaddr + ESDHC_SYSTEM_CONTROL, ESDHC_CLOCK_IPGEN |
-                 ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN | ESDHC_CLOCK_MASK);
-
-       if (clock == 0)
-               goto out;
-
-       while (host->max_clk / pre_div / 16 > clock && pre_div < 256)
-               pre_div *= 2;
-
-       while (host->max_clk / pre_div / div > clock && div < 16)
-               div++;
-
-       dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
-               clock, host->max_clk / pre_div / div);
-
-       pre_div >>= 1;
-       div--;
-
-       setbits32(host->ioaddr + ESDHC_SYSTEM_CONTROL, ESDHC_CLOCK_IPGEN |
-                 ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN |
-                 div << ESDHC_DIVIDER_SHIFT | pre_div << ESDHC_PREDIV_SHIFT);
-       mdelay(100);
-out:
-       host->clock = clock;
-}
-
-static int esdhc_enable_dma(struct sdhci_host *host)
-{
-       setbits32(host->ioaddr + ESDHC_DMA_SYSCTL, ESDHC_DMA_SNOOP);
-       return 0;
-}
-
-static unsigned int esdhc_get_max_clock(struct sdhci_host *host)
-{
-       struct sdhci_of_host *of_host = sdhci_priv(host);
-
-       return of_host->clock;
-}
-
-static unsigned int esdhc_get_min_clock(struct sdhci_host *host)
-{
-       struct sdhci_of_host *of_host = sdhci_priv(host);
-
-       return of_host->clock / 256 / 16;
-}
-
-static struct sdhci_of_data sdhci_esdhc = {
-       .quirks = SDHCI_QUIRK_FORCE_BLK_SZ_2048 |
-                 SDHCI_QUIRK_BROKEN_CARD_DETECTION |
-                 SDHCI_QUIRK_NO_BUSY_IRQ |
-                 SDHCI_QUIRK_NONSTANDARD_CLOCK |
-                 SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
-                 SDHCI_QUIRK_PIO_NEEDS_DELAY |
-                 SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET |
-                 SDHCI_QUIRK_NO_CARD_NO_RESET,
-       .ops = {
-               .readl = esdhc_readl,
-               .readw = esdhc_readw,
-               .readb = esdhc_readb,
-               .writel = esdhc_writel,
-               .writew = esdhc_writew,
-               .writeb = esdhc_writeb,
-               .set_clock = esdhc_set_clock,
-               .enable_dma = esdhc_enable_dma,
-               .get_max_clock = esdhc_get_max_clock,
-               .get_min_clock = esdhc_get_min_clock,
-       },
-};
+#endif /* CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER */
 
 #ifdef CONFIG_PM
 
@@ -301,9 +191,14 @@ static int __devexit sdhci_of_remove(struct of_device *ofdev)
 }
 
 static const struct of_device_id sdhci_of_match[] = {
+#ifdef CONFIG_MMC_SDHCI_OF_ESDHC
        { .compatible = "fsl,mpc8379-esdhc", .data = &sdhci_esdhc, },
        { .compatible = "fsl,mpc8536-esdhc", .data = &sdhci_esdhc, },
        { .compatible = "fsl,esdhc", .data = &sdhci_esdhc, },
+#endif
+#ifdef CONFIG_MMC_SDHCI_OF_HLWD
+       { .compatible = "nintendo,hollywood-sdhci", .data = &sdhci_hlwd, },
+#endif
        { .compatible = "generic-sdhci", },
        {},
 };
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
new file mode 100644 (file)
index 0000000..d5b11a1
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Freescale eSDHC controller driver.
+ *
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ * Copyright (c) 2009 MontaVista Software, Inc.
+ *
+ * Authors: Xiaobo Xie <X.Xie@freescale.com>
+ *         Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/mmc/host.h>
+#include "sdhci-of.h"
+#include "sdhci.h"
+
+/*
+ * Ops and quirks for the Freescale eSDHC controller.
+ */
+
+#define ESDHC_DMA_SYSCTL       0x40c
+#define ESDHC_DMA_SNOOP                0x00000040
+
+#define ESDHC_SYSTEM_CONTROL   0x2c
+#define ESDHC_CLOCK_MASK       0x0000fff0
+#define ESDHC_PREDIV_SHIFT     8
+#define ESDHC_DIVIDER_SHIFT    4
+#define ESDHC_CLOCK_PEREN      0x00000004
+#define ESDHC_CLOCK_HCKEN      0x00000002
+#define ESDHC_CLOCK_IPGEN      0x00000001
+
+#define ESDHC_HOST_CONTROL_RES 0x05
+
+static u16 esdhc_readw(struct sdhci_host *host, int reg)
+{
+       u16 ret;
+
+       if (unlikely(reg == SDHCI_HOST_VERSION))
+               ret = in_be16(host->ioaddr + reg);
+       else
+               ret = sdhci_be32bs_readw(host, reg);
+       return ret;
+}
+
+static void esdhc_writew(struct sdhci_host *host, u16 val, int reg)
+{
+       if (reg == SDHCI_BLOCK_SIZE) {
+               /*
+                * Two last DMA bits are reserved, and first one is used for
+                * non-standard blksz of 4096 bytes that we don't support
+                * yet. So clear the DMA boundary bits.
+                */
+               val &= ~SDHCI_MAKE_BLKSZ(0x7, 0);
+       }
+       sdhci_be32bs_writew(host, val, reg);
+}
+
+static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)
+{
+       /* Prevent SDHCI core from writing reserved bits (e.g. HISPD). */
+       if (reg == SDHCI_HOST_CONTROL)
+               val &= ~ESDHC_HOST_CONTROL_RES;
+       sdhci_be32bs_writeb(host, val, reg);
+}
+
+static void esdhc_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+       int pre_div = 2;
+       int div = 1;
+
+       clrbits32(host->ioaddr + ESDHC_SYSTEM_CONTROL, ESDHC_CLOCK_IPGEN |
+                 ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN | ESDHC_CLOCK_MASK);
+
+       if (clock == 0)
+               goto out;
+
+       while (host->max_clk / pre_div / 16 > clock && pre_div < 256)
+               pre_div *= 2;
+
+       while (host->max_clk / pre_div / div > clock && div < 16)
+               div++;
+
+       dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
+               clock, host->max_clk / pre_div / div);
+
+       pre_div >>= 1;
+       div--;
+
+       setbits32(host->ioaddr + ESDHC_SYSTEM_CONTROL, ESDHC_CLOCK_IPGEN |
+                 ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN |
+                 div << ESDHC_DIVIDER_SHIFT | pre_div << ESDHC_PREDIV_SHIFT);
+       mdelay(100);
+out:
+       host->clock = clock;
+}
+
+static int esdhc_enable_dma(struct sdhci_host *host)
+{
+       setbits32(host->ioaddr + ESDHC_DMA_SYSCTL, ESDHC_DMA_SNOOP);
+       return 0;
+}
+
+static unsigned int esdhc_get_max_clock(struct sdhci_host *host)
+{
+       struct sdhci_of_host *of_host = sdhci_priv(host);
+
+       return of_host->clock;
+}
+
+static unsigned int esdhc_get_min_clock(struct sdhci_host *host)
+{
+       struct sdhci_of_host *of_host = sdhci_priv(host);
+
+       return of_host->clock / 256 / 16;
+}
+
+struct sdhci_of_data sdhci_esdhc = {
+       .quirks = SDHCI_QUIRK_FORCE_BLK_SZ_2048 |
+                 SDHCI_QUIRK_BROKEN_CARD_DETECTION |
+                 SDHCI_QUIRK_NO_BUSY_IRQ |
+                 SDHCI_QUIRK_NONSTANDARD_CLOCK |
+                 SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
+                 SDHCI_QUIRK_PIO_NEEDS_DELAY |
+                 SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET |
+                 SDHCI_QUIRK_NO_CARD_NO_RESET,
+       .ops = {
+               .readl = sdhci_be32bs_readl,
+               .readw = esdhc_readw,
+               .readb = sdhci_be32bs_readb,
+               .writel = sdhci_be32bs_writel,
+               .writew = esdhc_writew,
+               .writeb = esdhc_writeb,
+               .set_clock = esdhc_set_clock,
+               .enable_dma = esdhc_enable_dma,
+               .get_max_clock = esdhc_get_max_clock,
+               .get_min_clock = esdhc_get_min_clock,
+       },
+};
diff --git a/drivers/mmc/host/sdhci-of-hlwd.c b/drivers/mmc/host/sdhci-of-hlwd.c
new file mode 100644 (file)
index 0000000..35117f3
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * drivers/mmc/host/sdhci-of-hlwd.c
+ *
+ * Nintendo Wii Secure Digital Host Controller Interface.
+ * Copyright (C) 2009 The GameCube Linux Team
+ * Copyright (C) 2009 Albert Herranz
+ *
+ * Based on sdhci-of-esdhc.c
+ *
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ * Copyright (c) 2009 MontaVista Software, Inc.
+ *
+ * Authors: Xiaobo Xie <X.Xie@freescale.com>
+ *         Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/delay.h>
+#include <linux/mmc/host.h>
+#include "sdhci-of.h"
+#include "sdhci.h"
+
+/*
+ * Ops and quirks for the Nintendo Wii SDHCI controllers.
+ */
+
+/*
+ * We need a small delay after each write, or things go horribly wrong.
+ */
+#define SDHCI_HLWD_WRITE_DELAY 5 /* usecs */
+
+static void sdhci_hlwd_writel(struct sdhci_host *host, u32 val, int reg)
+{
+       sdhci_be32bs_writel(host, val, reg);
+       udelay(SDHCI_HLWD_WRITE_DELAY);
+}
+
+static void sdhci_hlwd_writew(struct sdhci_host *host, u16 val, int reg)
+{
+       sdhci_be32bs_writew(host, val, reg);
+       udelay(SDHCI_HLWD_WRITE_DELAY);
+}
+
+static void sdhci_hlwd_writeb(struct sdhci_host *host, u8 val, int reg)
+{
+       sdhci_be32bs_writeb(host, val, reg);
+       udelay(SDHCI_HLWD_WRITE_DELAY);
+}
+
+struct sdhci_of_data sdhci_hlwd = {
+       .quirks = SDHCI_QUIRK_32BIT_DMA_ADDR |
+                 SDHCI_QUIRK_32BIT_DMA_SIZE,
+       .ops = {
+               .readl = sdhci_be32bs_readl,
+               .readw = sdhci_be32bs_readw,
+               .readb = sdhci_be32bs_readb,
+               .writel = sdhci_hlwd_writel,
+               .writew = sdhci_hlwd_writew,
+               .writeb = sdhci_hlwd_writeb,
+       },
+};
diff --git a/drivers/mmc/host/sdhci-of.h b/drivers/mmc/host/sdhci-of.h
new file mode 100644 (file)
index 0000000..ad09ad9
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * OpenFirmware bindings for Secure Digital Host Controller Interface.
+ *
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ * Copyright (c) 2009 MontaVista Software, Inc.
+ *
+ * Authors: Xiaobo Xie <X.Xie@freescale.com>
+ *         Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#ifndef __SDHCI_OF_H
+#define __SDHCI_OF_H
+
+#include <linux/types.h>
+#include "sdhci.h"
+
+struct sdhci_of_data {
+       unsigned int quirks;
+       struct sdhci_ops ops;
+};
+
+struct sdhci_of_host {
+       unsigned int clock;
+       u16 xfer_mode_shadow;
+};
+
+extern u32 sdhci_be32bs_readl(struct sdhci_host *host, int reg);
+extern u16 sdhci_be32bs_readw(struct sdhci_host *host, int reg);
+extern u8 sdhci_be32bs_readb(struct sdhci_host *host, int reg);
+extern void sdhci_be32bs_writel(struct sdhci_host *host, u32 val, int reg);
+extern void sdhci_be32bs_writew(struct sdhci_host *host, u16 val, int reg);
+extern void sdhci_be32bs_writeb(struct sdhci_host *host, u8 val, int reg);
+
+extern struct sdhci_of_data sdhci_esdhc;
+extern struct sdhci_of_data sdhci_hlwd;
+
+#endif /* __SDHCI_OF_H */
index ce5f1d73dc04667841c6da99973500e9e3c96e7f..842f46f9428469657679e45c1b5b1dc8097c694f 100644 (file)
@@ -8,6 +8,8 @@
  * the Free Software Foundation; either version 2 of the License, or (at
  * your option) any later version.
  */
+#ifndef __SDHCI_H
+#define __SDHCI_H
 
 #include <linux/scatterlist.h>
 #include <linux/compiler.h>
@@ -408,3 +410,5 @@ extern void sdhci_remove_host(struct sdhci_host *host, int dead);
 extern int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state);
 extern int sdhci_resume_host(struct sdhci_host *host);
 #endif
+
+#endif /* __SDHCI_H */
index 74fa075c838a52209c2c6db29d49df1a7e00f7bc..b13f6417b5b262a81b149713184fe4de9364bea9 100644 (file)
 
 #include <asm/io.h>
 #include <mach/hardware.h>
-#include <asm/cacheflush.h>
 
 #include <asm/mach/flash.h>
 
+#define CACHELINESIZE  32
+
 static void pxa2xx_map_inval_cache(struct map_info *map, unsigned long from,
                                      ssize_t len)
 {
-       flush_ioremap_region(map->phys, map->cached, from, len);
+       unsigned long start = (unsigned long)map->cached + from;
+       unsigned long end = start + len;
+
+       start &= ~(CACHELINESIZE - 1);
+       while (start < end) {
+               /* invalidate D cache line */
+               asm volatile ("mcr p15, 0, %0, c7, c6, 1" : : "r" (start));
+               start += CACHELINESIZE;
+       }
 }
 
 struct pxa2xx_flash_info {
index 675b7df632fc1a1076f9b16862bb5bac2652b964..27ca859e7453c250ca70aea6d64ce9820ae6f98d 100644 (file)
@@ -63,7 +63,7 @@
 #ifndef __iwl_core_h__
 #define __iwl_core_h__
 
-#include <linux/utsrelease.h>
+#include <generated/utsrelease.h>
 
 /************************
  * forward declarations *
index 3aabf1e379888e7bf4c025d5d779862132efa007..76e640bccde848c258799b2d4b245e73a17e37bb 100644 (file)
@@ -291,7 +291,7 @@ static int pxa2xx_drv_pcmcia_probe(struct platform_device *dev)
                skt->nr = ops->first + i;
                skt->ops = ops;
                skt->socket.owner = ops->owner;
-               skt->socket.dev.parent = dev;
+               skt->socket.dev.parent = &dev->dev;
                skt->socket.pci_irq = NO_IRQ;
 
                ret = pxa2xx_drv_pcmcia_add_one(skt);
@@ -304,8 +304,8 @@ static int pxa2xx_drv_pcmcia_probe(struct platform_device *dev)
                        soc_pcmcia_remove_one(&sinfo->skt[i]);
                kfree(sinfo);
        } else {
-               pxa2xx_configure_sockets(dev);
-               dev_set_drvdata(dev, sinfo);
+               pxa2xx_configure_sockets(&dev->dev);
+               dev_set_drvdata(&dev->dev, sinfo);
        }
 
        return ret;
index 11003bba10d3e495cee585b83d49dc27f5b4ee80..1a387e79f71945ac92b6536643ec83ec8398be3e 100644 (file)
@@ -51,7 +51,6 @@
 #include <linux/dmi.h>
 #include <linux/backlight.h>
 #include <linux/platform_device.h>
-#include <linux/autoconf.h>
 
 #define COMPAL_DRIVER_VERSION "0.2.6"
 
diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c
new file mode 100644 (file)
index 0000000..0471955
--- /dev/null
@@ -0,0 +1,685 @@
+/*
+ * Regulators driver for Marvell 88PM8607
+ *
+ * Copyright (C) 2009 Marvell International Ltd.
+ *     Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/88pm8607.h>
+
+struct pm8607_regulator_info {
+       struct regulator_desc   desc;
+       struct pm8607_chip      *chip;
+       struct regulator_dev    *regulator;
+
+       int     min_uV;
+       int     max_uV;
+       int     step_uV;
+       int     vol_reg;
+       int     vol_shift;
+       int     vol_nbits;
+       int     update_reg;
+       int     update_bit;
+       int     enable_reg;
+       int     enable_bit;
+       int     slope_double;
+};
+
+static inline int check_range(struct pm8607_regulator_info *info,
+                               int min_uV, int max_uV)
+{
+       if (max_uV < info->min_uV || min_uV > info->max_uV || min_uV > max_uV)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index)
+{
+       struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
+       uint8_t chip_id = info->chip->chip_id;
+       int ret = -EINVAL;
+
+       switch (info->desc.id) {
+       case PM8607_ID_BUCK1:
+               ret = (index < 0x1d) ? (index * 25000 + 800000) :
+                       ((index < 0x20) ? 1500000 :
+                       ((index < 0x40) ? ((index - 0x20) * 25000) :
+                       -EINVAL));
+               break;
+       case PM8607_ID_BUCK3:
+               ret = (index < 0x3d) ? (index * 25000) :
+                       ((index < 0x40) ? 1500000 : -EINVAL);
+               if (ret < 0)
+                       break;
+               if (info->slope_double)
+                       ret <<= 1;
+               break;
+       case PM8607_ID_LDO1:
+               ret = (index == 0) ? 1800000 :
+                       ((index == 1) ? 1200000 :
+                       ((index == 2) ? 2800000 : -EINVAL));
+               break;
+       case PM8607_ID_LDO5:
+               ret = (index == 0) ? 2900000 :
+                       ((index == 1) ? 3000000 :
+                       ((index == 2) ? 3100000 : 3300000));
+               break;
+       case PM8607_ID_LDO7:
+       case PM8607_ID_LDO8:
+               ret = (index < 3) ? (index * 50000 + 1800000) :
+                       ((index < 8) ? (index * 50000 + 2550000) :
+                        -EINVAL);
+               break;
+       case PM8607_ID_LDO12:
+               ret = (index < 2) ? (index * 100000 + 1800000) :
+                       ((index < 7) ? (index * 100000 + 2500000) :
+                       ((index == 7) ? 3300000 : 1200000));
+               break;
+       case PM8607_ID_LDO2:
+       case PM8607_ID_LDO3:
+       case PM8607_ID_LDO9:
+               switch (chip_id) {
+               case PM8607_CHIP_A0:
+               case PM8607_CHIP_A1:
+                       ret = (index < 3) ? (index * 50000 + 1800000) :
+                               ((index < 8) ? (index * 50000 + 2550000) :
+                                -EINVAL);
+                       break;
+               case PM8607_CHIP_B0:
+                       ret = (index < 3) ? (index * 50000 + 1800000) :
+                               ((index < 7) ? (index * 50000 + 2550000) :
+                               3300000);
+                       break;
+               }
+               break;
+       case PM8607_ID_LDO4:
+               switch (chip_id) {
+               case PM8607_CHIP_A0:
+               case PM8607_CHIP_A1:
+                       ret = (index < 3) ? (index * 50000 + 1800000) :
+                               ((index < 8) ? (index * 50000 + 2550000) :
+                                -EINVAL);
+                       break;
+               case PM8607_CHIP_B0:
+                       ret = (index < 3) ? (index * 50000 + 1800000) :
+                               ((index < 6) ? (index * 50000 + 2550000) :
+                               ((index == 6) ? 2900000 : 3300000));
+                       break;
+               }
+               break;
+       case PM8607_ID_LDO6:
+               switch (chip_id) {
+               case PM8607_CHIP_A0:
+               case PM8607_CHIP_A1:
+                       ret = (index < 3) ? (index * 50000 + 1800000) :
+                               ((index < 8) ? (index * 50000 + 2450000) :
+                               -EINVAL);
+                       break;
+               case PM8607_CHIP_B0:
+                       ret = (index < 2) ? (index * 50000 + 1800000) :
+                               ((index < 7) ? (index * 50000 + 2500000) :
+                               3300000);
+                       break;
+               }
+               break;
+       case PM8607_ID_LDO10:
+               switch (chip_id) {
+               case PM8607_CHIP_A0:
+               case PM8607_CHIP_A1:
+                       ret = (index < 3) ? (index * 50000 + 1800000) :
+                               ((index < 8) ? (index * 50000 + 2550000) :
+                               1200000);
+                       break;
+               case PM8607_CHIP_B0:
+                       ret = (index < 3) ? (index * 50000 + 1800000) :
+                               ((index < 7) ? (index * 50000 + 2550000) :
+                               ((index == 7) ? 3300000 : 1200000));
+                       break;
+               }
+               break;
+       case PM8607_ID_LDO14:
+               switch (chip_id) {
+               case PM8607_CHIP_A0:
+               case PM8607_CHIP_A1:
+                       ret = (index < 3) ? (index * 50000 + 1800000) :
+                               ((index < 8) ? (index * 50000 + 2550000) :
+                                -EINVAL);
+                       break;
+               case PM8607_CHIP_B0:
+                       ret = (index < 2) ? (index * 50000 + 1800000) :
+                               ((index < 7) ? (index * 50000 + 2600000) :
+                               3300000);
+                       break;
+               }
+               break;
+       }
+       return ret;
+}
+
+static int choose_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
+{
+       struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
+       uint8_t chip_id = info->chip->chip_id;
+       int val = -ENOENT;
+       int ret;
+
+       switch (info->desc.id) {
+       case PM8607_ID_BUCK1:
+               if (min_uV >= 800000)           /* 800mV ~ 1500mV / 25mV */
+                       val = (min_uV - 775001) / 25000;
+               else {                          /* 25mV ~ 775mV / 25mV */
+                       val = (min_uV + 249999) / 25000;
+                       val += 32;
+               }
+               break;
+       case PM8607_ID_BUCK3:
+               if (info->slope_double)
+                       min_uV = min_uV >> 1;
+               val = (min_uV + 249999) / 25000; /* 0mV ~ 1500mV / 25mV */
+
+               break;
+       case PM8607_ID_LDO1:
+               if (min_uV > 1800000)
+                       val = 2;
+               else if (min_uV > 1200000)
+                       val = 0;
+               else
+                       val = 1;
+               break;
+       case PM8607_ID_LDO5:
+               if (min_uV > 3100000)
+                       val = 3;
+               else                            /* 2900mV ~ 3100mV / 100mV */
+                       val = (min_uV - 2800001) / 100000;
+               break;
+       case PM8607_ID_LDO7:
+       case PM8607_ID_LDO8:
+               if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */
+                       if (min_uV <= 1800000)
+                               val = 0;        /* 1800mv */
+                       else if (min_uV <= 1900000)
+                               val = (min_uV - 1750001) / 50000;
+                       else
+                               val = 3;        /* 2700mV */
+               } else {                 /* 2700mV ~ 2900mV / 50mV */
+                       if (min_uV <= 2900000) {
+                               val = (min_uV - 2650001) / 50000;
+                               val += 3;
+                       } else
+                               val = -EINVAL;
+               }
+               break;
+       case PM8607_ID_LDO10:
+               if (min_uV > 2850000)
+                       val = 7;
+               else if (min_uV <= 1200000)
+                       val = 8;
+               else if (min_uV < 2700000)      /* 1800mV ~ 1900mV / 50mV */
+                       val = (min_uV - 1750001) / 50000;
+               else {                          /* 2700mV ~ 2850mV / 50mV */
+                       val = (min_uV - 2650001) / 50000;
+                       val += 3;
+               }
+               break;
+       case PM8607_ID_LDO12:
+               if (min_uV < 2700000) {         /* 1800mV ~ 1900mV / 100mV */
+                       if (min_uV <= 1200000)
+                               val = 8;        /* 1200mV */
+                       else if (min_uV <= 1800000)
+                               val = 0;        /* 1800mV */
+                       else if (min_uV <= 1900000)
+                               val = (min_uV - 1700001) / 100000;
+                       else
+                               val = 2;        /* 2700mV */
+               } else {                        /* 2700mV ~ 3100mV / 100mV */
+                       if (min_uV <= 3100000) {
+                               val = (min_uV - 2600001) / 100000;
+                               val += 2;
+                       } else if (min_uV <= 3300000)
+                               val = 7;
+                       else
+                               val = -EINVAL;
+               }
+               break;
+       case PM8607_ID_LDO2:
+       case PM8607_ID_LDO3:
+       case PM8607_ID_LDO9:
+               switch (chip_id) {
+               case PM8607_CHIP_A0:
+               case PM8607_CHIP_A1:
+                       if (min_uV < 2700000)   /* 1800mV ~ 1900mV / 50mV */
+                               if (min_uV <= 1800000)
+                                       val = 0;
+                               else if (min_uV <= 1900000)
+                                       val = (min_uV - 1750001) / 50000;
+                               else
+                                       val = 3;        /* 2700mV */
+                       else {                  /* 2700mV ~ 2900mV / 50mV */
+                               if (min_uV <= 2900000) {
+                                       val = (min_uV - 2650001) / 50000;
+                                       val += 3;
+                               } else
+                                       val = -EINVAL;
+                       }
+                       break;
+               case PM8607_CHIP_B0:
+                       if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */
+                               if (min_uV <= 1800000)
+                                       val = 0;
+                               else if (min_uV <= 1900000)
+                                       val = (min_uV - 1750001) / 50000;
+                               else
+                                       val = 3;        /* 2700mV */
+                       } else {                 /* 2700mV ~ 2850mV / 50mV */
+                               if (min_uV <= 2850000) {
+                                       val = (min_uV - 2650001) / 50000;
+                                       val += 3;
+                               } else if (min_uV <= 3300000)
+                                       val = 7;
+                               else
+                                       val = -EINVAL;
+                       }
+                       break;
+               }
+               break;
+       case PM8607_ID_LDO4:
+               switch (chip_id) {
+               case PM8607_CHIP_A0:
+               case PM8607_CHIP_A1:
+                       if (min_uV < 2700000)   /* 1800mV ~ 1900mV / 50mV */
+                               if (min_uV <= 1800000)
+                                       val = 0;
+                               else if (min_uV <= 1900000)
+                                       val = (min_uV - 1750001) / 50000;
+                               else
+                                       val = 3;        /* 2700mV */
+                       else {                  /* 2700mV ~ 2900mV / 50mV */
+                               if (min_uV <= 2900000) {
+                                       val = (min_uV - 2650001) / 50000;
+                                       val += 3;
+                               } else
+                                       val = -EINVAL;
+                       }
+                       break;
+               case PM8607_CHIP_B0:
+                       if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */
+                               if (min_uV <= 1800000)
+                                       val = 0;
+                               else if (min_uV <= 1900000)
+                                       val = (min_uV - 1750001) / 50000;
+                               else
+                                       val = 3;        /* 2700mV */
+                       } else {                 /* 2700mV ~ 2800mV / 50mV */
+                               if (min_uV <= 2850000) {
+                                       val = (min_uV - 2650001) / 50000;
+                                       val += 3;
+                               } else if (min_uV <= 2900000)
+                                       val = 6;
+                               else if (min_uV <= 3300000)
+                                       val = 7;
+                               else
+                                       val = -EINVAL;
+                       }
+                       break;
+               }
+               break;
+       case PM8607_ID_LDO6:
+               switch (chip_id) {
+               case PM8607_CHIP_A0:
+               case PM8607_CHIP_A1:
+                       if (min_uV < 2600000) { /* 1800mV ~ 1900mV / 50mV */
+                               if (min_uV <= 1800000)
+                                       val = 0;
+                               else if (min_uV <= 1900000)
+                                       val = (min_uV - 1750001) / 50000;
+                               else
+                                       val = 3;        /* 2600mV */
+                       } else {                /* 2600mV ~ 2800mV / 50mV */
+                               if (min_uV <= 2800000) {
+                                       val = (min_uV - 2550001) / 50000;
+                                       val += 3;
+                               } else
+                                       val = -EINVAL;
+                       }
+                       break;
+               case PM8607_CHIP_B0:
+                       if (min_uV < 2600000) { /* 1800mV ~ 1850mV / 50mV */
+                               if (min_uV <= 1800000)
+                                       val = 0;
+                               else if (min_uV <= 1850000)
+                                       val = (min_uV - 1750001) / 50000;
+                               else
+                                       val = 2;        /* 2600mV */
+                       } else {                /* 2600mV ~ 2800mV / 50mV */
+                               if (min_uV <= 2800000) {
+                                       val = (min_uV - 2550001) / 50000;
+                                       val += 2;
+                               } else if (min_uV <= 3300000)
+                                       val = 7;
+                               else
+                                       val = -EINVAL;
+                       }
+                       break;
+               }
+               break;
+       case PM8607_ID_LDO14:
+               switch (chip_id) {
+               case PM8607_CHIP_A0:
+               case PM8607_CHIP_A1:
+                       if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */
+                               if (min_uV <= 1800000)
+                                       val = 0;
+                               else if (min_uV <= 1900000)
+                                       val = (min_uV - 1750001) / 50000;
+                               else
+                                       val = 3;        /* 2700mV */
+                       } else {                 /* 2700mV ~ 2900mV / 50mV */
+                               if (min_uV <= 2900000) {
+                                       val = (min_uV - 2650001) / 50000;
+                                       val += 3;
+                               } else
+                                       val = -EINVAL;
+                       }
+                       break;
+               case PM8607_CHIP_B0:
+                       if (min_uV < 2700000) { /* 1800mV ~ 1850mV / 50mV */
+                               if (min_uV <= 1800000)
+                                       val = 0;
+                               else if (min_uV <= 1850000)
+                                       val = (min_uV - 1750001) / 50000;
+                               else
+                                       val = 2;        /* 2700mV */
+                       } else {                 /* 2700mV ~ 2900mV / 50mV */
+                               if (min_uV <= 2900000) {
+                                       val = (min_uV - 2650001) / 50000;
+                                       val += 2;
+                               } else if (min_uV <= 3300000)
+                                       val = 7;
+                               else
+                                       val = -EINVAL;
+                       }
+                       break;
+               }
+               break;
+       }
+       if (val >= 0) {
+               ret = pm8607_list_voltage(rdev, val);
+               if (ret > max_uV) {
+                       pr_err("exceed voltage range (%d %d) uV",
+                               min_uV, max_uV);
+                       return -EINVAL;
+               }
+       } else
+               pr_err("invalid voltage range (%d %d) uV", min_uV, max_uV);
+       return val;
+}
+
+static int pm8607_set_voltage(struct regulator_dev *rdev,
+                             int min_uV, int max_uV)
+{
+       struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
+       struct pm8607_chip *chip = info->chip;
+       uint8_t val, mask;
+       int ret;
+
+       if (check_range(info, min_uV, max_uV)) {
+               pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV);
+               return -EINVAL;
+       }
+
+       ret = choose_voltage(rdev, min_uV, max_uV);
+       if (ret < 0)
+               return -EINVAL;
+       val = (uint8_t)(ret << info->vol_shift);
+       mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
+
+       ret = pm8607_set_bits(chip, info->vol_reg, mask, val);
+       if (ret)
+               return ret;
+       switch (info->desc.id) {
+       case PM8607_ID_BUCK1:
+       case PM8607_ID_BUCK3:
+               ret = pm8607_set_bits(chip, info->update_reg,
+                                     1 << info->update_bit,
+                                     1 << info->update_bit);
+               break;
+       }
+       return ret;
+}
+
+static int pm8607_get_voltage(struct regulator_dev *rdev)
+{
+       struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
+       struct pm8607_chip *chip = info->chip;
+       uint8_t val, mask;
+       int ret;
+
+       ret = pm8607_reg_read(chip, info->vol_reg);
+       if (ret < 0)
+               return ret;
+
+       mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
+       val = ((unsigned char)ret & mask) >> info->vol_shift;
+
+       return pm8607_list_voltage(rdev, val);
+}
+
+static int pm8607_enable(struct regulator_dev *rdev)
+{
+       struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
+       struct pm8607_chip *chip = info->chip;
+
+       return pm8607_set_bits(chip, info->enable_reg,
+                              1 << info->enable_bit,
+                              1 << info->enable_bit);
+}
+
+static int pm8607_disable(struct regulator_dev *rdev)
+{
+       struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
+       struct pm8607_chip *chip = info->chip;
+
+       return pm8607_set_bits(chip, info->enable_reg,
+                              1 << info->enable_bit, 0);
+}
+
+static int pm8607_is_enabled(struct regulator_dev *rdev)
+{
+       struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
+       struct pm8607_chip *chip = info->chip;
+       int ret;
+
+       ret = pm8607_reg_read(chip, info->enable_reg);
+       if (ret < 0)
+               return ret;
+
+       return !!((unsigned char)ret & (1 << info->enable_bit));
+}
+
+static struct regulator_ops pm8607_regulator_ops = {
+       .set_voltage    = pm8607_set_voltage,
+       .get_voltage    = pm8607_get_voltage,
+       .enable         = pm8607_enable,
+       .disable        = pm8607_disable,
+       .is_enabled     = pm8607_is_enabled,
+};
+
+#define PM8607_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \
+{                                                                      \
+       .desc   = {                                                     \
+               .name   = "BUCK" #_id,                                  \
+               .ops    = &pm8607_regulator_ops,                        \
+               .type   = REGULATOR_VOLTAGE,                            \
+               .id     = PM8607_ID_BUCK##_id,                          \
+               .owner  = THIS_MODULE,                                  \
+       },                                                              \
+       .min_uV         = (min) * 1000,                                 \
+       .max_uV         = (max) * 1000,                                 \
+       .step_uV        = (step) * 1000,                                \
+       .vol_reg        = PM8607_##vreg,                                \
+       .vol_shift      = (0),                                          \
+       .vol_nbits      = (nbits),                                      \
+       .update_reg     = PM8607_##ureg,                                \
+       .update_bit     = (ubit),                                       \
+       .enable_reg     = PM8607_##ereg,                                \
+       .enable_bit     = (ebit),                                       \
+       .slope_double   = (0),                                          \
+}
+
+#define PM8607_LDO(_id, min, max, step, vreg, shift, nbits, ereg, ebit)        \
+{                                                                      \
+       .desc   = {                                                     \
+               .name   = "LDO" #_id,                                   \
+               .ops    = &pm8607_regulator_ops,                        \
+               .type   = REGULATOR_VOLTAGE,                            \
+               .id     = PM8607_ID_LDO##_id,                           \
+               .owner  = THIS_MODULE,                                  \
+       },                                                              \
+       .min_uV         = (min) * 1000,                                 \
+       .max_uV         = (max) * 1000,                                 \
+       .step_uV        = (step) * 1000,                                \
+       .vol_reg        = PM8607_##vreg,                                \
+       .vol_shift      = (shift),                                      \
+       .vol_nbits      = (nbits),                                      \
+       .enable_reg     = PM8607_##ereg,                                \
+       .enable_bit     = (ebit),                                       \
+       .slope_double   = (0),                                          \
+}
+
+static struct pm8607_regulator_info pm8607_regulator_info[] = {
+       PM8607_DVC(1, 0, 1500, 25, BUCK1, 6, GO, 0, SUPPLIES_EN11, 0),
+       PM8607_DVC(3, 0, 1500, 25, BUCK3, 6, GO, 2, SUPPLIES_EN11, 2),
+
+       PM8607_LDO(1 , 1200, 2800, 0, LDO1 , 0, 2, SUPPLIES_EN11, 3),
+       PM8607_LDO(2 , 1800, 3300, 0, LDO2 , 0, 3, SUPPLIES_EN11, 4),
+       PM8607_LDO(3 , 1800, 3300, 0, LDO3 , 0, 3, SUPPLIES_EN11, 5),
+       PM8607_LDO(4 , 1800, 3300, 0, LDO4 , 0, 3, SUPPLIES_EN11, 6),
+       PM8607_LDO(5 , 2900, 3300, 0, LDO5 , 0, 2, SUPPLIES_EN11, 7),
+       PM8607_LDO(6 , 1800, 3300, 0, LDO6 , 0, 3, SUPPLIES_EN12, 0),
+       PM8607_LDO(7 , 1800, 2900, 0, LDO7 , 0, 3, SUPPLIES_EN12, 1),
+       PM8607_LDO(8 , 1800, 2900, 0, LDO8 , 0, 3, SUPPLIES_EN12, 2),
+       PM8607_LDO(9 , 1800, 3300, 0, LDO9 , 0, 3, SUPPLIES_EN12, 3),
+       PM8607_LDO(10, 1200, 3300, 0, LDO10, 0, 4, SUPPLIES_EN11, 4),
+       PM8607_LDO(12, 1200, 3300, 0, LDO12, 0, 4, SUPPLIES_EN11, 5),
+       PM8607_LDO(14, 1800, 3300, 0, LDO14, 0, 3, SUPPLIES_EN11, 6),
+};
+
+static inline struct pm8607_regulator_info *find_regulator_info(int id)
+{
+       struct pm8607_regulator_info *info;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) {
+               info = &pm8607_regulator_info[i];
+               if (info->desc.id == id)
+                       return info;
+       }
+       return NULL;
+}
+
+static int __devinit pm8607_regulator_probe(struct platform_device *pdev)
+{
+       struct pm8607_chip *chip = dev_get_drvdata(pdev->dev.parent);
+       struct pm8607_platform_data *pdata = chip->dev->platform_data;
+       struct pm8607_regulator_info *info = NULL;
+
+       info = find_regulator_info(pdev->id);
+       if (info == NULL) {
+               dev_err(&pdev->dev, "invalid regulator ID specified\n");
+               return -EINVAL;
+       }
+
+       info->chip = chip;
+
+       info->regulator = regulator_register(&info->desc, &pdev->dev,
+                                            pdata->regulator[pdev->id], info);
+       if (IS_ERR(info->regulator)) {
+               dev_err(&pdev->dev, "failed to register regulator %s\n",
+                       info->desc.name);
+               return PTR_ERR(info->regulator);
+       }
+
+       /* check DVC ramp slope double */
+       if (info->desc.id == PM8607_ID_BUCK3)
+               if (info->chip->buck3_double)
+                       info->slope_double = 1;
+
+       platform_set_drvdata(pdev, info);
+       return 0;
+}
+
+static int __devexit pm8607_regulator_remove(struct platform_device *pdev)
+{
+       struct pm8607_regulator_info *info = platform_get_drvdata(pdev);
+
+       regulator_unregister(info->regulator);
+       return 0;
+}
+
+#define PM8607_REGULATOR_DRIVER(_name)                         \
+{                                                              \
+       .driver         = {                                     \
+               .name   = "88pm8607-" #_name,                   \
+               .owner  = THIS_MODULE,                          \
+       },                                                      \
+       .probe          = pm8607_regulator_probe,               \
+       .remove         = __devexit_p(pm8607_regulator_remove), \
+}
+
+static struct platform_driver pm8607_regulator_driver[] = {
+       PM8607_REGULATOR_DRIVER(buck1),
+       PM8607_REGULATOR_DRIVER(buck2),
+       PM8607_REGULATOR_DRIVER(buck3),
+       PM8607_REGULATOR_DRIVER(ldo1),
+       PM8607_REGULATOR_DRIVER(ldo2),
+       PM8607_REGULATOR_DRIVER(ldo3),
+       PM8607_REGULATOR_DRIVER(ldo4),
+       PM8607_REGULATOR_DRIVER(ldo5),
+       PM8607_REGULATOR_DRIVER(ldo6),
+       PM8607_REGULATOR_DRIVER(ldo7),
+       PM8607_REGULATOR_DRIVER(ldo8),
+       PM8607_REGULATOR_DRIVER(ldo9),
+       PM8607_REGULATOR_DRIVER(ldo10),
+       PM8607_REGULATOR_DRIVER(ldo12),
+       PM8607_REGULATOR_DRIVER(ldo14),
+};
+
+static int __init pm8607_regulator_init(void)
+{
+       int i, count, ret;
+
+       count = ARRAY_SIZE(pm8607_regulator_driver);
+       for (i = 0; i < count; i++) {
+               ret = platform_driver_register(&pm8607_regulator_driver[i]);
+               if (ret != 0)
+                       pr_err("Failed to register regulator driver: %d\n",
+                               ret);
+       }
+       return 0;
+}
+subsys_initcall(pm8607_regulator_init);
+
+static void __exit pm8607_regulator_exit(void)
+{
+       int i, count;
+
+       count = ARRAY_SIZE(pm8607_regulator_driver);
+       for (i = 0; i < count; i++)
+               platform_driver_unregister(&pm8607_regulator_driver[i]);
+}
+module_exit(pm8607_regulator_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_DESCRIPTION("Regulator Driver for Marvell 88PM8607 PMIC");
+MODULE_ALIAS("platform:88pm8607-regulator");
index 7cfdd65bebb4185efb9552d2be4afa9f3611385f..262f62eec837438f36a5adbf53ebdabae96fe9f7 100644 (file)
@@ -69,6 +69,13 @@ config REGULATOR_MAX1586
          regulator via I2C bus. The provided regulator is suitable
          for PXA27x chips to control VCC_CORE and VCC_USIM voltages.
 
+config REGULATOR_MAX8660
+       tristate "Maxim 8660/8661 voltage regulator"
+       depends on I2C
+       help
+         This driver controls a Maxim 8660/8661 voltage output
+         regulator via I2C bus.
+
 config REGULATOR_TWL4030
        bool "TI TWL4030/TWL5030/TWL6030/TPS695x0 PMIC"
        depends on TWL4030_CORE
@@ -157,5 +164,11 @@ config REGULATOR_TPS6507X
          three step-down converters and two general-purpose LDO voltage regulators.
          It supports TI's software based Class-2 SmartReflex implementation.
 
+config REGULATOR_88PM8607
+       bool "Marvell 88PM8607 Power regulators"
+       depends on MFD_88PM8607=y
+       help
+         This driver supports 88PM8607 voltage regulator chips.
+
 endif
 
index 9ae3cc44e668d97dacaecee4489322de94f8d56e..b3c806c794157aac2f2604d16e9b6a47d82d0ac2 100644 (file)
@@ -12,6 +12,7 @@ obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o
 obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
 obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o
 obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o
+obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o
 obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o
 obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o
 obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o
@@ -20,10 +21,11 @@ obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
 obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
 obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
 obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
-obj-$(CONFIG_REGULATOR_MC13783) += mc13783.o
+obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
 obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o
 
 obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o
 obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o
+obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o
 
 ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
index 49aeee823a25889e8eebd1c21d15ec6b1949ea28..b349db4504b79c6d122ee94221793541af4e0f32 100644 (file)
@@ -81,7 +81,7 @@ static const u8 ab3100_reg_init_order[AB3100_NUM_REGULATORS+2] = {
 #define LDO_C_VOLTAGE 2650000
 #define LDO_D_VOLTAGE 2650000
 
-static const int const ldo_e_buck_typ_voltages[] = {
+static const int ldo_e_buck_typ_voltages[] = {
        1800000,
        1400000,
        1300000,
@@ -91,7 +91,7 @@ static const int const ldo_e_buck_typ_voltages[] = {
        900000,
 };
 
-static const int const ldo_f_typ_voltages[] = {
+static const int ldo_f_typ_voltages[] = {
        1800000,
        1400000,
        1300000,
@@ -102,21 +102,21 @@ static const int const ldo_f_typ_voltages[] = {
        2650000,
 };
 
-static const int const ldo_g_typ_voltages[] = {
+static const int ldo_g_typ_voltages[] = {
        2850000,
        2750000,
        1800000,
        1500000,
 };
 
-static const int const ldo_h_typ_voltages[] = {
+static const int ldo_h_typ_voltages[] = {
        2750000,
        1800000,
        1500000,
        1200000,
 };
 
-static const int const ldo_k_typ_voltages[] = {
+static const int ldo_k_typ_voltages[] = {
        2750000,
        1800000,
 };
@@ -241,24 +241,12 @@ static int ab3100_disable_regulator(struct regulator_dev *reg)
         * LDO D is a special regulator. When it is disabled, the entire
         * system is shut down. So this is handled specially.
         */
+       pr_info("Called ab3100_disable_regulator\n");
        if (abreg->regreg == AB3100_LDO_D) {
-               int i;
-
                dev_info(&reg->dev, "disabling LDO D - shut down system\n");
-               /*
-                * Set regulators to default values, ignore any errors,
-                * we're going DOWN
-                */
-               for (i = 0; i < ARRAY_SIZE(ab3100_reg_init_order); i++) {
-                       (void) ab3100_set_register_interruptible(abreg->ab3100,
-                                       ab3100_reg_init_order[i],
-                                       abreg->plfdata->reg_initvals[i]);
-               }
-
                /* Setting LDO D to 0x00 cuts the power to the SoC */
                return ab3100_set_register_interruptible(abreg->ab3100,
                                                         AB3100_LDO_D, 0x00U);
-
        }
 
        /*
@@ -607,13 +595,6 @@ static int __init ab3100_regulators_probe(struct platform_device *pdev)
                }
        }
 
-       if (err) {
-               dev_err(&pdev->dev,
-                       "LDO D regulator initialization failed with error %d\n",
-                       err);
-               return err;
-       }
-
        /* Register the regulators */
        for (i = 0; i < AB3100_NUM_REGULATORS; i++) {
                struct ab3100_regulator *reg = &ab3100_regulators[i];
@@ -688,7 +669,7 @@ static __init int ab3100_regulators_init(void)
 
 static __exit void ab3100_regulators_exit(void)
 {
-       platform_driver_register(&ab3100_regulators_driver);
+       platform_driver_unregister(&ab3100_regulators_driver);
 }
 
 subsys_initcall(ab3100_regulators_init);
index efe568deda12b7710e882e07d81388af9053e484..686ef270ecf7f01d23bf84a85b5f512be4566f10 100644 (file)
@@ -66,6 +66,16 @@ static unsigned int _regulator_get_mode(struct regulator_dev *rdev);
 static void _notifier_call_chain(struct regulator_dev *rdev,
                                  unsigned long event, void *data);
 
+static const char *rdev_get_name(struct regulator_dev *rdev)
+{
+       if (rdev->constraints && rdev->constraints->name)
+               return rdev->constraints->name;
+       else if (rdev->desc->name)
+               return rdev->desc->name;
+       else
+               return "";
+}
+
 /* gets the regulator for a given consumer device */
 static struct regulator *get_device_regulator(struct device *dev)
 {
@@ -96,12 +106,12 @@ static int regulator_check_voltage(struct regulator_dev *rdev,
 
        if (!rdev->constraints) {
                printk(KERN_ERR "%s: no constraints for %s\n", __func__,
-                      rdev->desc->name);
+                      rdev_get_name(rdev));
                return -ENODEV;
        }
        if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) {
                printk(KERN_ERR "%s: operation not allowed for %s\n",
-                      __func__, rdev->desc->name);
+                      __func__, rdev_get_name(rdev));
                return -EPERM;
        }
 
@@ -124,12 +134,12 @@ static int regulator_check_current_limit(struct regulator_dev *rdev,
 
        if (!rdev->constraints) {
                printk(KERN_ERR "%s: no constraints for %s\n", __func__,
-                      rdev->desc->name);
+                      rdev_get_name(rdev));
                return -ENODEV;
        }
        if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_CURRENT)) {
                printk(KERN_ERR "%s: operation not allowed for %s\n",
-                      __func__, rdev->desc->name);
+                      __func__, rdev_get_name(rdev));
                return -EPERM;
        }
 
@@ -159,17 +169,17 @@ static int regulator_check_mode(struct regulator_dev *rdev, int mode)
 
        if (!rdev->constraints) {
                printk(KERN_ERR "%s: no constraints for %s\n", __func__,
-                      rdev->desc->name);
+                      rdev_get_name(rdev));
                return -ENODEV;
        }
        if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_MODE)) {
                printk(KERN_ERR "%s: operation not allowed for %s\n",
-                      __func__, rdev->desc->name);
+                      __func__, rdev_get_name(rdev));
                return -EPERM;
        }
        if (!(rdev->constraints->valid_modes_mask & mode)) {
                printk(KERN_ERR "%s: invalid mode %x for %s\n",
-                      __func__, mode, rdev->desc->name);
+                      __func__, mode, rdev_get_name(rdev));
                return -EINVAL;
        }
        return 0;
@@ -180,12 +190,12 @@ static int regulator_check_drms(struct regulator_dev *rdev)
 {
        if (!rdev->constraints) {
                printk(KERN_ERR "%s: no constraints for %s\n", __func__,
-                      rdev->desc->name);
+                      rdev_get_name(rdev));
                return -ENODEV;
        }
        if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS)) {
                printk(KERN_ERR "%s: operation not allowed for %s\n",
-                      __func__, rdev->desc->name);
+                      __func__, rdev_get_name(rdev));
                return -EPERM;
        }
        return 0;
@@ -230,16 +240,8 @@ static ssize_t regulator_name_show(struct device *dev,
                             struct device_attribute *attr, char *buf)
 {
        struct regulator_dev *rdev = dev_get_drvdata(dev);
-       const char *name;
 
-       if (rdev->constraints && rdev->constraints->name)
-               name = rdev->constraints->name;
-       else if (rdev->desc->name)
-               name = rdev->desc->name;
-       else
-               name = "";
-
-       return sprintf(buf, "%s\n", name);
+       return sprintf(buf, "%s\n", rdev_get_name(rdev));
 }
 
 static ssize_t regulator_print_opmode(char *buf, int mode)
@@ -388,7 +390,7 @@ static ssize_t regulator_total_uA_show(struct device *dev,
 
        mutex_lock(&rdev->mutex);
        list_for_each_entry(regulator, &rdev->consumer_list, list)
-           uA += regulator->uA_load;
+               uA += regulator->uA_load;
        mutex_unlock(&rdev->mutex);
        return sprintf(buf, "%d\n", uA);
 }
@@ -563,7 +565,7 @@ static void drms_uA_update(struct regulator_dev *rdev)
 
        /* calc total requested load */
        list_for_each_entry(sibling, &rdev->consumer_list, list)
-           current_uA += sibling->uA_load;
+               current_uA += sibling->uA_load;
 
        /* now get the optimum mode for our new total regulator load */
        mode = rdev->desc->ops->get_optimum_mode(rdev, input_uV,
@@ -579,10 +581,29 @@ static int suspend_set_state(struct regulator_dev *rdev,
        struct regulator_state *rstate)
 {
        int ret = 0;
+       bool can_set_state;
 
-       /* enable & disable are mandatory for suspend control */
-       if (!rdev->desc->ops->set_suspend_enable ||
-               !rdev->desc->ops->set_suspend_disable) {
+       can_set_state = rdev->desc->ops->set_suspend_enable &&
+               rdev->desc->ops->set_suspend_disable;
+
+       /* If we have no suspend mode configration don't set anything;
+        * only warn if the driver actually makes the suspend mode
+        * configurable.
+        */
+       if (!rstate->enabled && !rstate->disabled) {
+               if (can_set_state)
+                       printk(KERN_WARNING "%s: No configuration for %s\n",
+                              __func__, rdev_get_name(rdev));
+               return 0;
+       }
+
+       if (rstate->enabled && rstate->disabled) {
+               printk(KERN_ERR "%s: invalid configuration for %s\n",
+                      __func__, rdev_get_name(rdev));
+               return -EINVAL;
+       }
+
+       if (!can_set_state) {
                printk(KERN_ERR "%s: no way to set suspend state\n",
                        __func__);
                return -EINVAL;
@@ -641,25 +662,43 @@ static void print_constraints(struct regulator_dev *rdev)
 {
        struct regulation_constraints *constraints = rdev->constraints;
        char buf[80];
-       int count;
+       int count = 0;
+       int ret;
 
-       if (rdev->desc->type == REGULATOR_VOLTAGE) {
+       if (constraints->min_uV && constraints->max_uV) {
                if (constraints->min_uV == constraints->max_uV)
-                       count = sprintf(buf, "%d mV ",
-                                       constraints->min_uV / 1000);
+                       count += sprintf(buf + count, "%d mV ",
+                                        constraints->min_uV / 1000);
                else
-                       count = sprintf(buf, "%d <--> %d mV ",
-                                       constraints->min_uV / 1000,
-                                       constraints->max_uV / 1000);
-       } else {
+                       count += sprintf(buf + count, "%d <--> %d mV ",
+                                        constraints->min_uV / 1000,
+                                        constraints->max_uV / 1000);
+       }
+
+       if (!constraints->min_uV ||
+           constraints->min_uV != constraints->max_uV) {
+               ret = _regulator_get_voltage(rdev);
+               if (ret > 0)
+                       count += sprintf(buf + count, "at %d mV ", ret / 1000);
+       }
+
+       if (constraints->min_uA && constraints->max_uA) {
                if (constraints->min_uA == constraints->max_uA)
-                       count = sprintf(buf, "%d mA ",
-                                       constraints->min_uA / 1000);
+                       count += sprintf(buf + count, "%d mA ",
+                                        constraints->min_uA / 1000);
                else
-                       count = sprintf(buf, "%d <--> %d mA ",
-                                       constraints->min_uA / 1000,
-                                       constraints->max_uA / 1000);
+                       count += sprintf(buf + count, "%d <--> %d mA ",
+                                        constraints->min_uA / 1000,
+                                        constraints->max_uA / 1000);
        }
+
+       if (!constraints->min_uA ||
+           constraints->min_uA != constraints->max_uA) {
+               ret = _regulator_get_current_limit(rdev);
+               if (ret > 0)
+                       count += sprintf(buf + count, "at %d uA ", ret / 1000);
+       }
+
        if (constraints->valid_modes_mask & REGULATOR_MODE_FAST)
                count += sprintf(buf + count, "fast ");
        if (constraints->valid_modes_mask & REGULATOR_MODE_NORMAL)
@@ -669,33 +708,30 @@ static void print_constraints(struct regulator_dev *rdev)
        if (constraints->valid_modes_mask & REGULATOR_MODE_STANDBY)
                count += sprintf(buf + count, "standby");
 
-       printk(KERN_INFO "regulator: %s: %s\n", rdev->desc->name, buf);
+       printk(KERN_INFO "regulator: %s: %s\n", rdev_get_name(rdev), buf);
 }
 
-/**
- * set_machine_constraints - sets regulator constraints
- * @rdev: regulator source
- * @constraints: constraints to apply
- *
- * Allows platform initialisation code to define and constrain
- * regulator circuits e.g. valid voltage/current ranges, etc.  NOTE:
- * Constraints *must* be set by platform code in order for some
- * regulator operations to proceed i.e. set_voltage, set_current_limit,
- * set_mode.
- */
-static int set_machine_constraints(struct regulator_dev *rdev,
+static int machine_constraints_voltage(struct regulator_dev *rdev,
        struct regulation_constraints *constraints)
 {
-       int ret = 0;
-       const char *name;
        struct regulator_ops *ops = rdev->desc->ops;
+       const char *name = rdev_get_name(rdev);
+       int ret;
 
-       if (constraints->name)
-               name = constraints->name;
-       else if (rdev->desc->name)
-               name = rdev->desc->name;
-       else
-               name = "regulator";
+       /* do we need to apply the constraint voltage */
+       if (rdev->constraints->apply_uV &&
+               rdev->constraints->min_uV == rdev->constraints->max_uV &&
+               ops->set_voltage) {
+               ret = ops->set_voltage(rdev,
+                       rdev->constraints->min_uV, rdev->constraints->max_uV);
+                       if (ret < 0) {
+                               printk(KERN_ERR "%s: failed to apply %duV constraint to %s\n",
+                                      __func__,
+                                      rdev->constraints->min_uV, name);
+                               rdev->constraints = NULL;
+                               return ret;
+                       }
+       }
 
        /* constrain machine-level voltage specs to fit
         * the actual range supported by this regulator.
@@ -719,14 +755,13 @@ static int set_machine_constraints(struct regulator_dev *rdev,
 
                /* voltage constraints are optional */
                if ((cmin == 0) && (cmax == 0))
-                       goto out;
+                       return 0;
 
                /* else require explicit machine-level constraints */
                if (cmin <= 0 || cmax <= 0 || cmax < cmin) {
                        pr_err("%s: %s '%s' voltage constraints\n",
                                       __func__, "invalid", name);
-                       ret = -EINVAL;
-                       goto out;
+                       return -EINVAL;
                }
 
                /* initial: [cmin..cmax] valid, [min_uV..max_uV] not */
@@ -748,8 +783,7 @@ static int set_machine_constraints(struct regulator_dev *rdev,
                if (max_uV < min_uV) {
                        pr_err("%s: %s '%s' voltage constraints\n",
                                       __func__, "unsupportable", name);
-                       ret = -EINVAL;
-                       goto out;
+                       return -EINVAL;
                }
 
                /* use regulator's subset of machine constraints */
@@ -767,22 +801,34 @@ static int set_machine_constraints(struct regulator_dev *rdev,
                }
        }
 
+       return 0;
+}
+
+/**
+ * set_machine_constraints - sets regulator constraints
+ * @rdev: regulator source
+ * @constraints: constraints to apply
+ *
+ * Allows platform initialisation code to define and constrain
+ * regulator circuits e.g. valid voltage/current ranges, etc.  NOTE:
+ * Constraints *must* be set by platform code in order for some
+ * regulator operations to proceed i.e. set_voltage, set_current_limit,
+ * set_mode.
+ */
+static int set_machine_constraints(struct regulator_dev *rdev,
+       struct regulation_constraints *constraints)
+{
+       int ret = 0;
+       const char *name;
+       struct regulator_ops *ops = rdev->desc->ops;
+
        rdev->constraints = constraints;
 
-       /* do we need to apply the constraint voltage */
-       if (rdev->constraints->apply_uV &&
-               rdev->constraints->min_uV == rdev->constraints->max_uV &&
-               ops->set_voltage) {
-               ret = ops->set_voltage(rdev,
-                       rdev->constraints->min_uV, rdev->constraints->max_uV);
-                       if (ret < 0) {
-                               printk(KERN_ERR "%s: failed to apply %duV constraint to %s\n",
-                                      __func__,
-                                      rdev->constraints->min_uV, name);
-                               rdev->constraints = NULL;
-                               goto out;
-                       }
-       }
+       name = rdev_get_name(rdev);
+
+       ret = machine_constraints_voltage(rdev, constraints);
+       if (ret != 0)
+               goto out;
 
        /* do we need to setup our suspend state */
        if (constraints->initial_state) {
@@ -903,7 +949,7 @@ static int set_consumer_device_supply(struct regulator_dev *rdev,
                                dev_name(&node->regulator->dev),
                                node->regulator->desc->name,
                                supply,
-                               dev_name(&rdev->dev), rdev->desc->name);
+                               dev_name(&rdev->dev), rdev_get_name(rdev));
                return -EBUSY;
        }
 
@@ -1212,7 +1258,7 @@ static int _regulator_enable(struct regulator_dev *rdev)
                ret = _regulator_enable(rdev->supply);
                if (ret < 0) {
                        printk(KERN_ERR "%s: failed to enable %s: %d\n",
-                              __func__, rdev->desc->name, ret);
+                              __func__, rdev_get_name(rdev), ret);
                        return ret;
                }
        }
@@ -1238,7 +1284,7 @@ static int _regulator_enable(struct regulator_dev *rdev)
                        }
                } else if (ret < 0) {
                        printk(KERN_ERR "%s: is_enabled() failed for %s: %d\n",
-                              __func__, rdev->desc->name, ret);
+                              __func__, rdev_get_name(rdev), ret);
                        return ret;
                }
                /* Fallthrough on positive return values - already enabled */
@@ -1279,7 +1325,7 @@ static int _regulator_disable(struct regulator_dev *rdev)
 
        if (WARN(rdev->use_count <= 0,
                        "unbalanced disables for %s\n",
-                       rdev->desc->name))
+                       rdev_get_name(rdev)))
                return -EIO;
 
        /* are we the last user and permitted to disable ? */
@@ -1292,7 +1338,7 @@ static int _regulator_disable(struct regulator_dev *rdev)
                        ret = rdev->desc->ops->disable(rdev);
                        if (ret < 0) {
                                printk(KERN_ERR "%s: failed to disable %s\n",
-                                      __func__, rdev->desc->name);
+                                      __func__, rdev_get_name(rdev));
                                return ret;
                        }
                }
@@ -1349,7 +1395,7 @@ static int _regulator_force_disable(struct regulator_dev *rdev)
                ret = rdev->desc->ops->disable(rdev);
                if (ret < 0) {
                        printk(KERN_ERR "%s: failed to force disable %s\n",
-                              __func__, rdev->desc->name);
+                              __func__, rdev_get_name(rdev));
                        return ret;
                }
                /* notify other consumers that power has been forced off */
@@ -1766,7 +1812,7 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load)
        output_uV = rdev->desc->ops->get_voltage(rdev);
        if (output_uV <= 0) {
                printk(KERN_ERR "%s: invalid output voltage found for %s\n",
-                       __func__, rdev->desc->name);
+                       __func__, rdev_get_name(rdev));
                goto out;
        }
 
@@ -1777,13 +1823,13 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load)
                input_uV = rdev->constraints->input_uV;
        if (input_uV <= 0) {
                printk(KERN_ERR "%s: invalid input voltage found for %s\n",
-                       __func__, rdev->desc->name);
+                       __func__, rdev_get_name(rdev));
                goto out;
        }
 
        /* calc total requested load for this regulator */
        list_for_each_entry(consumer, &rdev->consumer_list, list)
-           total_uA_load += consumer->uA_load;
+               total_uA_load += consumer->uA_load;
 
        mode = rdev->desc->ops->get_optimum_mode(rdev,
                                                 input_uV, output_uV,
@@ -1791,7 +1837,7 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load)
        ret = regulator_check_mode(rdev, mode);
        if (ret < 0) {
                printk(KERN_ERR "%s: failed to get optimum mode for %s @"
-                       " %d uA %d -> %d uV\n", __func__, rdev->desc->name,
+                       " %d uA %d -> %d uV\n", __func__, rdev_get_name(rdev),
                        total_uA_load, input_uV, output_uV);
                goto out;
        }
@@ -1799,7 +1845,7 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load)
        ret = rdev->desc->ops->set_mode(rdev, mode);
        if (ret < 0) {
                printk(KERN_ERR "%s: failed to set optimum mode %x for %s\n",
-                       __func__, mode, rdev->desc->name);
+                       __func__, mode, rdev_get_name(rdev));
                goto out;
        }
        ret = mode;
@@ -1852,9 +1898,9 @@ static void _notifier_call_chain(struct regulator_dev *rdev,
 
        /* now notify regulator we supply */
        list_for_each_entry(_rdev, &rdev->supply_list, slist) {
-         mutex_lock(&_rdev->mutex);
-         _notifier_call_chain(_rdev, event, data);
-         mutex_unlock(&_rdev->mutex);
+               mutex_lock(&_rdev->mutex);
+               _notifier_call_chain(_rdev, event, data);
+               mutex_unlock(&_rdev->mutex);
        }
 }
 
@@ -1885,9 +1931,9 @@ int regulator_bulk_get(struct device *dev, int num_consumers,
                consumers[i].consumer = regulator_get(dev,
                                                      consumers[i].supply);
                if (IS_ERR(consumers[i].consumer)) {
-                       dev_err(dev, "Failed to get supply '%s'\n",
-                               consumers[i].supply);
                        ret = PTR_ERR(consumers[i].consumer);
+                       dev_err(dev, "Failed to get supply '%s': %d\n",
+                               consumers[i].supply, ret);
                        consumers[i].consumer = NULL;
                        goto err;
                }
@@ -1930,8 +1976,8 @@ int regulator_bulk_enable(int num_consumers,
        return 0;
 
 err:
-       printk(KERN_ERR "Failed to enable %s\n", consumers[i].supply);
-       for (i = 0; i < num_consumers; i++)
+       printk(KERN_ERR "Failed to enable %s: %d\n", consumers[i].supply, ret);
+       for (--i; i >= 0; --i)
                regulator_disable(consumers[i].consumer);
 
        return ret;
@@ -1965,8 +2011,9 @@ int regulator_bulk_disable(int num_consumers,
        return 0;
 
 err:
-       printk(KERN_ERR "Failed to disable %s\n", consumers[i].supply);
-       for (i = 0; i < num_consumers; i++)
+       printk(KERN_ERR "Failed to disable %s: %d\n", consumers[i].supply,
+              ret);
+       for (--i; i >= 0; --i)
                regulator_enable(consumers[i].consumer);
 
        return ret;
@@ -2316,7 +2363,7 @@ int regulator_suspend_prepare(suspend_state_t state)
 
                if (ret < 0) {
                        printk(KERN_ERR "%s: failed to prepare %s\n",
-                               __func__, rdev->desc->name);
+                               __func__, rdev_get_name(rdev));
                        goto out;
                }
        }
@@ -2429,12 +2476,7 @@ static int __init regulator_init_complete(void)
                ops = rdev->desc->ops;
                c = rdev->constraints;
 
-               if (c && c->name)
-                       name = c->name;
-               else if (rdev->desc->name)
-                       name = rdev->desc->name;
-               else
-                       name = "regulator";
+               name = rdev_get_name(rdev);
 
                if (!ops->disable || (c && c->always_on))
                        continue;
index aa224d936e0de4c92665faf14115bc5592e63bde..f8c4661a7a81ae82705b51691669e230553203b1 100644 (file)
@@ -331,7 +331,7 @@ static int da9034_get_ldo12_voltage(struct regulator_dev *rdev)
 static int da9034_list_ldo12_voltage(struct regulator_dev *rdev,
                                     unsigned selector)
 {
-       if (selector > ARRAY_SIZE(da9034_ldo12_data))
+       if (selector >= ARRAY_SIZE(da9034_ldo12_data))
                return -EINVAL;
        return da9034_ldo12_data[selector] * 1000;
 }
index 7803a320543b1da4f9da2d64ed33e0f108b2f634..76d08c282f9cac3a54133acc30b88fda81b37738 100644 (file)
@@ -446,8 +446,8 @@ static int setup_regulators(struct lp3971 *lp3971,
                lp3971->rdev[i] = regulator_register(&regulators[id],
                        lp3971->dev, pdata->regulators[i].initdata, lp3971);
 
-               err = IS_ERR(lp3971->rdev[i]);
-               if (err) {
+               if (IS_ERR(lp3971->rdev[i])) {
+                       err = PTR_ERR(lp3971->rdev[i]);
                        dev_err(lp3971->dev, "regulator init failed: %d\n",
                                err);
                        goto error;
diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c
new file mode 100644 (file)
index 0000000..acc2fb7
--- /dev/null
@@ -0,0 +1,510 @@
+/*
+ * max8660.c  --  Voltage regulation for the Maxim 8660/8661
+ *
+ * based on max1586.c and wm8400-regulator.c
+ *
+ * Copyright (C) 2009 Wolfram Sang, Pengutronix e.K.
+ *
+ * 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; 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
+ *
+ * Some info:
+ *
+ * Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX8660-MAX8661.pdf
+ *
+ * This chip is a bit nasty because it is a write-only device. Thus, the driver
+ * uses shadow registers to keep track of its values. The main problem appears
+ * to be the initialization: When Linux boots up, we cannot know if the chip is
+ * in the default state or not, so we would have to pass such information in
+ * platform_data. As this adds a bit of complexity to the driver, this is left
+ * out for now until it is really needed.
+ *
+ * [A|S|M]DTV1 registers are currently not used, but [A|S|M]DTV2.
+ *
+ * If the driver is feature complete, it might be worth to check if one set of
+ * functions for V3-V7 is sufficient. For maximum flexibility during
+ * development, they are separated for now.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/max8660.h>
+
+#define MAX8660_DCDC_MIN_UV     725000
+#define MAX8660_DCDC_MAX_UV    1800000
+#define MAX8660_DCDC_STEP        25000
+#define MAX8660_DCDC_MAX_SEL   0x2b
+
+#define MAX8660_LDO5_MIN_UV    1700000
+#define MAX8660_LDO5_MAX_UV    2000000
+#define MAX8660_LDO5_STEP        25000
+#define MAX8660_LDO5_MAX_SEL   0x0c
+
+#define MAX8660_LDO67_MIN_UV   1800000
+#define MAX8660_LDO67_MAX_UV   3300000
+#define MAX8660_LDO67_STEP      100000
+#define MAX8660_LDO67_MAX_SEL  0x0f
+
+enum {
+       MAX8660_OVER1,
+       MAX8660_OVER2,
+       MAX8660_VCC1,
+       MAX8660_ADTV1,
+       MAX8660_ADTV2,
+       MAX8660_SDTV1,
+       MAX8660_SDTV2,
+       MAX8660_MDTV1,
+       MAX8660_MDTV2,
+       MAX8660_L12VCR,
+       MAX8660_FPWM,
+       MAX8660_N_REGS, /* not a real register */
+};
+
+struct max8660 {
+       struct i2c_client *client;
+       u8 shadow_regs[MAX8660_N_REGS];         /* as chip is write only */
+       struct regulator_dev *rdev[];
+};
+
+static int max8660_write(struct max8660 *max8660, u8 reg, u8 mask, u8 val)
+{
+       static const u8 max8660_addresses[MAX8660_N_REGS] =
+         { 0x10, 0x12, 0x20, 0x23, 0x24, 0x29, 0x2a, 0x32, 0x33, 0x39, 0x80 };
+
+       int ret;
+       u8 reg_val = (max8660->shadow_regs[reg] & mask) | val;
+       dev_vdbg(&max8660->client->dev, "Writing reg %02x with %02x\n",
+                       max8660_addresses[reg], reg_val);
+
+       ret = i2c_smbus_write_byte_data(max8660->client,
+                       max8660_addresses[reg], reg_val);
+       if (ret == 0)
+               max8660->shadow_regs[reg] = reg_val;
+
+       return ret;
+}
+
+
+/*
+ * DCDC functions
+ */
+
+static int max8660_dcdc_is_enabled(struct regulator_dev *rdev)
+{
+       struct max8660 *max8660 = rdev_get_drvdata(rdev);
+       u8 val = max8660->shadow_regs[MAX8660_OVER1];
+       u8 mask = (rdev_get_id(rdev) == MAX8660_V3) ? 1 : 4;
+       return !!(val & mask);
+}
+
+static int max8660_dcdc_enable(struct regulator_dev *rdev)
+{
+       struct max8660 *max8660 = rdev_get_drvdata(rdev);
+       u8 bit = (rdev_get_id(rdev) == MAX8660_V3) ? 1 : 4;
+       return max8660_write(max8660, MAX8660_OVER1, 0xff, bit);
+}
+
+static int max8660_dcdc_disable(struct regulator_dev *rdev)
+{
+       struct max8660 *max8660 = rdev_get_drvdata(rdev);
+       u8 mask = (rdev_get_id(rdev) == MAX8660_V3) ? ~1 : ~4;
+       return max8660_write(max8660, MAX8660_OVER1, mask, 0);
+}
+
+static int max8660_dcdc_list(struct regulator_dev *rdev, unsigned selector)
+{
+       if (selector > MAX8660_DCDC_MAX_SEL)
+               return -EINVAL;
+       return MAX8660_DCDC_MIN_UV + selector * MAX8660_DCDC_STEP;
+}
+
+static int max8660_dcdc_get(struct regulator_dev *rdev)
+{
+       struct max8660 *max8660 = rdev_get_drvdata(rdev);
+       u8 reg = (rdev_get_id(rdev) == MAX8660_V3) ? MAX8660_ADTV2 : MAX8660_SDTV2;
+       u8 selector = max8660->shadow_regs[reg];
+       return MAX8660_DCDC_MIN_UV + selector * MAX8660_DCDC_STEP;
+}
+
+static int max8660_dcdc_set(struct regulator_dev *rdev, int min_uV, int max_uV)
+{
+       struct max8660 *max8660 = rdev_get_drvdata(rdev);
+       u8 reg, selector, bits;
+       int ret;
+
+       if (min_uV < MAX8660_DCDC_MIN_UV || min_uV > MAX8660_DCDC_MAX_UV)
+               return -EINVAL;
+       if (max_uV < MAX8660_DCDC_MIN_UV || max_uV > MAX8660_DCDC_MAX_UV)
+               return -EINVAL;
+
+       selector = (min_uV - (MAX8660_DCDC_MIN_UV - MAX8660_DCDC_STEP + 1))
+                       / MAX8660_DCDC_STEP;
+
+       ret = max8660_dcdc_list(rdev, selector);
+       if (ret < 0 || ret > max_uV)
+               return -EINVAL;
+
+       reg = (rdev_get_id(rdev) == MAX8660_V3) ? MAX8660_ADTV2 : MAX8660_SDTV2;
+       ret = max8660_write(max8660, reg, 0, selector);
+       if (ret)
+               return ret;
+
+       /* Select target voltage register and activate regulation */
+       bits = (rdev_get_id(rdev) == MAX8660_V3) ? 0x03 : 0x30;
+       return max8660_write(max8660, MAX8660_VCC1, 0xff, bits);
+}
+
+static struct regulator_ops max8660_dcdc_ops = {
+       .is_enabled = max8660_dcdc_is_enabled,
+       .list_voltage = max8660_dcdc_list,
+       .set_voltage = max8660_dcdc_set,
+       .get_voltage = max8660_dcdc_get,
+};
+
+
+/*
+ * LDO5 functions
+ */
+
+static int max8660_ldo5_list(struct regulator_dev *rdev, unsigned selector)
+{
+       if (selector > MAX8660_LDO5_MAX_SEL)
+               return -EINVAL;
+       return MAX8660_LDO5_MIN_UV + selector * MAX8660_LDO5_STEP;
+}
+
+static int max8660_ldo5_get(struct regulator_dev *rdev)
+{
+       struct max8660 *max8660 = rdev_get_drvdata(rdev);
+       u8 selector = max8660->shadow_regs[MAX8660_MDTV2];
+
+       return MAX8660_LDO5_MIN_UV + selector * MAX8660_LDO5_STEP;
+}
+
+static int max8660_ldo5_set(struct regulator_dev *rdev, int min_uV, int max_uV)
+{
+       struct max8660 *max8660 = rdev_get_drvdata(rdev);
+       u8 selector;
+       int ret;
+
+       if (min_uV < MAX8660_LDO5_MIN_UV || min_uV > MAX8660_LDO5_MAX_UV)
+               return -EINVAL;
+       if (max_uV < MAX8660_LDO5_MIN_UV || max_uV > MAX8660_LDO5_MAX_UV)
+               return -EINVAL;
+
+       selector = (min_uV - (MAX8660_LDO5_MIN_UV - MAX8660_LDO5_STEP + 1))
+                       / MAX8660_LDO5_STEP;
+       ret = max8660_ldo5_list(rdev, selector);
+       if (ret < 0 || ret > max_uV)
+               return -EINVAL;
+
+       ret = max8660_write(max8660, MAX8660_MDTV2, 0, selector);
+       if (ret)
+               return ret;
+
+       /* Select target voltage register and activate regulation */
+       return max8660_write(max8660, MAX8660_VCC1, 0xff, 0xc0);
+}
+
+static struct regulator_ops max8660_ldo5_ops = {
+       .list_voltage = max8660_ldo5_list,
+       .set_voltage = max8660_ldo5_set,
+       .get_voltage = max8660_ldo5_get,
+};
+
+
+/*
+ * LDO67 functions
+ */
+
+static int max8660_ldo67_is_enabled(struct regulator_dev *rdev)
+{
+       struct max8660 *max8660 = rdev_get_drvdata(rdev);
+       u8 val = max8660->shadow_regs[MAX8660_OVER2];
+       u8 mask = (rdev_get_id(rdev) == MAX8660_V6) ? 2 : 4;
+       return !!(val & mask);
+}
+
+static int max8660_ldo67_enable(struct regulator_dev *rdev)
+{
+       struct max8660 *max8660 = rdev_get_drvdata(rdev);
+       u8 bit = (rdev_get_id(rdev) == MAX8660_V6) ? 2 : 4;
+       return max8660_write(max8660, MAX8660_OVER2, 0xff, bit);
+}
+
+static int max8660_ldo67_disable(struct regulator_dev *rdev)
+{
+       struct max8660 *max8660 = rdev_get_drvdata(rdev);
+       u8 mask = (rdev_get_id(rdev) == MAX8660_V6) ? ~2 : ~4;
+       return max8660_write(max8660, MAX8660_OVER2, mask, 0);
+}
+
+static int max8660_ldo67_list(struct regulator_dev *rdev, unsigned selector)
+{
+       if (selector > MAX8660_LDO67_MAX_SEL)
+               return -EINVAL;
+       return MAX8660_LDO67_MIN_UV + selector * MAX8660_LDO67_STEP;
+}
+
+static int max8660_ldo67_get(struct regulator_dev *rdev)
+{
+       struct max8660 *max8660 = rdev_get_drvdata(rdev);
+       u8 shift = (rdev_get_id(rdev) == MAX8660_V6) ? 0 : 4;
+       u8 selector = (max8660->shadow_regs[MAX8660_L12VCR] >> shift) & 0xf;
+
+       return MAX8660_LDO67_MIN_UV + selector * MAX8660_LDO67_STEP;
+}
+
+static int max8660_ldo67_set(struct regulator_dev *rdev, int min_uV, int max_uV)
+{
+       struct max8660 *max8660 = rdev_get_drvdata(rdev);
+       u8 selector;
+       int ret;
+
+       if (min_uV < MAX8660_LDO67_MIN_UV || min_uV > MAX8660_LDO67_MAX_UV)
+               return -EINVAL;
+       if (max_uV < MAX8660_LDO67_MIN_UV || max_uV > MAX8660_LDO67_MAX_UV)
+               return -EINVAL;
+
+       selector = (min_uV - (MAX8660_LDO67_MIN_UV - MAX8660_LDO67_STEP + 1))
+                       / MAX8660_LDO67_STEP;
+
+       ret = max8660_ldo67_list(rdev, selector);
+       if (ret < 0 || ret > max_uV)
+               return -EINVAL;
+
+       if (rdev_get_id(rdev) == MAX8660_V6)
+               return max8660_write(max8660, MAX8660_L12VCR, 0xf0, selector);
+       else
+               return max8660_write(max8660, MAX8660_L12VCR, 0x0f, selector << 4);
+}
+
+static struct regulator_ops max8660_ldo67_ops = {
+       .is_enabled = max8660_ldo67_is_enabled,
+       .enable = max8660_ldo67_enable,
+       .disable = max8660_ldo67_disable,
+       .list_voltage = max8660_ldo67_list,
+       .get_voltage = max8660_ldo67_get,
+       .set_voltage = max8660_ldo67_set,
+};
+
+static struct regulator_desc max8660_reg[] = {
+       {
+               .name = "V3(DCDC)",
+               .id = MAX8660_V3,
+               .ops = &max8660_dcdc_ops,
+               .type = REGULATOR_VOLTAGE,
+               .n_voltages = MAX8660_DCDC_MAX_SEL + 1,
+               .owner = THIS_MODULE,
+       },
+       {
+               .name = "V4(DCDC)",
+               .id = MAX8660_V4,
+               .ops = &max8660_dcdc_ops,
+               .type = REGULATOR_VOLTAGE,
+               .n_voltages = MAX8660_DCDC_MAX_SEL + 1,
+               .owner = THIS_MODULE,
+       },
+       {
+               .name = "V5(LDO)",
+               .id = MAX8660_V5,
+               .ops = &max8660_ldo5_ops,
+               .type = REGULATOR_VOLTAGE,
+               .n_voltages = MAX8660_LDO5_MAX_SEL + 1,
+               .owner = THIS_MODULE,
+       },
+       {
+               .name = "V6(LDO)",
+               .id = MAX8660_V6,
+               .ops = &max8660_ldo67_ops,
+               .type = REGULATOR_VOLTAGE,
+               .n_voltages = MAX8660_LDO67_MAX_SEL + 1,
+               .owner = THIS_MODULE,
+       },
+       {
+               .name = "V7(LDO)",
+               .id = MAX8660_V7,
+               .ops = &max8660_ldo67_ops,
+               .type = REGULATOR_VOLTAGE,
+               .n_voltages = MAX8660_LDO67_MAX_SEL + 1,
+               .owner = THIS_MODULE,
+       },
+};
+
+static int max8660_probe(struct i2c_client *client,
+                             const struct i2c_device_id *i2c_id)
+{
+       struct regulator_dev **rdev;
+       struct max8660_platform_data *pdata = client->dev.platform_data;
+       struct max8660 *max8660;
+       int boot_on, i, id, ret = -EINVAL;
+
+       if (pdata->num_subdevs > MAX8660_V_END) {
+               dev_err(&client->dev, "Too much regulators found!\n");
+               goto out;
+       }
+
+       max8660 = kzalloc(sizeof(struct max8660) +
+                       sizeof(struct regulator_dev *) * MAX8660_V_END,
+                       GFP_KERNEL);
+       if (!max8660) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       max8660->client = client;
+       rdev = max8660->rdev;
+
+       if (pdata->en34_is_high) {
+               /* Simulate always on */
+               max8660->shadow_regs[MAX8660_OVER1] = 5;
+       } else {
+               /* Otherwise devices can be toggled via software */
+               max8660_dcdc_ops.enable = max8660_dcdc_enable;
+               max8660_dcdc_ops.disable = max8660_dcdc_disable;
+       }
+
+       /*
+        * First, set up shadow registers to prevent glitches. As some
+        * registers are shared between regulators, everything must be properly
+        * set up for all regulators in advance.
+        */
+       max8660->shadow_regs[MAX8660_ADTV1] =
+               max8660->shadow_regs[MAX8660_ADTV2] =
+               max8660->shadow_regs[MAX8660_SDTV1] =
+               max8660->shadow_regs[MAX8660_SDTV2] = 0x1b;
+       max8660->shadow_regs[MAX8660_MDTV1] =
+               max8660->shadow_regs[MAX8660_MDTV2] = 0x04;
+
+       for (i = 0; i < pdata->num_subdevs; i++) {
+
+               if (!pdata->subdevs[i].platform_data)
+                       goto err_free;
+
+               boot_on = pdata->subdevs[i].platform_data->constraints.boot_on;
+
+               switch (pdata->subdevs[i].id) {
+               case MAX8660_V3:
+                       if (boot_on)
+                               max8660->shadow_regs[MAX8660_OVER1] |= 1;
+                       break;
+
+               case MAX8660_V4:
+                       if (boot_on)
+                               max8660->shadow_regs[MAX8660_OVER1] |= 4;
+                       break;
+
+               case MAX8660_V5:
+                       break;
+
+               case MAX8660_V6:
+                       if (boot_on)
+                               max8660->shadow_regs[MAX8660_OVER2] |= 2;
+                       break;
+
+               case MAX8660_V7:
+                       if (!strcmp(i2c_id->name, "max8661")) {
+                               dev_err(&client->dev, "Regulator not on this chip!\n");
+                               goto err_free;
+                       }
+
+                       if (boot_on)
+                               max8660->shadow_regs[MAX8660_OVER2] |= 4;
+                       break;
+
+               default:
+                       dev_err(&client->dev, "invalid regulator %s\n",
+                                pdata->subdevs[i].name);
+                       goto err_free;
+               }
+       }
+
+       /* Finally register devices */
+       for (i = 0; i < pdata->num_subdevs; i++) {
+
+               id = pdata->subdevs[i].id;
+
+               rdev[i] = regulator_register(&max8660_reg[id], &client->dev,
+                                            pdata->subdevs[i].platform_data,
+                                            max8660);
+               if (IS_ERR(rdev[i])) {
+                       ret = PTR_ERR(rdev[i]);
+                       dev_err(&client->dev, "failed to register %s\n",
+                               max8660_reg[id].name);
+                       goto err_unregister;
+               }
+       }
+
+       i2c_set_clientdata(client, rdev);
+       dev_info(&client->dev, "Maxim 8660/8661 regulator driver loaded\n");
+       return 0;
+
+err_unregister:
+       while (--i >= 0)
+               regulator_unregister(rdev[i]);
+err_free:
+       kfree(max8660);
+out:
+       return ret;
+}
+
+static int max8660_remove(struct i2c_client *client)
+{
+       struct regulator_dev **rdev = i2c_get_clientdata(client);
+       int i;
+
+       for (i = 0; i < MAX8660_V_END; i++)
+               if (rdev[i])
+                       regulator_unregister(rdev[i]);
+       kfree(rdev);
+       i2c_set_clientdata(client, NULL);
+
+       return 0;
+}
+
+static const struct i2c_device_id max8660_id[] = {
+       { "max8660", 0 },
+       { "max8661", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, max8660_id);
+
+static struct i2c_driver max8660_driver = {
+       .probe = max8660_probe,
+       .remove = max8660_remove,
+       .driver         = {
+               .name   = "max8660",
+       },
+       .id_table       = max8660_id,
+};
+
+static int __init max8660_init(void)
+{
+       return i2c_add_driver(&max8660_driver);
+}
+subsys_initcall(max8660_init);
+
+static void __exit max8660_exit(void)
+{
+       i2c_del_driver(&max8660_driver);
+}
+module_exit(max8660_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("MAXIM 8660/8661 voltage regulator driver");
+MODULE_AUTHOR("Wolfram Sang");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c
new file mode 100644 (file)
index 0000000..39c4953
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * Regulator Driver for Freescale MC13783 PMIC
+ *
+ * Copyright (C) 2008 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/mfd/mc13783.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/driver.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+
+#define MC13783_REG_SWITCHERS4                 28
+#define MC13783_REG_SWITCHERS4_PLLEN                   (1 << 18)
+
+#define MC13783_REG_SWITCHERS5                 29
+#define MC13783_REG_SWITCHERS5_SW3EN                   (1 << 20)
+
+#define MC13783_REG_REGULATORMODE0             32
+#define MC13783_REG_REGULATORMODE0_VAUDIOEN            (1 << 0)
+#define MC13783_REG_REGULATORMODE0_VIOHIEN             (1 << 3)
+#define MC13783_REG_REGULATORMODE0_VIOLOEN             (1 << 6)
+#define MC13783_REG_REGULATORMODE0_VDIGEN              (1 << 9)
+#define MC13783_REG_REGULATORMODE0_VGENEN              (1 << 12)
+#define MC13783_REG_REGULATORMODE0_VRFDIGEN            (1 << 15)
+#define MC13783_REG_REGULATORMODE0_VRFREFEN            (1 << 18)
+#define MC13783_REG_REGULATORMODE0_VRFCPEN             (1 << 21)
+
+#define MC13783_REG_REGULATORMODE1             33
+#define MC13783_REG_REGULATORMODE1_VSIMEN              (1 << 0)
+#define MC13783_REG_REGULATORMODE1_VESIMEN             (1 << 3)
+#define MC13783_REG_REGULATORMODE1_VCAMEN              (1 << 6)
+#define MC13783_REG_REGULATORMODE1_VRFBGEN             (1 << 9)
+#define MC13783_REG_REGULATORMODE1_VVIBEN              (1 << 11)
+#define MC13783_REG_REGULATORMODE1_VRF1EN              (1 << 12)
+#define MC13783_REG_REGULATORMODE1_VRF2EN              (1 << 15)
+#define MC13783_REG_REGULATORMODE1_VMMC1EN             (1 << 18)
+#define MC13783_REG_REGULATORMODE1_VMMC2EN             (1 << 21)
+
+#define MC13783_REG_POWERMISC                  34
+#define MC13783_REG_POWERMISC_GPO1EN                   (1 << 6)
+#define MC13783_REG_POWERMISC_GPO2EN                   (1 << 8)
+#define MC13783_REG_POWERMISC_GPO3EN                   (1 << 10)
+#define MC13783_REG_POWERMISC_GPO4EN                   (1 << 12)
+
+struct mc13783_regulator {
+       struct regulator_desc desc;
+       int reg;
+       int enable_bit;
+};
+
+static struct regulator_ops mc13783_regulator_ops;
+
+#define MC13783_DEFINE(prefix, _name, _reg)                            \
+       [MC13783_ ## prefix ## _ ## _name] = {                          \
+               .desc = {                                               \
+                       .name = #prefix "_" #_name,                     \
+                       .ops = &mc13783_regulator_ops,                  \
+                       .type = REGULATOR_VOLTAGE,                      \
+                       .id = MC13783_ ## prefix ## _ ## _name,         \
+                       .owner = THIS_MODULE,                           \
+               },                                                      \
+               .reg = MC13783_REG_ ## _reg,                            \
+               .enable_bit = MC13783_REG_ ## _reg ## _ ## _name ## EN, \
+       }
+
+#define MC13783_DEFINE_SW(_name, _reg) MC13783_DEFINE(SW, _name, _reg)
+#define MC13783_DEFINE_REGU(_name, _reg) MC13783_DEFINE(REGU, _name, _reg)
+
+static struct mc13783_regulator mc13783_regulators[] = {
+       MC13783_DEFINE_SW(SW3, SWITCHERS5),
+       MC13783_DEFINE_SW(PLL, SWITCHERS4),
+
+       MC13783_DEFINE_REGU(VAUDIO, REGULATORMODE0),
+       MC13783_DEFINE_REGU(VIOHI, REGULATORMODE0),
+       MC13783_DEFINE_REGU(VIOLO, REGULATORMODE0),
+       MC13783_DEFINE_REGU(VDIG, REGULATORMODE0),
+       MC13783_DEFINE_REGU(VGEN, REGULATORMODE0),
+       MC13783_DEFINE_REGU(VRFDIG, REGULATORMODE0),
+       MC13783_DEFINE_REGU(VRFREF, REGULATORMODE0),
+       MC13783_DEFINE_REGU(VRFCP, REGULATORMODE0),
+       MC13783_DEFINE_REGU(VSIM, REGULATORMODE1),
+       MC13783_DEFINE_REGU(VESIM, REGULATORMODE1),
+       MC13783_DEFINE_REGU(VCAM, REGULATORMODE1),
+       MC13783_DEFINE_REGU(VRFBG, REGULATORMODE1),
+       MC13783_DEFINE_REGU(VVIB, REGULATORMODE1),
+       MC13783_DEFINE_REGU(VRF1, REGULATORMODE1),
+       MC13783_DEFINE_REGU(VRF2, REGULATORMODE1),
+       MC13783_DEFINE_REGU(VMMC1, REGULATORMODE1),
+       MC13783_DEFINE_REGU(VMMC2, REGULATORMODE1),
+       MC13783_DEFINE_REGU(GPO1, POWERMISC),
+       MC13783_DEFINE_REGU(GPO2, POWERMISC),
+       MC13783_DEFINE_REGU(GPO3, POWERMISC),
+       MC13783_DEFINE_REGU(GPO4, POWERMISC),
+};
+
+struct mc13783_regulator_priv {
+       struct mc13783 *mc13783;
+       struct regulator_dev *regulators[];
+};
+
+static int mc13783_regulator_enable(struct regulator_dev *rdev)
+{
+       struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev);
+       int id = rdev_get_id(rdev);
+       int ret;
+
+       dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
+
+       mc13783_lock(priv->mc13783);
+       ret = mc13783_reg_rmw(priv->mc13783, mc13783_regulators[id].reg,
+                       mc13783_regulators[id].enable_bit,
+                       mc13783_regulators[id].enable_bit);
+       mc13783_unlock(priv->mc13783);
+
+       return ret;
+}
+
+static int mc13783_regulator_disable(struct regulator_dev *rdev)
+{
+       struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev);
+       int id = rdev_get_id(rdev);
+       int ret;
+
+       dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
+
+       mc13783_lock(priv->mc13783);
+       ret = mc13783_reg_rmw(priv->mc13783, mc13783_regulators[id].reg,
+                       mc13783_regulators[id].enable_bit, 0);
+       mc13783_unlock(priv->mc13783);
+
+       return ret;
+}
+
+static int mc13783_regulator_is_enabled(struct regulator_dev *rdev)
+{
+       struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev);
+       int ret, id = rdev_get_id(rdev);
+       unsigned int val;
+
+       mc13783_lock(priv->mc13783);
+       ret = mc13783_reg_read(priv->mc13783, mc13783_regulators[id].reg, &val);
+       mc13783_unlock(priv->mc13783);
+
+       if (ret)
+               return ret;
+
+       return (val & mc13783_regulators[id].enable_bit) != 0;
+}
+
+static struct regulator_ops mc13783_regulator_ops = {
+       .enable = mc13783_regulator_enable,
+       .disable = mc13783_regulator_disable,
+       .is_enabled = mc13783_regulator_is_enabled,
+};
+
+static int __devinit mc13783_regulator_probe(struct platform_device *pdev)
+{
+       struct mc13783_regulator_priv *priv;
+       struct mc13783 *mc13783 = dev_get_drvdata(pdev->dev.parent);
+       struct mc13783_regulator_platform_data *pdata =
+               dev_get_platdata(&pdev->dev);
+       struct mc13783_regulator_init_data *init_data;
+       int i, ret;
+
+       dev_dbg(&pdev->dev, "mc13783_regulator_probe id %d\n", pdev->id);
+
+       priv = kzalloc(sizeof(*priv) +
+                       pdata->num_regulators * sizeof(priv->regulators[0]),
+                       GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->mc13783 = mc13783;
+
+       for (i = 0; i < pdata->num_regulators; i++) {
+               init_data = &pdata->regulators[i];
+               priv->regulators[i] = regulator_register(
+                               &mc13783_regulators[init_data->id].desc,
+                               &pdev->dev, init_data->init_data, priv);
+
+               if (IS_ERR(priv->regulators[i])) {
+                       dev_err(&pdev->dev, "failed to register regulator %s\n",
+                               mc13783_regulators[i].desc.name);
+                       ret = PTR_ERR(priv->regulators[i]);
+                       goto err;
+               }
+       }
+
+       platform_set_drvdata(pdev, priv);
+
+       return 0;
+err:
+       while (--i >= 0)
+               regulator_unregister(priv->regulators[i]);
+
+       kfree(priv);
+
+       return ret;
+}
+
+static int __devexit mc13783_regulator_remove(struct platform_device *pdev)
+{
+       struct mc13783_regulator_priv *priv = platform_get_drvdata(pdev);
+       struct mc13783_regulator_platform_data *pdata =
+               dev_get_platdata(&pdev->dev);
+       int i;
+
+       for (i = 0; i < pdata->num_regulators; i++)
+               regulator_unregister(priv->regulators[i]);
+
+       return 0;
+}
+
+static struct platform_driver mc13783_regulator_driver = {
+       .driver = {
+               .name   = "mc13783-regulator",
+               .owner  = THIS_MODULE,
+       },
+       .remove         = __devexit_p(mc13783_regulator_remove),
+       .probe          = mc13783_regulator_probe,
+};
+
+static int __init mc13783_regulator_init(void)
+{
+       return platform_driver_register(&mc13783_regulator_driver);
+}
+subsys_initcall(mc13783_regulator_init);
+
+static void __exit mc13783_regulator_exit(void)
+{
+       platform_driver_unregister(&mc13783_regulator_driver);
+}
+module_exit(mc13783_regulator_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de");
+MODULE_DESCRIPTION("Regulator Driver for Freescale MC13783 PMIC");
+MODULE_ALIAS("platform:mc13783-regulator");
diff --git a/drivers/regulator/mc13783.c b/drivers/regulator/mc13783.c
deleted file mode 100644 (file)
index 710211f..0000000
+++ /dev/null
@@ -1,410 +0,0 @@
-/*
- * Regulator Driver for Freescale MC13783 PMIC
- *
- * Copyright (C) 2008 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/mfd/mc13783-private.h>
-#include <linux/regulator/machine.h>
-#include <linux/regulator/driver.h>
-#include <linux/platform_device.h>
-#include <linux/mfd/mc13783.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/err.h>
-
-struct mc13783_regulator {
-       struct regulator_desc desc;
-       int reg;
-       int enable_bit;
-};
-
-static struct regulator_ops mc13783_regulator_ops;
-
-static struct mc13783_regulator mc13783_regulators[] = {
-       [MC13783_SW_SW3] = {
-               .desc = {
-                       .name   = "SW_SW3",
-                       .ops    = &mc13783_regulator_ops,
-                       .type   = REGULATOR_VOLTAGE,
-                       .id     = MC13783_SW_SW3,
-                       .owner  = THIS_MODULE,
-               },
-               .reg = MC13783_REG_SWITCHERS_5,
-               .enable_bit = MC13783_SWCTRL_SW3_EN,
-       },
-       [MC13783_SW_PLL] = {
-               .desc = {
-                       .name   = "SW_PLL",
-                       .ops    = &mc13783_regulator_ops,
-                       .type   = REGULATOR_VOLTAGE,
-                       .id     = MC13783_SW_PLL,
-                       .owner  = THIS_MODULE,
-               },
-               .reg = MC13783_REG_SWITCHERS_4,
-               .enable_bit = MC13783_SWCTRL_PLL_EN,
-       },
-       [MC13783_REGU_VAUDIO] = {
-               .desc = {
-                       .name   = "REGU_VAUDIO",
-                       .ops    = &mc13783_regulator_ops,
-                       .type   = REGULATOR_VOLTAGE,
-                       .id     = MC13783_REGU_VAUDIO,
-                       .owner  = THIS_MODULE,
-               },
-               .reg = MC13783_REG_REGULATOR_MODE_0,
-               .enable_bit = MC13783_REGCTRL_VAUDIO_EN,
-       },
-       [MC13783_REGU_VIOHI] = {
-               .desc = {
-                       .name   = "REGU_VIOHI",
-                       .ops    = &mc13783_regulator_ops,
-                       .type   = REGULATOR_VOLTAGE,
-                       .id     = MC13783_REGU_VIOHI,
-                       .owner  = THIS_MODULE,
-               },
-               .reg = MC13783_REG_REGULATOR_MODE_0,
-               .enable_bit = MC13783_REGCTRL_VIOHI_EN,
-       },
-       [MC13783_REGU_VIOLO] = {
-               .desc = {
-                       .name   = "REGU_VIOLO",
-                       .ops    = &mc13783_regulator_ops,
-                       .type   = REGULATOR_VOLTAGE,
-                       .id     = MC13783_REGU_VIOLO,
-                       .owner  = THIS_MODULE,
-               },
-               .reg = MC13783_REG_REGULATOR_MODE_0,
-               .enable_bit = MC13783_REGCTRL_VIOLO_EN,
-       },
-       [MC13783_REGU_VDIG] = {
-               .desc = {
-                       .name   = "REGU_VDIG",
-                       .ops    = &mc13783_regulator_ops,
-                       .type   = REGULATOR_VOLTAGE,
-                       .id     = MC13783_REGU_VDIG,
-                       .owner  = THIS_MODULE,
-               },
-               .reg = MC13783_REG_REGULATOR_MODE_0,
-               .enable_bit = MC13783_REGCTRL_VDIG_EN,
-       },
-       [MC13783_REGU_VGEN] = {
-               .desc = {
-                       .name   = "REGU_VGEN",
-                       .ops    = &mc13783_regulator_ops,
-                       .type   = REGULATOR_VOLTAGE,
-                       .id     = MC13783_REGU_VGEN,
-                       .owner  = THIS_MODULE,
-               },
-               .reg = MC13783_REG_REGULATOR_MODE_0,
-               .enable_bit = MC13783_REGCTRL_VGEN_EN,
-       },
-       [MC13783_REGU_VRFDIG] = {
-               .desc = {
-                       .name   = "REGU_VRFDIG",
-                       .ops    = &mc13783_regulator_ops,
-                       .type   = REGULATOR_VOLTAGE,
-                       .id     = MC13783_REGU_VRFDIG,
-                       .owner  = THIS_MODULE,
-               },
-               .reg = MC13783_REG_REGULATOR_MODE_0,
-               .enable_bit = MC13783_REGCTRL_VRFDIG_EN,
-       },
-       [MC13783_REGU_VRFREF] = {
-               .desc = {
-                       .name   = "REGU_VRFREF",
-                       .ops    = &mc13783_regulator_ops,
-                       .type   = REGULATOR_VOLTAGE,
-                       .id     = MC13783_REGU_VRFREF,
-                       .owner  = THIS_MODULE,
-               },
-               .reg = MC13783_REG_REGULATOR_MODE_0,
-               .enable_bit = MC13783_REGCTRL_VRFREF_EN,
-       },
-       [MC13783_REGU_VRFCP] = {
-               .desc = {
-                       .name   = "REGU_VRFCP",
-                       .ops    = &mc13783_regulator_ops,
-                       .type   = REGULATOR_VOLTAGE,
-                       .id     = MC13783_REGU_VRFCP,
-                       .owner  = THIS_MODULE,
-               },
-               .reg = MC13783_REG_REGULATOR_MODE_0,
-               .enable_bit = MC13783_REGCTRL_VRFCP_EN,
-       },
-       [MC13783_REGU_VSIM] = {
-               .desc = {
-                       .name   = "REGU_VSIM",
-                       .ops    = &mc13783_regulator_ops,
-                       .type   = REGULATOR_VOLTAGE,
-                       .id     = MC13783_REGU_VSIM,
-                       .owner  = THIS_MODULE,
-               },
-               .reg = MC13783_REG_REGULATOR_MODE_1,
-               .enable_bit = MC13783_REGCTRL_VSIM_EN,
-       },
-       [MC13783_REGU_VESIM] = {
-               .desc = {
-                       .name   = "REGU_VESIM",
-                       .ops    = &mc13783_regulator_ops,
-                       .type   = REGULATOR_VOLTAGE,
-                       .id     = MC13783_REGU_VESIM,
-                       .owner  = THIS_MODULE,
-               },
-               .reg = MC13783_REG_REGULATOR_MODE_1,
-               .enable_bit = MC13783_REGCTRL_VESIM_EN,
-       },
-       [MC13783_REGU_VCAM] = {
-               .desc = {
-                       .name   = "REGU_VCAM",
-                       .ops    = &mc13783_regulator_ops,
-                       .type   = REGULATOR_VOLTAGE,
-                       .id     = MC13783_REGU_VCAM,
-                       .owner  = THIS_MODULE,
-               },
-               .reg = MC13783_REG_REGULATOR_MODE_1,
-               .enable_bit = MC13783_REGCTRL_VCAM_EN,
-       },
-       [MC13783_REGU_VRFBG] = {
-               .desc = {
-                       .name   = "REGU_VRFBG",
-                       .ops    = &mc13783_regulator_ops,
-                       .type   = REGULATOR_VOLTAGE,
-                       .id     = MC13783_REGU_VRFBG,
-                       .owner  = THIS_MODULE,
-               },
-               .reg = MC13783_REG_REGULATOR_MODE_1,
-               .enable_bit = MC13783_REGCTRL_VRFBG_EN,
-       },
-       [MC13783_REGU_VVIB] = {
-               .desc = {
-                       .name   = "REGU_VVIB",
-                       .ops    = &mc13783_regulator_ops,
-                       .type   = REGULATOR_VOLTAGE,
-                       .id     = MC13783_REGU_VVIB,
-                       .owner  = THIS_MODULE,
-               },
-               .reg = MC13783_REG_REGULATOR_MODE_1,
-               .enable_bit = MC13783_REGCTRL_VVIB_EN,
-       },
-       [MC13783_REGU_VRF1] = {
-               .desc = {
-                       .name   = "REGU_VRF1",
-                       .ops    = &mc13783_regulator_ops,
-                       .type   = REGULATOR_VOLTAGE,
-                       .id     = MC13783_REGU_VRF1,
-                       .owner  = THIS_MODULE,
-               },
-               .reg = MC13783_REG_REGULATOR_MODE_1,
-               .enable_bit = MC13783_REGCTRL_VRF1_EN,
-       },
-       [MC13783_REGU_VRF2] = {
-               .desc = {
-                       .name   = "REGU_VRF2",
-                       .ops    = &mc13783_regulator_ops,
-                       .type   = REGULATOR_VOLTAGE,
-                       .id     = MC13783_REGU_VRF2,
-                       .owner  = THIS_MODULE,
-               },
-               .reg = MC13783_REG_REGULATOR_MODE_1,
-               .enable_bit = MC13783_REGCTRL_VRF2_EN,
-       },
-       [MC13783_REGU_VMMC1] = {
-               .desc = {
-                       .name   = "REGU_VMMC1",
-                       .ops    = &mc13783_regulator_ops,
-                       .type   = REGULATOR_VOLTAGE,
-                       .id     = MC13783_REGU_VMMC1,
-                       .owner  = THIS_MODULE,
-               },
-               .reg = MC13783_REG_REGULATOR_MODE_1,
-               .enable_bit = MC13783_REGCTRL_VMMC1_EN,
-       },
-       [MC13783_REGU_VMMC2] = {
-               .desc = {
-                       .name   = "REGU_VMMC2",
-                       .ops    = &mc13783_regulator_ops,
-                       .type   = REGULATOR_VOLTAGE,
-                       .id     = MC13783_REGU_VMMC2,
-                       .owner  = THIS_MODULE,
-               },
-               .reg = MC13783_REG_REGULATOR_MODE_1,
-               .enable_bit = MC13783_REGCTRL_VMMC2_EN,
-       },
-       [MC13783_REGU_GPO1] = {
-               .desc = {
-                       .name   = "REGU_GPO1",
-                       .ops    = &mc13783_regulator_ops,
-                       .type   = REGULATOR_VOLTAGE,
-                       .id     = MC13783_REGU_GPO1,
-                       .owner  = THIS_MODULE,
-               },
-               .reg = MC13783_REG_POWER_MISCELLANEOUS,
-               .enable_bit = MC13783_REGCTRL_GPO1_EN,
-       },
-       [MC13783_REGU_GPO2] = {
-               .desc = {
-                       .name   = "REGU_GPO2",
-                       .ops    = &mc13783_regulator_ops,
-                       .type   = REGULATOR_VOLTAGE,
-                       .id     = MC13783_REGU_GPO2,
-                       .owner  = THIS_MODULE,
-               },
-               .reg = MC13783_REG_POWER_MISCELLANEOUS,
-               .enable_bit = MC13783_REGCTRL_GPO2_EN,
-       },
-       [MC13783_REGU_GPO3] = {
-               .desc = {
-                       .name   = "REGU_GPO3",
-                       .ops    = &mc13783_regulator_ops,
-                       .type   = REGULATOR_VOLTAGE,
-                       .id     = MC13783_REGU_GPO3,
-                       .owner  = THIS_MODULE,
-               },
-               .reg = MC13783_REG_POWER_MISCELLANEOUS,
-               .enable_bit = MC13783_REGCTRL_GPO3_EN,
-       },
-       [MC13783_REGU_GPO4] = {
-               .desc = {
-                       .name   = "REGU_GPO4",
-                       .ops    = &mc13783_regulator_ops,
-                       .type   = REGULATOR_VOLTAGE,
-                       .id     = MC13783_REGU_GPO4,
-                       .owner  = THIS_MODULE,
-               },
-               .reg = MC13783_REG_POWER_MISCELLANEOUS,
-               .enable_bit = MC13783_REGCTRL_GPO4_EN,
-       },
-};
-
-struct mc13783_priv {
-       struct regulator_desc desc[ARRAY_SIZE(mc13783_regulators)];
-       struct mc13783 *mc13783;
-       struct regulator_dev *regulators[0];
-};
-
-static int mc13783_enable(struct regulator_dev *rdev)
-{
-       struct mc13783_priv *priv = rdev_get_drvdata(rdev);
-       int id = rdev_get_id(rdev);
-
-       dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
-
-       return mc13783_set_bits(priv->mc13783, mc13783_regulators[id].reg,
-                       mc13783_regulators[id].enable_bit,
-                       mc13783_regulators[id].enable_bit);
-}
-
-static int mc13783_disable(struct regulator_dev *rdev)
-{
-       struct mc13783_priv *priv = rdev_get_drvdata(rdev);
-       int id = rdev_get_id(rdev);
-
-       dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
-
-       return mc13783_set_bits(priv->mc13783, mc13783_regulators[id].reg,
-                       mc13783_regulators[id].enable_bit, 0);
-}
-
-static int mc13783_is_enabled(struct regulator_dev *rdev)
-{
-       struct mc13783_priv *priv = rdev_get_drvdata(rdev);
-       int ret, id = rdev_get_id(rdev);
-       unsigned int val;
-
-       ret = mc13783_reg_read(priv->mc13783, mc13783_regulators[id].reg, &val);
-       if (ret)
-               return ret;
-
-       return (val & mc13783_regulators[id].enable_bit) != 0;
-}
-
-static struct regulator_ops mc13783_regulator_ops = {
-       .enable         = mc13783_enable,
-       .disable        = mc13783_disable,
-       .is_enabled     = mc13783_is_enabled,
-};
-
-static int __devinit mc13783_regulator_probe(struct platform_device *pdev)
-{
-       struct mc13783_priv *priv;
-       struct mc13783 *mc13783 = dev_get_drvdata(pdev->dev.parent);
-       struct mc13783_regulator_init_data *init_data;
-       int i, ret;
-
-       dev_dbg(&pdev->dev, "mc13783_regulator_probe id %d\n", pdev->id);
-
-       priv = kzalloc(sizeof(*priv) + mc13783->num_regulators * sizeof(void *),
-                       GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-
-       priv->mc13783 = mc13783;
-
-       for (i = 0; i < mc13783->num_regulators; i++) {
-               init_data = &mc13783->regulators[i];
-               priv->regulators[i] = regulator_register(
-                               &mc13783_regulators[init_data->id].desc,
-                               &pdev->dev, init_data->init_data, priv);
-
-               if (IS_ERR(priv->regulators[i])) {
-                       dev_err(&pdev->dev, "failed to register regulator %s\n",
-                               mc13783_regulators[i].desc.name);
-                       ret = PTR_ERR(priv->regulators[i]);
-                       goto err;
-               }
-       }
-
-       platform_set_drvdata(pdev, priv);
-
-       return 0;
-err:
-       while (--i >= 0)
-               regulator_unregister(priv->regulators[i]);
-
-       kfree(priv);
-
-       return ret;
-}
-
-static int __devexit mc13783_regulator_remove(struct platform_device *pdev)
-{
-       struct mc13783_priv *priv = platform_get_drvdata(pdev);
-       struct mc13783 *mc13783 = priv->mc13783;
-       int i;
-
-       for (i = 0; i < mc13783->num_regulators; i++)
-               regulator_unregister(priv->regulators[i]);
-
-       return 0;
-}
-
-static struct platform_driver mc13783_regulator_driver = {
-       .driver = {
-               .name   = "mc13783-regulator",
-               .owner  = THIS_MODULE,
-       },
-       .remove         = __devexit_p(mc13783_regulator_remove),
-};
-
-static int __init mc13783_regulator_init(void)
-{
-       return platform_driver_probe(&mc13783_regulator_driver,
-                       mc13783_regulator_probe);
-}
-subsys_initcall(mc13783_regulator_init);
-
-static void __exit mc13783_regulator_exit(void)
-{
-       platform_driver_unregister(&mc13783_regulator_driver);
-}
-module_exit(mc13783_regulator_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de");
-MODULE_DESCRIPTION("Regulator Driver for Freescale MC13783 PMIC");
-MODULE_ALIAS("platform:mc13783-regulator");
index 7ea1c3a31081cd656b85ee62a1694ae943d34993..7e674859bd59b366288d43bf9baf2bc13dab8b11 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/err.h>
+#include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
@@ -40,6 +41,12 @@ struct twlreg_info {
        u8                      table_len;
        const u16               *table;
 
+       /* regulator specific turn-on delay */
+       u16                     delay;
+
+       /* State REMAP default configuration */
+       u8                      remap;
+
        /* chip constraints on regulator behavior */
        u16                     min_mV;
 
@@ -128,6 +135,7 @@ static int twlreg_enable(struct regulator_dev *rdev)
 {
        struct twlreg_info      *info = rdev_get_drvdata(rdev);
        int                     grp;
+       int                     ret;
 
        grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP);
        if (grp < 0)
@@ -138,7 +146,11 @@ static int twlreg_enable(struct regulator_dev *rdev)
        else
                grp |= P1_GRP_6030;
 
-       return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp);
+       ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp);
+
+       udelay(info->delay);
+
+       return ret;
 }
 
 static int twlreg_disable(struct regulator_dev *rdev)
@@ -151,9 +163,9 @@ static int twlreg_disable(struct regulator_dev *rdev)
                return grp;
 
        if (twl_class_is_4030())
-               grp &= ~P1_GRP_4030;
+               grp &= ~(P1_GRP_4030 | P2_GRP_4030 | P3_GRP_4030);
        else
-               grp &= ~P1_GRP_6030;
+               grp &= ~(P1_GRP_6030 | P2_GRP_6030 | P3_GRP_6030);
 
        return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp);
 }
@@ -294,6 +306,18 @@ static const u16 VSIM_VSEL_table[] = {
 static const u16 VDAC_VSEL_table[] = {
        1200, 1300, 1800, 1800,
 };
+static const u16 VDD1_VSEL_table[] = {
+       800, 1450,
+};
+static const u16 VDD2_VSEL_table[] = {
+       800, 1450, 1500,
+};
+static const u16 VIO_VSEL_table[] = {
+       1800, 1850,
+};
+static const u16 VINTANA2_VSEL_table[] = {
+       2500, 2750,
+};
 static const u16 VAUX1_6030_VSEL_table[] = {
        1000, 1300, 1800, 2500,
        2800, 2900, 3000, 3000,
@@ -414,20 +438,30 @@ static struct regulator_ops twlfixed_ops = {
 
 /*----------------------------------------------------------------------*/
 
-#define TWL4030_ADJUSTABLE_LDO(label, offset, num) \
-               TWL_ADJUSTABLE_LDO(label, offset, num, TWL4030)
-#define TWL4030_FIXED_LDO(label, offset, mVolts, num) \
-               TWL_FIXED_LDO(label, offset, mVolts, num, TWL4030)
-#define TWL6030_ADJUSTABLE_LDO(label, offset, num) \
-               TWL_ADJUSTABLE_LDO(label, offset, num, TWL6030)
-#define TWL6030_FIXED_LDO(label, offset, mVolts, num) \
-               TWL_FIXED_LDO(label, offset, mVolts, num, TWL6030)
-
-#define TWL_ADJUSTABLE_LDO(label, offset, num, family) { \
+#define TWL4030_ADJUSTABLE_LDO(label, offset, num, turnon_delay, remap_conf) \
+               TWL_ADJUSTABLE_LDO(label, offset, num, turnon_delay, \
+                       remap_conf, TWL4030)
+#define TWL4030_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
+                       remap_conf) \
+               TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
+                       remap_conf, TWL4030)
+#define TWL6030_ADJUSTABLE_LDO(label, offset, num, turnon_delay, \
+                       remap_conf) \
+               TWL_ADJUSTABLE_LDO(label, offset, num, turnon_delay, \
+                       remap_conf, TWL6030)
+#define TWL6030_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
+                       remap_conf) \
+               TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
+                       remap_conf, TWL6030)
+
+#define TWL_ADJUSTABLE_LDO(label, offset, num, turnon_delay, remap_conf, \
+               family) { \
        .base = offset, \
        .id = num, \
        .table_len = ARRAY_SIZE(label##_VSEL_table), \
        .table = label##_VSEL_table, \
+       .delay = turnon_delay, \
+       .remap = remap_conf, \
        .desc = { \
                .name = #label, \
                .id = family##_REG_##label, \
@@ -438,10 +472,13 @@ static struct regulator_ops twlfixed_ops = {
                }, \
        }
 
-#define TWL_FIXED_LDO(label, offset, mVolts, num, family) { \
+#define TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, remap_conf, \
+               family) { \
        .base = offset, \
        .id = num, \
        .min_mV = mVolts, \
+       .delay = turnon_delay, \
+       .remap = remap_conf, \
        .desc = { \
                .name = #label, \
                .id = family##_REG_##label, \
@@ -457,43 +494,41 @@ static struct regulator_ops twlfixed_ops = {
  * software control over them after boot.
  */
 static struct twlreg_info twl_regs[] = {
-       TWL4030_ADJUSTABLE_LDO(VAUX1, 0x17, 1),
-       TWL4030_ADJUSTABLE_LDO(VAUX2_4030, 0x1b, 2),
-       TWL4030_ADJUSTABLE_LDO(VAUX2, 0x1b, 2),
-       TWL4030_ADJUSTABLE_LDO(VAUX3, 0x1f, 3),
-       TWL4030_ADJUSTABLE_LDO(VAUX4, 0x23, 4),
-       TWL4030_ADJUSTABLE_LDO(VMMC1, 0x27, 5),
-       TWL4030_ADJUSTABLE_LDO(VMMC2, 0x2b, 6),
-       /*
-       TWL4030_ADJUSTABLE_LDO(VPLL1, 0x2f, 7),
-       */
-       TWL4030_ADJUSTABLE_LDO(VPLL2, 0x33, 8),
-       TWL4030_ADJUSTABLE_LDO(VSIM, 0x37, 9),
-       TWL4030_ADJUSTABLE_LDO(VDAC, 0x3b, 10),
-       /*
-       TWL4030_ADJUSTABLE_LDO(VINTANA1, 0x3f, 11),
-       TWL4030_ADJUSTABLE_LDO(VINTANA2, 0x43, 12),
-       TWL4030_ADJUSTABLE_LDO(VINTDIG, 0x47, 13),
-       TWL4030_SMPS(VIO, 0x4b, 14),
-       TWL4030_SMPS(VDD1, 0x55, 15),
-       TWL4030_SMPS(VDD2, 0x63, 16),
-        */
-       TWL4030_FIXED_LDO(VUSB1V5, 0x71, 1500, 17),
-       TWL4030_FIXED_LDO(VUSB1V8, 0x74, 1800, 18),
-       TWL4030_FIXED_LDO(VUSB3V1, 0x77, 3100, 19),
+       TWL4030_ADJUSTABLE_LDO(VAUX1, 0x17, 1, 100, 0x08),
+       TWL4030_ADJUSTABLE_LDO(VAUX2_4030, 0x1b, 2, 100, 0x08),
+       TWL4030_ADJUSTABLE_LDO(VAUX2, 0x1b, 2, 100, 0x08),
+       TWL4030_ADJUSTABLE_LDO(VAUX3, 0x1f, 3, 100, 0x08),
+       TWL4030_ADJUSTABLE_LDO(VAUX4, 0x23, 4, 100, 0x08),
+       TWL4030_ADJUSTABLE_LDO(VMMC1, 0x27, 5, 100, 0x08),
+       TWL4030_ADJUSTABLE_LDO(VMMC2, 0x2b, 6, 100, 0x08),
+       TWL4030_ADJUSTABLE_LDO(VPLL1, 0x2f, 7, 100, 0x00),
+       TWL4030_ADJUSTABLE_LDO(VPLL2, 0x33, 8, 100, 0x08),
+       TWL4030_ADJUSTABLE_LDO(VSIM, 0x37, 9, 100, 0x00),
+       TWL4030_ADJUSTABLE_LDO(VDAC, 0x3b, 10, 100, 0x08),
+       TWL4030_FIXED_LDO(VINTANA1, 0x3f, 1500, 11, 100, 0x08),
+       TWL4030_ADJUSTABLE_LDO(VINTANA2, 0x43, 12, 100, 0x08),
+       TWL4030_FIXED_LDO(VINTDIG, 0x47, 1500, 13, 100, 0x08),
+       TWL4030_ADJUSTABLE_LDO(VIO, 0x4b, 14, 1000, 0x08),
+       TWL4030_ADJUSTABLE_LDO(VDD1, 0x55, 15, 1000, 0x08),
+       TWL4030_ADJUSTABLE_LDO(VDD2, 0x63, 16, 1000, 0x08),
+       TWL4030_FIXED_LDO(VUSB1V5, 0x71, 1500, 17, 100, 0x08),
+       TWL4030_FIXED_LDO(VUSB1V8, 0x74, 1800, 18, 100, 0x08),
+       TWL4030_FIXED_LDO(VUSB3V1, 0x77, 3100, 19, 150, 0x08),
        /* VUSBCP is managed *only* by the USB subchip */
 
        /* 6030 REG with base as PMC Slave Misc : 0x0030 */
-       TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1),
-       TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 2),
-       TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 3),
-       TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 4),
-       TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 5),
-       TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 7),
-       TWL6030_FIXED_LDO(VANA, 0x50, 2100, 15),
-       TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 16),
-       TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 17),
-       TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 18)
+       /* Turnon-delay and remap configuration values for 6030 are not
+          verified since the specification is not public */
+       TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1, 0, 0x08),
+       TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 2, 0, 0x08),
+       TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 3, 0, 0x08),
+       TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 4, 0, 0x08),
+       TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 5, 0, 0x08),
+       TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 7, 0, 0x08),
+       TWL6030_FIXED_LDO(VANA, 0x50, 2100, 15, 0, 0x08),
+       TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 16, 0, 0x08),
+       TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 17, 0, 0x08),
+       TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 18, 0, 0x08)
 };
 
 static int twlreg_probe(struct platform_device *pdev)
@@ -525,6 +560,19 @@ static int twlreg_probe(struct platform_device *pdev)
        c->valid_ops_mask &= REGULATOR_CHANGE_VOLTAGE
                                | REGULATOR_CHANGE_MODE
                                | REGULATOR_CHANGE_STATUS;
+       switch (pdev->id) {
+       case TWL4030_REG_VIO:
+       case TWL4030_REG_VDD1:
+       case TWL4030_REG_VDD2:
+       case TWL4030_REG_VPLL1:
+       case TWL4030_REG_VINTANA1:
+       case TWL4030_REG_VINTANA2:
+       case TWL4030_REG_VINTDIG:
+               c->always_on = true;
+               break;
+       default:
+               break;
+       }
 
        rdev = regulator_register(&info->desc, &pdev->dev, initdata, info);
        if (IS_ERR(rdev)) {
@@ -534,6 +582,9 @@ static int twlreg_probe(struct platform_device *pdev)
        }
        platform_set_drvdata(pdev, rdev);
 
+       twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_REMAP,
+                                               info->remap);
+
        /* NOTE:  many regulators support short-circuit IRQs (presentable
         * as REGULATOR_OVER_CURRENT notifications?) configured via:
         *  - SC_CONFIG
index 2eefc1a0cf08eedcb68235dcd2dcfe0857910151..0a6577577e8d674252ea8b2a025f4a23515c5681 100644 (file)
@@ -19,6 +19,8 @@
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/gpio.h>
 
 #include <linux/mfd/wm831x/core.h>
 #include <linux/mfd/wm831x/regulator.h>
@@ -39,6 +41,7 @@
 #define WM831X_DCDC_CONTROL_2     1
 #define WM831X_DCDC_ON_CONFIG     2
 #define WM831X_DCDC_SLEEP_CONTROL 3
+#define WM831X_DCDC_DVS_CONTROL   4
 
 /*
  * Shared
@@ -50,6 +53,10 @@ struct wm831x_dcdc {
        int base;
        struct wm831x *wm831x;
        struct regulator_dev *regulator;
+       int dvs_gpio;
+       int dvs_gpio_state;
+       int on_vsel;
+       int dvs_vsel;
 };
 
 static int wm831x_dcdc_is_enabled(struct regulator_dev *rdev)
@@ -240,11 +247,9 @@ static int wm831x_buckv_list_voltage(struct regulator_dev *rdev,
        return -EINVAL;
 }
 
-static int wm831x_buckv_set_voltage_int(struct regulator_dev *rdev, int reg,
-                                        int min_uV, int max_uV)
+static int wm831x_buckv_select_min_voltage(struct regulator_dev *rdev,
+                                          int min_uV, int max_uV)
 {
-       struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
-       struct wm831x *wm831x = dcdc->wm831x;
        u16 vsel;
 
        if (min_uV < 600000)
@@ -257,39 +262,126 @@ static int wm831x_buckv_set_voltage_int(struct regulator_dev *rdev, int reg,
        if (wm831x_buckv_list_voltage(rdev, vsel) > max_uV)
                return -EINVAL;
 
-       return wm831x_set_bits(wm831x, reg, WM831X_DC1_ON_VSEL_MASK, vsel);
+       return vsel;
+}
+
+static int wm831x_buckv_select_max_voltage(struct regulator_dev *rdev,
+                                          int min_uV, int max_uV)
+{
+       u16 vsel;
+
+       if (max_uV < 600000 || max_uV > 1800000)
+               return -EINVAL;
+
+       vsel = ((max_uV - 600000) / 12500) + 8;
+
+       if (wm831x_buckv_list_voltage(rdev, vsel) < min_uV ||
+           wm831x_buckv_list_voltage(rdev, vsel) < max_uV)
+               return -EINVAL;
+
+       return vsel;
+}
+
+static int wm831x_buckv_set_dvs(struct regulator_dev *rdev, int state)
+{
+       struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
+
+       if (state == dcdc->dvs_gpio_state)
+               return 0;
+
+       dcdc->dvs_gpio_state = state;
+       gpio_set_value(dcdc->dvs_gpio, state);
+
+       /* Should wait for DVS state change to be asserted if we have
+        * a GPIO for it, for now assume the device is configured
+        * for the fastest possible transition.
+        */
+
+       return 0;
 }
 
 static int wm831x_buckv_set_voltage(struct regulator_dev *rdev,
-                                    int min_uV, int max_uV)
+                                   int min_uV, int max_uV)
 {
        struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
-       u16 reg = dcdc->base + WM831X_DCDC_ON_CONFIG;
+       struct wm831x *wm831x = dcdc->wm831x;
+       int on_reg = dcdc->base + WM831X_DCDC_ON_CONFIG;
+       int dvs_reg = dcdc->base + WM831X_DCDC_DVS_CONTROL;
+       int vsel, ret;
+
+       vsel = wm831x_buckv_select_min_voltage(rdev, min_uV, max_uV);
+       if (vsel < 0)
+               return vsel;
+
+       /* If this value is already set then do a GPIO update if we can */
+       if (dcdc->dvs_gpio && dcdc->on_vsel == vsel)
+               return wm831x_buckv_set_dvs(rdev, 0);
+
+       if (dcdc->dvs_gpio && dcdc->dvs_vsel == vsel)
+               return wm831x_buckv_set_dvs(rdev, 1);
+
+       /* Always set the ON status to the minimum voltage */
+       ret = wm831x_set_bits(wm831x, on_reg, WM831X_DC1_ON_VSEL_MASK, vsel);
+       if (ret < 0)
+               return ret;
+       dcdc->on_vsel = vsel;
+
+       if (!dcdc->dvs_gpio)
+               return ret;
+
+       /* Kick the voltage transition now */
+       ret = wm831x_buckv_set_dvs(rdev, 0);
+       if (ret < 0)
+               return ret;
+
+       /* Set the high voltage as the DVS voltage.  This is optimised
+        * for CPUfreq usage, most processors will keep the maximum
+        * voltage constant and lower the minimum with the frequency. */
+       vsel = wm831x_buckv_select_max_voltage(rdev, min_uV, max_uV);
+       if (vsel < 0) {
+               /* This should never happen - at worst the same vsel
+                * should be chosen */
+               WARN_ON(vsel < 0);
+               return 0;
+       }
+
+       /* Don't bother if it's the same VSEL we're already using */
+       if (vsel == dcdc->on_vsel)
+               return 0;
 
-       return wm831x_buckv_set_voltage_int(rdev, reg, min_uV, max_uV);
+       ret = wm831x_set_bits(wm831x, dvs_reg, WM831X_DC1_DVS_VSEL_MASK, vsel);
+       if (ret == 0)
+               dcdc->dvs_vsel = vsel;
+       else
+               dev_warn(wm831x->dev, "Failed to set DCDC DVS VSEL: %d\n",
+                        ret);
+
+       return 0;
 }
 
 static int wm831x_buckv_set_suspend_voltage(struct regulator_dev *rdev,
-                                            int uV)
+                                           int uV)
 {
        struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
+       struct wm831x *wm831x = dcdc->wm831x;
        u16 reg = dcdc->base + WM831X_DCDC_SLEEP_CONTROL;
+       int vsel;
+
+       vsel = wm831x_buckv_select_min_voltage(rdev, uV, uV);
+       if (vsel < 0)
+               return vsel;
 
-       return wm831x_buckv_set_voltage_int(rdev, reg, uV, uV);
+       return wm831x_set_bits(wm831x, reg, WM831X_DC1_SLP_VSEL_MASK, vsel);
 }
 
 static int wm831x_buckv_get_voltage(struct regulator_dev *rdev)
 {
        struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
-       struct wm831x *wm831x = dcdc->wm831x;
-       u16 reg = dcdc->base + WM831X_DCDC_ON_CONFIG;
-       int val;
 
-       val = wm831x_reg_read(wm831x, reg);
-       if (val < 0)
-               return val;
-
-       return wm831x_buckv_list_voltage(rdev, val & WM831X_DC1_ON_VSEL_MASK);
+       if (dcdc->dvs_gpio && dcdc->dvs_gpio_state)
+               return wm831x_buckv_list_voltage(rdev, dcdc->dvs_vsel);
+       else
+               return wm831x_buckv_list_voltage(rdev, dcdc->on_vsel);
 }
 
 /* Current limit options */
@@ -346,6 +438,64 @@ static struct regulator_ops wm831x_buckv_ops = {
        .set_suspend_mode = wm831x_dcdc_set_suspend_mode,
 };
 
+/*
+ * Set up DVS control.  We just log errors since we can still run
+ * (with reduced performance) if we fail.
+ */
+static __devinit void wm831x_buckv_dvs_init(struct wm831x_dcdc *dcdc,
+                                           struct wm831x_buckv_pdata *pdata)
+{
+       struct wm831x *wm831x = dcdc->wm831x;
+       int ret;
+       u16 ctrl;
+
+       if (!pdata || !pdata->dvs_gpio)
+               return;
+
+       switch (pdata->dvs_control_src) {
+       case 1:
+               ctrl = 2 << WM831X_DC1_DVS_SRC_SHIFT;
+               break;
+       case 2:
+               ctrl = 3 << WM831X_DC1_DVS_SRC_SHIFT;
+               break;
+       default:
+               dev_err(wm831x->dev, "Invalid DVS control source %d for %s\n",
+                       pdata->dvs_control_src, dcdc->name);
+               return;
+       }
+
+       ret = wm831x_set_bits(wm831x, dcdc->base + WM831X_DCDC_DVS_CONTROL,
+                             WM831X_DC1_DVS_SRC_MASK, ctrl);
+       if (ret < 0) {
+               dev_err(wm831x->dev, "Failed to set %s DVS source: %d\n",
+                       dcdc->name, ret);
+               return;
+       }
+
+       ret = gpio_request(pdata->dvs_gpio, "DCDC DVS");
+       if (ret < 0) {
+               dev_err(wm831x->dev, "Failed to get %s DVS GPIO: %d\n",
+                       dcdc->name, ret);
+               return;
+       }
+
+       /* gpiolib won't let us read the GPIO status so pick the higher
+        * of the two existing voltages so we take it as platform data.
+        */
+       dcdc->dvs_gpio_state = pdata->dvs_init_state;
+
+       ret = gpio_direction_output(pdata->dvs_gpio, dcdc->dvs_gpio_state);
+       if (ret < 0) {
+               dev_err(wm831x->dev, "Failed to enable %s DVS GPIO: %d\n",
+                       dcdc->name, ret);
+               gpio_free(pdata->dvs_gpio);
+               return;
+       }
+
+       dcdc->dvs_gpio = pdata->dvs_gpio;
+}
+
 static __devinit int wm831x_buckv_probe(struct platform_device *pdev)
 {
        struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
@@ -384,6 +534,23 @@ static __devinit int wm831x_buckv_probe(struct platform_device *pdev)
        dcdc->desc.ops = &wm831x_buckv_ops;
        dcdc->desc.owner = THIS_MODULE;
 
+       ret = wm831x_reg_read(wm831x, dcdc->base + WM831X_DCDC_ON_CONFIG);
+       if (ret < 0) {
+               dev_err(wm831x->dev, "Failed to read ON VSEL: %d\n", ret);
+               goto err;
+       }
+       dcdc->on_vsel = ret & WM831X_DC1_ON_VSEL_MASK;
+
+       ret = wm831x_reg_read(wm831x, dcdc->base + WM831X_DCDC_ON_CONFIG);
+       if (ret < 0) {
+               dev_err(wm831x->dev, "Failed to read DVS VSEL: %d\n", ret);
+               goto err;
+       }
+       dcdc->dvs_vsel = ret & WM831X_DC1_DVS_VSEL_MASK;
+
+       if (pdata->dcdc[id])
+               wm831x_buckv_dvs_init(dcdc, pdata->dcdc[id]->driver_data);
+
        dcdc->regulator = regulator_register(&dcdc->desc, &pdev->dev,
                                             pdata->dcdc[id], dcdc);
        if (IS_ERR(dcdc->regulator)) {
@@ -422,6 +589,8 @@ err_uv:
 err_regulator:
        regulator_unregister(dcdc->regulator);
 err:
+       if (dcdc->dvs_gpio)
+               gpio_free(dcdc->dvs_gpio);
        kfree(dcdc);
        return ret;
 }
@@ -434,6 +603,8 @@ static __devexit int wm831x_buckv_remove(struct platform_device *pdev)
        wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "HC"), dcdc);
        wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), dcdc);
        regulator_unregister(dcdc->regulator);
+       if (dcdc->dvs_gpio)
+               gpio_free(dcdc->dvs_gpio);
        kfree(dcdc);
 
        return 0;
index 902db56ce099676f6a2a3f2483dd0d7b3c75811f..61e02ac2fda334f9e17dd145cf65d938f816548e 100644 (file)
@@ -470,7 +470,7 @@ static unsigned int wm831x_aldo_get_mode(struct regulator_dev *rdev)
        struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
        struct wm831x *wm831x = ldo->wm831x;
        int on_reg = ldo->base + WM831X_LDO_ON_CONTROL;
-       unsigned int ret;
+       int ret;
 
        ret = wm831x_reg_read(wm831x, on_reg);
        if (ret < 0)
index 259db7f3535b4754b3fe2d95e9a92d722e75a4ec..9630e7d3314e59d19dd9e94be9f917cab7307f16 100644 (file)
@@ -778,6 +778,8 @@ static int __devinit ds1305_probe(struct spi_device *spi)
                                        spi->irq, status);
                        goto fail1;
                }
+
+               device_set_wakeup_capable(&spi->dev, 1);
        }
 
        /* export NVRAM */
index 8a99da6f2f2439fba20b9e6bd3772dafc639eedd..c4ec5c158aa14f81ca355c9c0b0366ffa383e11c 100644 (file)
@@ -881,6 +881,8 @@ read_rtc:
                                "unable to request IRQ!\n");
                        goto exit_irq;
                }
+
+               device_set_wakeup_capable(&client->dev, 1);
                set_bit(HAS_ALARM, &ds1307->flags);
                dev_dbg(&client->dev, "got IRQ %d\n", client->irq);
        }
index 713f7bf5afb330c508b5d2482804f97ed0083470..5317bbcbc7a0c7cb3f60e16e6bafac483327a666 100644 (file)
@@ -383,6 +383,8 @@ static int ds1374_probe(struct i2c_client *client,
                        dev_err(&client->dev, "unable to request IRQ\n");
                        goto out_free;
                }
+
+               device_set_wakeup_capable(&client->dev, 1);
        }
 
        ds1374->rtc = rtc_device_register(client->name, &client->dev,
index 2d9d70359360719ea3851ee8ad33fba70f884635..f55eb0107336b0a66ca8f68dd41b9a3752d3bb3a 100644 (file)
@@ -216,6 +216,17 @@ config SPI_S3C24XX
        help
          SPI driver for Samsung S3C24XX series ARM SoCs
 
+config SPI_S3C24XX_FIQ
+       bool "S3C24XX driver with FIQ pseudo-DMA"
+       depends on SPI_S3C24XX
+       select FIQ
+       help
+         Enable FIQ support for the S3C24XX SPI driver to provide pseudo
+         DMA by using the fast-interrupt request framework, This allows
+         the driver to get DMA-like performance when there are either
+         no free DMA channels, or when doing transfers that required both
+         TX and RX data paths.
+
 config SPI_S3C24XX_GPIO
        tristate "Samsung S3C24XX series SPI by GPIO"
        depends on ARCH_S3C2410 && EXPERIMENTAL
@@ -226,6 +237,13 @@ config SPI_S3C24XX_GPIO
          the inbuilt hardware cannot provide the transfer mode, or
          where the board is using non hardware connected pins.
 
+config SPI_S3C64XX
+       tristate "Samsung S3C64XX series type SPI"
+       depends on ARCH_S3C64XX && EXPERIMENTAL
+       select S3C64XX_DMA
+       help
+         SPI driver for Samsung S3C64XX and newer SoCs.
+
 config SPI_SH_MSIOF
        tristate "SuperH MSIOF SPI controller"
        depends on SUPERH && HAVE_CLK
@@ -289,6 +307,16 @@ config SPI_NUC900
 # Add new SPI master controllers in alphabetical order above this line
 #
 
+config SPI_DESIGNWARE
+       bool "DesignWare SPI controller core support"
+       depends on SPI_MASTER
+       help
+         general driver for SPI controller core from DesignWare
+
+config SPI_DW_PCI
+       tristate "PCI interface driver for DW SPI core"
+       depends on SPI_DESIGNWARE && PCI
+
 #
 # There are lots of SPI device types, with sensors and memory
 # being probably the most widely used ones.
index ed8c1675b52f8c1af6918eb016fe871b85ccf973..f3d2810ba11c9f3fd11cbdaddf9b50431e70b70b 100644 (file)
@@ -16,6 +16,8 @@ obj-$(CONFIG_SPI_BFIN)                        += spi_bfin5xx.o
 obj-$(CONFIG_SPI_BITBANG)              += spi_bitbang.o
 obj-$(CONFIG_SPI_AU1550)               += au1550_spi.o
 obj-$(CONFIG_SPI_BUTTERFLY)            += spi_butterfly.o
+obj-$(CONFIG_SPI_DESIGNWARE)           += dw_spi.o
+obj-$(CONFIG_SPI_DW_PCI)               += dw_spi_pci.o
 obj-$(CONFIG_SPI_GPIO)                 += spi_gpio.o
 obj-$(CONFIG_SPI_IMX)                  += spi_imx.o
 obj-$(CONFIG_SPI_LM70_LLP)             += spi_lm70llp.o
@@ -30,7 +32,8 @@ obj-$(CONFIG_SPI_MPC52xx)             += mpc52xx_spi.o
 obj-$(CONFIG_SPI_MPC8xxx)              += spi_mpc8xxx.o
 obj-$(CONFIG_SPI_PPC4xx)               += spi_ppc4xx.o
 obj-$(CONFIG_SPI_S3C24XX_GPIO)         += spi_s3c24xx_gpio.o
-obj-$(CONFIG_SPI_S3C24XX)              += spi_s3c24xx.o
+obj-$(CONFIG_SPI_S3C24XX)              += spi_s3c24xx_hw.o
+obj-$(CONFIG_SPI_S3C64XX)              += spi_s3c64xx.o
 obj-$(CONFIG_SPI_TXX9)                 += spi_txx9.o
 obj-$(CONFIG_SPI_XILINX)               += xilinx_spi.o
 obj-$(CONFIG_SPI_XILINX_OF)            += xilinx_spi_of.o
@@ -39,6 +42,11 @@ obj-$(CONFIG_SPI_SH_SCI)             += spi_sh_sci.o
 obj-$(CONFIG_SPI_SH_MSIOF)             += spi_sh_msiof.o
 obj-$(CONFIG_SPI_STMP3XXX)             += spi_stmp.o
 obj-$(CONFIG_SPI_NUC900)               += spi_nuc900.o
+
+# special build for s3c24xx spi driver with fiq support
+spi_s3c24xx_hw-y                       := spi_s3c24xx.o
+spi_s3c24xx_hw-$(CONFIG_SPI_S3C24XX_FIQ) += spi_s3c24xx_fiq.o
+
 #      ... add above this line ...
 
 # SPI protocol drivers (device/link on bus)
index f5b3fdbb1e27c22044df0b8c8759129a98622712..d21c24eaf0a95537baae7f22e783bff8658aa816 100644 (file)
@@ -189,14 +189,14 @@ static void atmel_spi_next_xfer_data(struct spi_master *master,
 
        /* use scratch buffer only when rx or tx data is unspecified */
        if (xfer->rx_buf)
-               *rx_dma = xfer->rx_dma + xfer->len - len;
+               *rx_dma = xfer->rx_dma + xfer->len - *plen;
        else {
                *rx_dma = as->buffer_dma;
                if (len > BUFFER_SIZE)
                        len = BUFFER_SIZE;
        }
        if (xfer->tx_buf)
-               *tx_dma = xfer->tx_dma + xfer->len - len;
+               *tx_dma = xfer->tx_dma + xfer->len - *plen;
        else {
                *tx_dma = as->buffer_dma;
                if (len > BUFFER_SIZE)
@@ -788,7 +788,7 @@ static int __init atmel_spi_probe(struct platform_device *pdev)
        spin_lock_init(&as->lock);
        INIT_LIST_HEAD(&as->queue);
        as->pdev = pdev;
-       as->regs = ioremap(regs->start, (regs->end - regs->start) + 1);
+       as->regs = ioremap(regs->start, resource_size(regs));
        if (!as->regs)
                goto out_free_buffer;
        as->irq = irq;
diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c
new file mode 100644 (file)
index 0000000..31620fa
--- /dev/null
@@ -0,0 +1,944 @@
+/*
+ * dw_spi.c - Designware SPI core controller driver (refer pxa2xx_spi.c)
+ *
+ * Copyright (c) 2009, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/highmem.h>
+#include <linux/delay.h>
+
+#include <linux/spi/dw_spi.h>
+#include <linux/spi/spi.h>
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#endif
+
+#define START_STATE    ((void *)0)
+#define RUNNING_STATE  ((void *)1)
+#define DONE_STATE     ((void *)2)
+#define ERROR_STATE    ((void *)-1)
+
+#define QUEUE_RUNNING  0
+#define QUEUE_STOPPED  1
+
+#define MRST_SPI_DEASSERT      0
+#define MRST_SPI_ASSERT                1
+
+/* Slave spi_dev related */
+struct chip_data {
+       u16 cr0;
+       u8 cs;                  /* chip select pin */
+       u8 n_bytes;             /* current is a 1/2/4 byte op */
+       u8 tmode;               /* TR/TO/RO/EEPROM */
+       u8 type;                /* SPI/SSP/MicroWire */
+
+       u8 poll_mode;           /* 1 means use poll mode */
+
+       u32 dma_width;
+       u32 rx_threshold;
+       u32 tx_threshold;
+       u8 enable_dma;
+       u8 bits_per_word;
+       u16 clk_div;            /* baud rate divider */
+       u32 speed_hz;           /* baud rate */
+       int (*write)(struct dw_spi *dws);
+       int (*read)(struct dw_spi *dws);
+       void (*cs_control)(u32 command);
+};
+
+#ifdef CONFIG_DEBUG_FS
+static int spi_show_regs_open(struct inode *inode, struct file *file)
+{
+       file->private_data = inode->i_private;
+       return 0;
+}
+
+#define SPI_REGS_BUFSIZE       1024
+static ssize_t  spi_show_regs(struct file *file, char __user *user_buf,
+                               size_t count, loff_t *ppos)
+{
+       struct dw_spi *dws;
+       char *buf;
+       u32 len = 0;
+       ssize_t ret;
+
+       dws = file->private_data;
+
+       buf = kzalloc(SPI_REGS_BUFSIZE, GFP_KERNEL);
+       if (!buf)
+               return 0;
+
+       len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+                       "MRST SPI0 registers:\n");
+       len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+                       "=================================\n");
+       len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+                       "CTRL0: \t\t0x%08x\n", dw_readl(dws, ctrl0));
+       len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+                       "CTRL1: \t\t0x%08x\n", dw_readl(dws, ctrl1));
+       len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+                       "SSIENR: \t0x%08x\n", dw_readl(dws, ssienr));
+       len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+                       "SER: \t\t0x%08x\n", dw_readl(dws, ser));
+       len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+                       "BAUDR: \t\t0x%08x\n", dw_readl(dws, baudr));
+       len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+                       "TXFTLR: \t0x%08x\n", dw_readl(dws, txfltr));
+       len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+                       "RXFTLR: \t0x%08x\n", dw_readl(dws, rxfltr));
+       len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+                       "TXFLR: \t\t0x%08x\n", dw_readl(dws, txflr));
+       len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+                       "RXFLR: \t\t0x%08x\n", dw_readl(dws, rxflr));
+       len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+                       "SR: \t\t0x%08x\n", dw_readl(dws, sr));
+       len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+                       "IMR: \t\t0x%08x\n", dw_readl(dws, imr));
+       len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+                       "ISR: \t\t0x%08x\n", dw_readl(dws, isr));
+       len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+                       "DMACR: \t\t0x%08x\n", dw_readl(dws, dmacr));
+       len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+                       "DMATDLR: \t0x%08x\n", dw_readl(dws, dmatdlr));
+       len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+                       "DMARDLR: \t0x%08x\n", dw_readl(dws, dmardlr));
+       len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+                       "=================================\n");
+
+       ret =  simple_read_from_buffer(user_buf, count, ppos, buf, len);
+       kfree(buf);
+       return ret;
+}
+
+static const struct file_operations mrst_spi_regs_ops = {
+       .owner          = THIS_MODULE,
+       .open           = spi_show_regs_open,
+       .read           = spi_show_regs,
+};
+
+static int mrst_spi_debugfs_init(struct dw_spi *dws)
+{
+       dws->debugfs = debugfs_create_dir("mrst_spi", NULL);
+       if (!dws->debugfs)
+               return -ENOMEM;
+
+       debugfs_create_file("registers", S_IFREG | S_IRUGO,
+               dws->debugfs, (void *)dws, &mrst_spi_regs_ops);
+       return 0;
+}
+
+static void mrst_spi_debugfs_remove(struct dw_spi *dws)
+{
+       if (dws->debugfs)
+               debugfs_remove_recursive(dws->debugfs);
+}
+
+#else
+static inline int mrst_spi_debugfs_init(struct dw_spi *dws)
+{
+}
+
+static inline void mrst_spi_debugfs_remove(struct dw_spi *dws)
+{
+}
+#endif /* CONFIG_DEBUG_FS */
+
+static void wait_till_not_busy(struct dw_spi *dws)
+{
+       unsigned long end = jiffies + usecs_to_jiffies(1000);
+
+       while (time_before(jiffies, end)) {
+               if (!(dw_readw(dws, sr) & SR_BUSY))
+                       return;
+       }
+       dev_err(&dws->master->dev,
+               "DW SPI: Stutus keeps busy for 1000us after a read/write!\n");
+}
+
+static void flush(struct dw_spi *dws)
+{
+       while (dw_readw(dws, sr) & SR_RF_NOT_EMPT)
+               dw_readw(dws, dr);
+
+       wait_till_not_busy(dws);
+}
+
+static void null_cs_control(u32 command)
+{
+}
+
+static int null_writer(struct dw_spi *dws)
+{
+       u8 n_bytes = dws->n_bytes;
+
+       if (!(dw_readw(dws, sr) & SR_TF_NOT_FULL)
+               || (dws->tx == dws->tx_end))
+               return 0;
+       dw_writew(dws, dr, 0);
+       dws->tx += n_bytes;
+
+       wait_till_not_busy(dws);
+       return 1;
+}
+
+static int null_reader(struct dw_spi *dws)
+{
+       u8 n_bytes = dws->n_bytes;
+
+       while ((dw_readw(dws, sr) & SR_RF_NOT_EMPT)
+               && (dws->rx < dws->rx_end)) {
+               dw_readw(dws, dr);
+               dws->rx += n_bytes;
+       }
+       wait_till_not_busy(dws);
+       return dws->rx == dws->rx_end;
+}
+
+static int u8_writer(struct dw_spi *dws)
+{
+       if (!(dw_readw(dws, sr) & SR_TF_NOT_FULL)
+               || (dws->tx == dws->tx_end))
+               return 0;
+
+       dw_writew(dws, dr, *(u8 *)(dws->tx));
+       ++dws->tx;
+
+       wait_till_not_busy(dws);
+       return 1;
+}
+
+static int u8_reader(struct dw_spi *dws)
+{
+       while ((dw_readw(dws, sr) & SR_RF_NOT_EMPT)
+               && (dws->rx < dws->rx_end)) {
+               *(u8 *)(dws->rx) = dw_readw(dws, dr);
+               ++dws->rx;
+       }
+
+       wait_till_not_busy(dws);
+       return dws->rx == dws->rx_end;
+}
+
+static int u16_writer(struct dw_spi *dws)
+{
+       if (!(dw_readw(dws, sr) & SR_TF_NOT_FULL)
+               || (dws->tx == dws->tx_end))
+               return 0;
+
+       dw_writew(dws, dr, *(u16 *)(dws->tx));
+       dws->tx += 2;
+
+       wait_till_not_busy(dws);
+       return 1;
+}
+
+static int u16_reader(struct dw_spi *dws)
+{
+       u16 temp;
+
+       while ((dw_readw(dws, sr) & SR_RF_NOT_EMPT)
+               && (dws->rx < dws->rx_end)) {
+               temp = dw_readw(dws, dr);
+               *(u16 *)(dws->rx) = temp;
+               dws->rx += 2;
+       }
+
+       wait_till_not_busy(dws);
+       return dws->rx == dws->rx_end;
+}
+
+static void *next_transfer(struct dw_spi *dws)
+{
+       struct spi_message *msg = dws->cur_msg;
+       struct spi_transfer *trans = dws->cur_transfer;
+
+       /* Move to next transfer */
+       if (trans->transfer_list.next != &msg->transfers) {
+               dws->cur_transfer =
+                       list_entry(trans->transfer_list.next,
+                                       struct spi_transfer,
+                                       transfer_list);
+               return RUNNING_STATE;
+       } else
+               return DONE_STATE;
+}
+
+/*
+ * Note: first step is the protocol driver prepares
+ * a dma-capable memory, and this func just need translate
+ * the virt addr to physical
+ */
+static int map_dma_buffers(struct dw_spi *dws)
+{
+       if (!dws->cur_msg->is_dma_mapped || !dws->dma_inited
+               || !dws->cur_chip->enable_dma)
+               return 0;
+
+       if (dws->cur_transfer->tx_dma)
+               dws->tx_dma = dws->cur_transfer->tx_dma;
+
+       if (dws->cur_transfer->rx_dma)
+               dws->rx_dma = dws->cur_transfer->rx_dma;
+
+       return 1;
+}
+
+/* Caller already set message->status; dma and pio irqs are blocked */
+static void giveback(struct dw_spi *dws)
+{
+       struct spi_transfer *last_transfer;
+       unsigned long flags;
+       struct spi_message *msg;
+
+       spin_lock_irqsave(&dws->lock, flags);
+       msg = dws->cur_msg;
+       dws->cur_msg = NULL;
+       dws->cur_transfer = NULL;
+       dws->prev_chip = dws->cur_chip;
+       dws->cur_chip = NULL;
+       dws->dma_mapped = 0;
+       queue_work(dws->workqueue, &dws->pump_messages);
+       spin_unlock_irqrestore(&dws->lock, flags);
+
+       last_transfer = list_entry(msg->transfers.prev,
+                                       struct spi_transfer,
+                                       transfer_list);
+
+       if (!last_transfer->cs_change)
+               dws->cs_control(MRST_SPI_DEASSERT);
+
+       msg->state = NULL;
+       if (msg->complete)
+               msg->complete(msg->context);
+}
+
+static void int_error_stop(struct dw_spi *dws, const char *msg)
+{
+       /* Stop and reset hw */
+       flush(dws);
+       spi_enable_chip(dws, 0);
+
+       dev_err(&dws->master->dev, "%s\n", msg);
+       dws->cur_msg->state = ERROR_STATE;
+       tasklet_schedule(&dws->pump_transfers);
+}
+
+static void transfer_complete(struct dw_spi *dws)
+{
+       /* Update total byte transfered return count actual bytes read */
+       dws->cur_msg->actual_length += dws->len;
+
+       /* Move to next transfer */
+       dws->cur_msg->state = next_transfer(dws);
+
+       /* Handle end of message */
+       if (dws->cur_msg->state == DONE_STATE) {
+               dws->cur_msg->status = 0;
+               giveback(dws);
+       } else
+               tasklet_schedule(&dws->pump_transfers);
+}
+
+static irqreturn_t interrupt_transfer(struct dw_spi *dws)
+{
+       u16 irq_status, irq_mask = 0x3f;
+
+       irq_status = dw_readw(dws, isr) & irq_mask;
+       /* Error handling */
+       if (irq_status & (SPI_INT_TXOI | SPI_INT_RXOI | SPI_INT_RXUI)) {
+               dw_readw(dws, txoicr);
+               dw_readw(dws, rxoicr);
+               dw_readw(dws, rxuicr);
+               int_error_stop(dws, "interrupt_transfer: fifo overrun");
+               return IRQ_HANDLED;
+       }
+
+       /* INT comes from tx */
+       if (dws->tx && (irq_status & SPI_INT_TXEI)) {
+               while (dws->tx < dws->tx_end)
+                       dws->write(dws);
+
+               if (dws->tx == dws->tx_end) {
+                       spi_mask_intr(dws, SPI_INT_TXEI);
+                       transfer_complete(dws);
+               }
+       }
+
+       /* INT comes from rx */
+       if (dws->rx && (irq_status & SPI_INT_RXFI)) {
+               if (dws->read(dws))
+                       transfer_complete(dws);
+       }
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t dw_spi_irq(int irq, void *dev_id)
+{
+       struct dw_spi *dws = dev_id;
+
+       if (!dws->cur_msg) {
+               spi_mask_intr(dws, SPI_INT_TXEI);
+               /* Never fail */
+               return IRQ_HANDLED;
+       }
+
+       return dws->transfer_handler(dws);
+}
+
+/* Must be called inside pump_transfers() */
+static void poll_transfer(struct dw_spi *dws)
+{
+       if (dws->tx) {
+               while (dws->write(dws))
+                       dws->read(dws);
+       }
+
+       dws->read(dws);
+       transfer_complete(dws);
+}
+
+static void dma_transfer(struct dw_spi *dws, int cs_change)
+{
+}
+
+static void pump_transfers(unsigned long data)
+{
+       struct dw_spi *dws = (struct dw_spi *)data;
+       struct spi_message *message = NULL;
+       struct spi_transfer *transfer = NULL;
+       struct spi_transfer *previous = NULL;
+       struct spi_device *spi = NULL;
+       struct chip_data *chip = NULL;
+       u8 bits = 0;
+       u8 imask = 0;
+       u8 cs_change = 0;
+       u16 clk_div = 0;
+       u32 speed = 0;
+       u32 cr0 = 0;
+
+       /* Get current state information */
+       message = dws->cur_msg;
+       transfer = dws->cur_transfer;
+       chip = dws->cur_chip;
+       spi = message->spi;
+
+       if (message->state == ERROR_STATE) {
+               message->status = -EIO;
+               goto early_exit;
+       }
+
+       /* Handle end of message */
+       if (message->state == DONE_STATE) {
+               message->status = 0;
+               goto early_exit;
+       }
+
+       /* Delay if requested at end of transfer*/
+       if (message->state == RUNNING_STATE) {
+               previous = list_entry(transfer->transfer_list.prev,
+                                       struct spi_transfer,
+                                       transfer_list);
+               if (previous->delay_usecs)
+                       udelay(previous->delay_usecs);
+       }
+
+       dws->n_bytes = chip->n_bytes;
+       dws->dma_width = chip->dma_width;
+       dws->cs_control = chip->cs_control;
+
+       dws->rx_dma = transfer->rx_dma;
+       dws->tx_dma = transfer->tx_dma;
+       dws->tx = (void *)transfer->tx_buf;
+       dws->tx_end = dws->tx + transfer->len;
+       dws->rx = transfer->rx_buf;
+       dws->rx_end = dws->rx + transfer->len;
+       dws->write = dws->tx ? chip->write : null_writer;
+       dws->read = dws->rx ? chip->read : null_reader;
+       dws->cs_change = transfer->cs_change;
+       dws->len = dws->cur_transfer->len;
+       if (chip != dws->prev_chip)
+               cs_change = 1;
+
+       cr0 = chip->cr0;
+
+       /* Handle per transfer options for bpw and speed */
+       if (transfer->speed_hz) {
+               speed = chip->speed_hz;
+
+               if (transfer->speed_hz != speed) {
+                       speed = transfer->speed_hz;
+                       if (speed > dws->max_freq) {
+                               printk(KERN_ERR "MRST SPI0: unsupported"
+                                       "freq: %dHz\n", speed);
+                               message->status = -EIO;
+                               goto early_exit;
+                       }
+
+                       /* clk_div doesn't support odd number */
+                       clk_div = dws->max_freq / speed;
+                       clk_div = (clk_div >> 1) << 1;
+
+                       chip->speed_hz = speed;
+                       chip->clk_div = clk_div;
+               }
+       }
+       if (transfer->bits_per_word) {
+               bits = transfer->bits_per_word;
+
+               switch (bits) {
+               case 8:
+                       dws->n_bytes = 1;
+                       dws->dma_width = 1;
+                       dws->read = (dws->read != null_reader) ?
+                                       u8_reader : null_reader;
+                       dws->write = (dws->write != null_writer) ?
+                                       u8_writer : null_writer;
+                       break;
+               case 16:
+                       dws->n_bytes = 2;
+                       dws->dma_width = 2;
+                       dws->read = (dws->read != null_reader) ?
+                                       u16_reader : null_reader;
+                       dws->write = (dws->write != null_writer) ?
+                                       u16_writer : null_writer;
+                       break;
+               default:
+                       printk(KERN_ERR "MRST SPI0: unsupported bits:"
+                               "%db\n", bits);
+                       message->status = -EIO;
+                       goto early_exit;
+               }
+
+               cr0 = (bits - 1)
+                       | (chip->type << SPI_FRF_OFFSET)
+                       | (spi->mode << SPI_MODE_OFFSET)
+                       | (chip->tmode << SPI_TMOD_OFFSET);
+       }
+       message->state = RUNNING_STATE;
+
+       /* Check if current transfer is a DMA transaction */
+       dws->dma_mapped = map_dma_buffers(dws);
+
+       if (!dws->dma_mapped && !chip->poll_mode) {
+               if (dws->rx)
+                       imask |= SPI_INT_RXFI;
+               if (dws->tx)
+                       imask |= SPI_INT_TXEI;
+               dws->transfer_handler = interrupt_transfer;
+       }
+
+       /*
+        * Reprogram registers only if
+        *      1. chip select changes
+        *      2. clk_div is changed
+        *      3. control value changes
+        */
+       if (dw_readw(dws, ctrl0) != cr0 || cs_change || clk_div) {
+               spi_enable_chip(dws, 0);
+
+               if (dw_readw(dws, ctrl0) != cr0)
+                       dw_writew(dws, ctrl0, cr0);
+
+               /* Set the interrupt mask, for poll mode just diable all int */
+               spi_mask_intr(dws, 0xff);
+               if (!chip->poll_mode)
+                       spi_umask_intr(dws, imask);
+
+               spi_set_clk(dws, clk_div ? clk_div : chip->clk_div);
+               spi_chip_sel(dws, spi->chip_select);
+               spi_enable_chip(dws, 1);
+
+               if (cs_change)
+                       dws->prev_chip = chip;
+       }
+
+       if (dws->dma_mapped)
+               dma_transfer(dws, cs_change);
+
+       if (chip->poll_mode)
+               poll_transfer(dws);
+
+       return;
+
+early_exit:
+       giveback(dws);
+       return;
+}
+
+static void pump_messages(struct work_struct *work)
+{
+       struct dw_spi *dws =
+               container_of(work, struct dw_spi, pump_messages);
+       unsigned long flags;
+
+       /* Lock queue and check for queue work */
+       spin_lock_irqsave(&dws->lock, flags);
+       if (list_empty(&dws->queue) || dws->run == QUEUE_STOPPED) {
+               dws->busy = 0;
+               spin_unlock_irqrestore(&dws->lock, flags);
+               return;
+       }
+
+       /* Make sure we are not already running a message */
+       if (dws->cur_msg) {
+               spin_unlock_irqrestore(&dws->lock, flags);
+               return;
+       }
+
+       /* Extract head of queue */
+       dws->cur_msg = list_entry(dws->queue.next, struct spi_message, queue);
+       list_del_init(&dws->cur_msg->queue);
+
+       /* Initial message state*/
+       dws->cur_msg->state = START_STATE;
+       dws->cur_transfer = list_entry(dws->cur_msg->transfers.next,
+                                               struct spi_transfer,
+                                               transfer_list);
+       dws->cur_chip = spi_get_ctldata(dws->cur_msg->spi);
+
+       /* Mark as busy and launch transfers */
+       tasklet_schedule(&dws->pump_transfers);
+
+       dws->busy = 1;
+       spin_unlock_irqrestore(&dws->lock, flags);
+}
+
+/* spi_device use this to queue in their spi_msg */
+static int dw_spi_transfer(struct spi_device *spi, struct spi_message *msg)
+{
+       struct dw_spi *dws = spi_master_get_devdata(spi->master);
+       unsigned long flags;
+
+       spin_lock_irqsave(&dws->lock, flags);
+
+       if (dws->run == QUEUE_STOPPED) {
+               spin_unlock_irqrestore(&dws->lock, flags);
+               return -ESHUTDOWN;
+       }
+
+       msg->actual_length = 0;
+       msg->status = -EINPROGRESS;
+       msg->state = START_STATE;
+
+       list_add_tail(&msg->queue, &dws->queue);
+
+       if (dws->run == QUEUE_RUNNING && !dws->busy) {
+
+               if (dws->cur_transfer || dws->cur_msg)
+                       queue_work(dws->workqueue,
+                                       &dws->pump_messages);
+               else {
+                       /* If no other data transaction in air, just go */
+                       spin_unlock_irqrestore(&dws->lock, flags);
+                       pump_messages(&dws->pump_messages);
+                       return 0;
+               }
+       }
+
+       spin_unlock_irqrestore(&dws->lock, flags);
+       return 0;
+}
+
+/* This may be called twice for each spi dev */
+static int dw_spi_setup(struct spi_device *spi)
+{
+       struct dw_spi_chip *chip_info = NULL;
+       struct chip_data *chip;
+
+       if (spi->bits_per_word != 8 && spi->bits_per_word != 16)
+               return -EINVAL;
+
+       /* Only alloc on first setup */
+       chip = spi_get_ctldata(spi);
+       if (!chip) {
+               chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
+               if (!chip)
+                       return -ENOMEM;
+
+               chip->cs_control = null_cs_control;
+               chip->enable_dma = 0;
+       }
+
+       /*
+        * Protocol drivers may change the chip settings, so...
+        * if chip_info exists, use it
+        */
+       chip_info = spi->controller_data;
+
+       /* chip_info doesn't always exist */
+       if (chip_info) {
+               if (chip_info->cs_control)
+                       chip->cs_control = chip_info->cs_control;
+
+               chip->poll_mode = chip_info->poll_mode;
+               chip->type = chip_info->type;
+
+               chip->rx_threshold = 0;
+               chip->tx_threshold = 0;
+
+               chip->enable_dma = chip_info->enable_dma;
+       }
+
+       if (spi->bits_per_word <= 8) {
+               chip->n_bytes = 1;
+               chip->dma_width = 1;
+               chip->read = u8_reader;
+               chip->write = u8_writer;
+       } else if (spi->bits_per_word <= 16) {
+               chip->n_bytes = 2;
+               chip->dma_width = 2;
+               chip->read = u16_reader;
+               chip->write = u16_writer;
+       } else {
+               /* Never take >16b case for MRST SPIC */
+               dev_err(&spi->dev, "invalid wordsize\n");
+               return -EINVAL;
+       }
+       chip->bits_per_word = spi->bits_per_word;
+
+       chip->speed_hz = spi->max_speed_hz;
+       if (chip->speed_hz)
+               chip->clk_div = 25000000 / chip->speed_hz;
+       else
+               chip->clk_div = 8;      /* default value */
+
+       chip->tmode = 0; /* Tx & Rx */
+       /* Default SPI mode is SCPOL = 0, SCPH = 0 */
+       chip->cr0 = (chip->bits_per_word - 1)
+                       | (chip->type << SPI_FRF_OFFSET)
+                       | (spi->mode  << SPI_MODE_OFFSET)
+                       | (chip->tmode << SPI_TMOD_OFFSET);
+
+       spi_set_ctldata(spi, chip);
+       return 0;
+}
+
+static void dw_spi_cleanup(struct spi_device *spi)
+{
+       struct chip_data *chip = spi_get_ctldata(spi);
+       kfree(chip);
+}
+
+static int __init init_queue(struct dw_spi *dws)
+{
+       INIT_LIST_HEAD(&dws->queue);
+       spin_lock_init(&dws->lock);
+
+       dws->run = QUEUE_STOPPED;
+       dws->busy = 0;
+
+       tasklet_init(&dws->pump_transfers,
+                       pump_transfers, (unsigned long)dws);
+
+       INIT_WORK(&dws->pump_messages, pump_messages);
+       dws->workqueue = create_singlethread_workqueue(
+                                       dev_name(dws->master->dev.parent));
+       if (dws->workqueue == NULL)
+               return -EBUSY;
+
+       return 0;
+}
+
+static int start_queue(struct dw_spi *dws)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&dws->lock, flags);
+
+       if (dws->run == QUEUE_RUNNING || dws->busy) {
+               spin_unlock_irqrestore(&dws->lock, flags);
+               return -EBUSY;
+       }
+
+       dws->run = QUEUE_RUNNING;
+       dws->cur_msg = NULL;
+       dws->cur_transfer = NULL;
+       dws->cur_chip = NULL;
+       dws->prev_chip = NULL;
+       spin_unlock_irqrestore(&dws->lock, flags);
+
+       queue_work(dws->workqueue, &dws->pump_messages);
+
+       return 0;
+}
+
+static int stop_queue(struct dw_spi *dws)
+{
+       unsigned long flags;
+       unsigned limit = 50;
+       int status = 0;
+
+       spin_lock_irqsave(&dws->lock, flags);
+       dws->run = QUEUE_STOPPED;
+       while (!list_empty(&dws->queue) && dws->busy && limit--) {
+               spin_unlock_irqrestore(&dws->lock, flags);
+               msleep(10);
+               spin_lock_irqsave(&dws->lock, flags);
+       }
+
+       if (!list_empty(&dws->queue) || dws->busy)
+               status = -EBUSY;
+       spin_unlock_irqrestore(&dws->lock, flags);
+
+       return status;
+}
+
+static int destroy_queue(struct dw_spi *dws)
+{
+       int status;
+
+       status = stop_queue(dws);
+       if (status != 0)
+               return status;
+       destroy_workqueue(dws->workqueue);
+       return 0;
+}
+
+/* Restart the controller, disable all interrupts, clean rx fifo */
+static void spi_hw_init(struct dw_spi *dws)
+{
+       spi_enable_chip(dws, 0);
+       spi_mask_intr(dws, 0xff);
+       spi_enable_chip(dws, 1);
+       flush(dws);
+}
+
+int __devinit dw_spi_add_host(struct dw_spi *dws)
+{
+       struct spi_master *master;
+       int ret;
+
+       BUG_ON(dws == NULL);
+
+       master = spi_alloc_master(dws->parent_dev, 0);
+       if (!master) {
+               ret = -ENOMEM;
+               goto exit;
+       }
+
+       dws->master = master;
+       dws->type = SSI_MOTO_SPI;
+       dws->prev_chip = NULL;
+       dws->dma_inited = 0;
+       dws->dma_addr = (dma_addr_t)(dws->paddr + 0x60);
+
+       ret = request_irq(dws->irq, dw_spi_irq, 0,
+                       "dw_spi", dws);
+       if (ret < 0) {
+               dev_err(&master->dev, "can not get IRQ\n");
+               goto err_free_master;
+       }
+
+       master->mode_bits = SPI_CPOL | SPI_CPHA;
+       master->bus_num = dws->bus_num;
+       master->num_chipselect = dws->num_cs;
+       master->cleanup = dw_spi_cleanup;
+       master->setup = dw_spi_setup;
+       master->transfer = dw_spi_transfer;
+
+       dws->dma_inited = 0;
+
+       /* Basic HW init */
+       spi_hw_init(dws);
+
+       /* Initial and start queue */
+       ret = init_queue(dws);
+       if (ret) {
+               dev_err(&master->dev, "problem initializing queue\n");
+               goto err_diable_hw;
+       }
+       ret = start_queue(dws);
+       if (ret) {
+               dev_err(&master->dev, "problem starting queue\n");
+               goto err_diable_hw;
+       }
+
+       spi_master_set_devdata(master, dws);
+       ret = spi_register_master(master);
+       if (ret) {
+               dev_err(&master->dev, "problem registering spi master\n");
+               goto err_queue_alloc;
+       }
+
+       mrst_spi_debugfs_init(dws);
+       return 0;
+
+err_queue_alloc:
+       destroy_queue(dws);
+err_diable_hw:
+       spi_enable_chip(dws, 0);
+       free_irq(dws->irq, dws);
+err_free_master:
+       spi_master_put(master);
+exit:
+       return ret;
+}
+EXPORT_SYMBOL(dw_spi_add_host);
+
+void __devexit dw_spi_remove_host(struct dw_spi *dws)
+{
+       int status = 0;
+
+       if (!dws)
+               return;
+       mrst_spi_debugfs_remove(dws);
+
+       /* Remove the queue */
+       status = destroy_queue(dws);
+       if (status != 0)
+               dev_err(&dws->master->dev, "dw_spi_remove: workqueue will not "
+                       "complete, message memory not freed\n");
+
+       spi_enable_chip(dws, 0);
+       /* Disable clk */
+       spi_set_clk(dws, 0);
+       free_irq(dws->irq, dws);
+
+       /* Disconnect from the SPI framework */
+       spi_unregister_master(dws->master);
+}
+
+int dw_spi_suspend_host(struct dw_spi *dws)
+{
+       int ret = 0;
+
+       ret = stop_queue(dws);
+       if (ret)
+               return ret;
+       spi_enable_chip(dws, 0);
+       spi_set_clk(dws, 0);
+       return ret;
+}
+EXPORT_SYMBOL(dw_spi_suspend_host);
+
+int dw_spi_resume_host(struct dw_spi *dws)
+{
+       int ret;
+
+       spi_hw_init(dws);
+       ret = start_queue(dws);
+       if (ret)
+               dev_err(&dws->master->dev, "fail to start queue (%d)\n", ret);
+       return ret;
+}
+EXPORT_SYMBOL(dw_spi_resume_host);
+
+MODULE_AUTHOR("Feng Tang <feng.tang@intel.com>");
+MODULE_DESCRIPTION("Driver for DesignWare SPI controller core");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/spi/dw_spi_pci.c b/drivers/spi/dw_spi_pci.c
new file mode 100644 (file)
index 0000000..34ba691
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * mrst_spi_pci.c - PCI interface driver for DW SPI Core
+ *
+ * Copyright (c) 2009, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/spi/dw_spi.h>
+#include <linux/spi/spi.h>
+
+#define DRIVER_NAME "dw_spi_pci"
+
+struct dw_spi_pci {
+       struct pci_dev          *pdev;
+       struct dw_spi           dws;
+};
+
+static int __devinit spi_pci_probe(struct pci_dev *pdev,
+       const struct pci_device_id *ent)
+{
+       struct dw_spi_pci *dwpci;
+       struct dw_spi *dws;
+       int pci_bar = 0;
+       int ret;
+
+       printk(KERN_INFO "DW: found PCI SPI controller(ID: %04x:%04x)\n",
+               pdev->vendor, pdev->device);
+
+       ret = pci_enable_device(pdev);
+       if (ret)
+               return ret;
+
+       dwpci = kzalloc(sizeof(struct dw_spi_pci), GFP_KERNEL);
+       if (!dwpci) {
+               ret = -ENOMEM;
+               goto err_disable;
+       }
+
+       dwpci->pdev = pdev;
+       dws = &dwpci->dws;
+
+       /* Get basic io resource and map it */
+       dws->paddr = pci_resource_start(pdev, pci_bar);
+       dws->iolen = pci_resource_len(pdev, pci_bar);
+
+       ret = pci_request_region(pdev, pci_bar, dev_name(&pdev->dev));
+       if (ret)
+               goto err_kfree;
+
+       dws->regs = ioremap_nocache((unsigned long)dws->paddr,
+                               pci_resource_len(pdev, pci_bar));
+       if (!dws->regs) {
+               ret = -ENOMEM;
+               goto err_release_reg;
+       }
+
+       dws->parent_dev = &pdev->dev;
+       dws->bus_num = 0;
+       dws->num_cs = 4;
+       dws->max_freq = 25000000;       /* for Moorestwon */
+       dws->irq = pdev->irq;
+
+       ret = dw_spi_add_host(dws);
+       if (ret)
+               goto err_unmap;
+
+       /* PCI hook and SPI hook use the same drv data */
+       pci_set_drvdata(pdev, dwpci);
+       return 0;
+
+err_unmap:
+       iounmap(dws->regs);
+err_release_reg:
+       pci_release_region(pdev, pci_bar);
+err_kfree:
+       kfree(dwpci);
+err_disable:
+       pci_disable_device(pdev);
+       return ret;
+}
+
+static void __devexit spi_pci_remove(struct pci_dev *pdev)
+{
+       struct dw_spi_pci *dwpci = pci_get_drvdata(pdev);
+
+       pci_set_drvdata(pdev, NULL);
+       iounmap(dwpci->dws.regs);
+       pci_release_region(pdev, 0);
+       kfree(dwpci);
+       pci_disable_device(pdev);
+}
+
+#ifdef CONFIG_PM
+static int spi_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       struct dw_spi_pci *dwpci = pci_get_drvdata(pdev);
+       int ret;
+
+       ret = dw_spi_suspend_host(&dwpci->dws);
+       if (ret)
+               return ret;
+       pci_save_state(pdev);
+       pci_disable_device(pdev);
+       pci_set_power_state(pdev, pci_choose_state(pdev, state));
+       return ret;
+}
+
+static int spi_resume(struct pci_dev *pdev)
+{
+       struct dw_spi_pci *dwpci = pci_get_drvdata(pdev);
+       int ret;
+
+       pci_set_power_state(pdev, PCI_D0);
+       pci_restore_state(pdev);
+       ret = pci_enable_device(pdev);
+       if (ret)
+               return ret;
+       return dw_spi_resume_host(&dwpci->dws);
+}
+#else
+#define spi_suspend    NULL
+#define spi_resume     NULL
+#endif
+
+static const struct pci_device_id pci_ids[] __devinitdata = {
+       /* Intel Moorestown platform SPI controller 0 */
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0800) },
+       {},
+};
+
+static struct pci_driver dw_spi_driver = {
+       .name =         DRIVER_NAME,
+       .id_table =     pci_ids,
+       .probe =        spi_pci_probe,
+       .remove =       __devexit_p(spi_pci_remove),
+       .suspend =      spi_suspend,
+       .resume =       spi_resume,
+};
+
+static int __init mrst_spi_init(void)
+{
+       return pci_register_driver(&dw_spi_driver);
+}
+
+static void __exit mrst_spi_exit(void)
+{
+       pci_unregister_driver(&dw_spi_driver);
+}
+
+module_init(mrst_spi_init);
+module_exit(mrst_spi_exit);
+
+MODULE_AUTHOR("Feng Tang <feng.tang@intel.com>");
+MODULE_DESCRIPTION("PCI interface driver for DW SPI Core");
+MODULE_LICENSE("GPL v2");
index 73e24ef5a2f961fa41c0d3ee81dc03143e768cd5..1d41058bbab2a4227dc663f388e3e026e1ce84b3 100644 (file)
@@ -1294,7 +1294,7 @@ static int __init bfin_spi_probe(struct platform_device *pdev)
                goto out_error_get_res;
        }
 
-       drv_data->regs_base = ioremap(res->start, (res->end - res->start + 1));
+       drv_data->regs_base = ioremap(res->start, resource_size(res));
        if (drv_data->regs_base == NULL) {
                dev_err(dev, "Cannot map IO\n");
                status = -ENXIO;
index e9390d747bfcf35e018747fcfc6a1b2e529ef486..1fb2a6ea328cfcff9ce8ec3a03700f3bec729947 100644 (file)
@@ -1013,7 +1013,7 @@ mpc8xxx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq)
 
        init_completion(&mpc8xxx_spi->done);
 
-       mpc8xxx_spi->base = ioremap(mem->start, mem->end - mem->start + 1);
+       mpc8xxx_spi->base = ioremap(mem->start, resource_size(mem));
        if (mpc8xxx_spi->base == NULL) {
                ret = -ENOMEM;
                goto err_ioremap;
index 276591569c8bce421f1c2c9c4b0ed94385d22f44..c010733877ae73f8dc57c211c97163d0301a34d6 100644 (file)
@@ -1,7 +1,7 @@
 /* linux/drivers/spi/spi_s3c24xx.c
  *
  * Copyright (c) 2006 Ben Dooks
- * Copyright (c) 2006 Simtec Electronics
+ * Copyright 2006-2009 Simtec Electronics
  *     Ben Dooks <ben@simtec.co.uk>
  *
  * This program is free software; you can redistribute it and/or modify
 #include <plat/regs-spi.h>
 #include <mach/spi.h>
 
+#include <plat/fiq.h>
+#include <asm/fiq.h>
+
+#include "spi_s3c24xx_fiq.h"
+
 /**
  * s3c24xx_spi_devstate - per device data
  * @hz: Last frequency calculated for @sppre field.
@@ -42,6 +47,13 @@ struct s3c24xx_spi_devstate {
        u8              sppre;
 };
 
+enum spi_fiq_mode {
+       FIQ_MODE_NONE   = 0,
+       FIQ_MODE_TX     = 1,
+       FIQ_MODE_RX     = 2,
+       FIQ_MODE_TXRX   = 3,
+};
+
 struct s3c24xx_spi {
        /* bitbang has to be first */
        struct spi_bitbang       bitbang;
@@ -52,6 +64,11 @@ struct s3c24xx_spi {
        int                      len;
        int                      count;
 
+       struct fiq_handler       fiq_handler;
+       enum spi_fiq_mode        fiq_mode;
+       unsigned char            fiq_inuse;
+       unsigned char            fiq_claimed;
+
        void                    (*set_cs)(struct s3c2410_spi_info *spi,
                                          int cs, int pol);
 
@@ -67,6 +84,7 @@ struct s3c24xx_spi {
        struct s3c2410_spi_info *pdata;
 };
 
+
 #define SPCON_DEFAULT (S3C2410_SPCON_MSTR | S3C2410_SPCON_SMOD_INT)
 #define SPPIN_DEFAULT (S3C2410_SPPIN_KEEP)
 
@@ -127,7 +145,7 @@ static int s3c24xx_spi_update_state(struct spi_device *spi,
        }
 
        if (spi->mode != cs->mode) {
-               u8 spcon = SPCON_DEFAULT;
+               u8 spcon = SPCON_DEFAULT | S3C2410_SPCON_ENSCK;
 
                if (spi->mode & SPI_CPHA)
                        spcon |= S3C2410_SPCON_CPHA_FMTB;
@@ -214,13 +232,196 @@ static inline unsigned int hw_txbyte(struct s3c24xx_spi *hw, int count)
        return hw->tx ? hw->tx[count] : 0;
 }
 
+#ifdef CONFIG_SPI_S3C24XX_FIQ
+/* Support for FIQ based pseudo-DMA to improve the transfer speed.
+ *
+ * This code uses the assembly helper in spi_s3c24xx_spi.S which is
+ * used by the FIQ core to move data between main memory and the peripheral
+ * block. Since this is code running on the processor, there is no problem
+ * with cache coherency of the buffers, so we can use any buffer we like.
+ */
+
+/**
+ * struct spi_fiq_code - FIQ code and header
+ * @length: The length of the code fragment, excluding this header.
+ * @ack_offset: The offset from @data to the word to place the IRQ ACK bit at.
+ * @data: The code itself to install as a FIQ handler.
+ */
+struct spi_fiq_code {
+       u32     length;
+       u32     ack_offset;
+       u8      data[0];
+};
+
+extern struct spi_fiq_code s3c24xx_spi_fiq_txrx;
+extern struct spi_fiq_code s3c24xx_spi_fiq_tx;
+extern struct spi_fiq_code s3c24xx_spi_fiq_rx;
+
+/**
+ * ack_bit - turn IRQ into IRQ acknowledgement bit
+ * @irq: The interrupt number
+ *
+ * Returns the bit to write to the interrupt acknowledge register.
+ */
+static inline u32 ack_bit(unsigned int irq)
+{
+       return 1 << (irq - IRQ_EINT0);
+}
+
+/**
+ * s3c24xx_spi_tryfiq - attempt to claim and setup FIQ for transfer
+ * @hw: The hardware state.
+ *
+ * Claim the FIQ handler (only one can be active at any one time) and
+ * then setup the correct transfer code for this transfer.
+ *
+ * This call updates all the necessary state information if sucessful,
+ * so the caller does not need to do anything more than start the transfer
+ * as normal, since the IRQ will have been re-routed to the FIQ handler.
+*/
+void s3c24xx_spi_tryfiq(struct s3c24xx_spi *hw)
+{
+       struct pt_regs regs;
+       enum spi_fiq_mode mode;
+       struct spi_fiq_code *code;
+       int ret;
+
+       if (!hw->fiq_claimed) {
+               /* try and claim fiq if we haven't got it, and if not
+                * then return and simply use another transfer method */
+
+               ret = claim_fiq(&hw->fiq_handler);
+               if (ret)
+                       return;
+       }
+
+       if (hw->tx && !hw->rx)
+               mode = FIQ_MODE_TX;
+       else if (hw->rx && !hw->tx)
+               mode = FIQ_MODE_RX;
+       else
+               mode = FIQ_MODE_TXRX;
+
+       regs.uregs[fiq_rspi] = (long)hw->regs;
+       regs.uregs[fiq_rrx]  = (long)hw->rx;
+       regs.uregs[fiq_rtx]  = (long)hw->tx + 1;
+       regs.uregs[fiq_rcount] = hw->len - 1;
+       regs.uregs[fiq_rirq] = (long)S3C24XX_VA_IRQ;
+
+       set_fiq_regs(&regs);
+
+       if (hw->fiq_mode != mode) {
+               u32 *ack_ptr;
+
+               hw->fiq_mode = mode;
+
+               switch (mode) {
+               case FIQ_MODE_TX:
+                       code = &s3c24xx_spi_fiq_tx;
+                       break;
+               case FIQ_MODE_RX:
+                       code = &s3c24xx_spi_fiq_rx;
+                       break;
+               case FIQ_MODE_TXRX:
+                       code = &s3c24xx_spi_fiq_txrx;
+                       break;
+               default:
+                       code = NULL;
+               }
+
+               BUG_ON(!code);
+
+               ack_ptr = (u32 *)&code->data[code->ack_offset];
+               *ack_ptr = ack_bit(hw->irq);
+
+               set_fiq_handler(&code->data, code->length);
+       }
+
+       s3c24xx_set_fiq(hw->irq, true);
+
+       hw->fiq_mode = mode;
+       hw->fiq_inuse = 1;
+}
+
+/**
+ * s3c24xx_spi_fiqop - FIQ core code callback
+ * @pw: Data registered with the handler
+ * @release: Whether this is a release or a return.
+ *
+ * Called by the FIQ code when another module wants to use the FIQ, so
+ * return whether we are currently using this or not and then update our
+ * internal state.
+ */
+static int s3c24xx_spi_fiqop(void *pw, int release)
+{
+       struct s3c24xx_spi *hw = pw;
+       int ret = 0;
+
+       if (release) {
+               if (hw->fiq_inuse)
+                       ret = -EBUSY;
+
+               /* note, we do not need to unroute the FIQ, as the FIQ
+                * vector code de-routes it to signal the end of transfer */
+
+               hw->fiq_mode = FIQ_MODE_NONE;
+               hw->fiq_claimed = 0;
+       } else {
+               hw->fiq_claimed = 1;
+       }
+
+       return ret;
+}
+
+/**
+ * s3c24xx_spi_initfiq - setup the information for the FIQ core
+ * @hw: The hardware state.
+ *
+ * Setup the fiq_handler block to pass to the FIQ core.
+ */
+static inline void s3c24xx_spi_initfiq(struct s3c24xx_spi *hw)
+{
+       hw->fiq_handler.dev_id = hw;
+       hw->fiq_handler.name = dev_name(hw->dev);
+       hw->fiq_handler.fiq_op = s3c24xx_spi_fiqop;
+}
+
+/**
+ * s3c24xx_spi_usefiq - return if we should be using FIQ.
+ * @hw: The hardware state.
+ *
+ * Return true if the platform data specifies whether this channel is
+ * allowed to use the FIQ.
+ */
+static inline bool s3c24xx_spi_usefiq(struct s3c24xx_spi *hw)
+{
+       return hw->pdata->use_fiq;
+}
+
+/**
+ * s3c24xx_spi_usingfiq - return if channel is using FIQ
+ * @spi: The hardware state.
+ *
+ * Return whether the channel is currently using the FIQ (separate from
+ * whether the FIQ is claimed).
+ */
+static inline bool s3c24xx_spi_usingfiq(struct s3c24xx_spi *spi)
+{
+       return spi->fiq_inuse;
+}
+#else
+
+static inline void s3c24xx_spi_initfiq(struct s3c24xx_spi *s) { }
+static inline void s3c24xx_spi_tryfiq(struct s3c24xx_spi *s) { }
+static inline bool s3c24xx_spi_usefiq(struct s3c24xx_spi *s) { return false; }
+static inline bool s3c24xx_spi_usingfiq(struct s3c24xx_spi *s) { return false; }
+
+#endif /* CONFIG_SPI_S3C24XX_FIQ */
+
 static int s3c24xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
 {
        struct s3c24xx_spi *hw = to_hw(spi);
 
-       dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n",
-               t->tx_buf, t->rx_buf, t->len);
-
        hw->tx = t->tx_buf;
        hw->rx = t->rx_buf;
        hw->len = t->len;
@@ -228,11 +429,14 @@ static int s3c24xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
 
        init_completion(&hw->done);
 
+       hw->fiq_inuse = 0;
+       if (s3c24xx_spi_usefiq(hw) && t->len >= 3)
+               s3c24xx_spi_tryfiq(hw);
+
        /* send the first byte */
        writeb(hw_txbyte(hw, 0), hw->regs + S3C2410_SPTDAT);
 
        wait_for_completion(&hw->done);
-
        return hw->count;
 }
 
@@ -254,17 +458,27 @@ static irqreturn_t s3c24xx_spi_irq(int irq, void *dev)
                goto irq_done;
        }
 
-       hw->count++;
+       if (!s3c24xx_spi_usingfiq(hw)) {
+               hw->count++;
 
-       if (hw->rx)
-               hw->rx[count] = readb(hw->regs + S3C2410_SPRDAT);
+               if (hw->rx)
+                       hw->rx[count] = readb(hw->regs + S3C2410_SPRDAT);
 
-       count++;
+               count++;
+
+               if (count < hw->len)
+                       writeb(hw_txbyte(hw, count), hw->regs + S3C2410_SPTDAT);
+               else
+                       complete(&hw->done);
+       } else {
+               hw->count = hw->len;
+               hw->fiq_inuse = 0;
+
+               if (hw->rx)
+                       hw->rx[hw->len-1] = readb(hw->regs + S3C2410_SPRDAT);
 
-       if (count < hw->len)
-               writeb(hw_txbyte(hw, count), hw->regs + S3C2410_SPTDAT);
-       else
                complete(&hw->done);
+       }
 
  irq_done:
        return IRQ_HANDLED;
@@ -322,6 +536,10 @@ static int __init s3c24xx_spi_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, hw);
        init_completion(&hw->done);
 
+       /* initialise fiq handler */
+
+       s3c24xx_spi_initfiq(hw);
+
        /* setup the master state. */
 
        /* the spi->mode bits understood by this driver: */
diff --git a/drivers/spi/spi_s3c24xx_fiq.S b/drivers/spi/spi_s3c24xx_fiq.S
new file mode 100644 (file)
index 0000000..3793cae
--- /dev/null
@@ -0,0 +1,116 @@
+/* linux/drivers/spi/spi_s3c24xx_fiq.S
+ *
+ * Copyright 2009 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C24XX SPI - FIQ pseudo-DMA transfer code
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+#include <mach/map.h>
+#include <mach/regs-irq.h>
+#include <plat/regs-spi.h>
+
+#include "spi_s3c24xx_fiq.h"
+
+       .text
+
+       @ entry to these routines is as follows, with the register names
+       @ defined in fiq.h so that they can be shared with the C files which
+       @ setup the calling registers.
+       @
+       @ fiq_rirq      The base of the IRQ registers to find S3C2410_SRCPND
+       @ fiq_rtmp      Temporary register to hold tx/rx data
+       @ fiq_rspi      The base of the SPI register block
+       @ fiq_rtx       The tx buffer pointer
+       @ fiq_rrx       The rx buffer pointer
+       @ fiq_rcount    The number of bytes to move
+
+       @ each entry starts with a word entry of how long it is
+       @ and an offset to the irq acknowledgment word
+
+ENTRY(s3c24xx_spi_fiq_rx)
+s3c24xx_spi_fix_rx:
+       .word   fiq_rx_end - fiq_rx_start
+       .word   fiq_rx_irq_ack - fiq_rx_start
+fiq_rx_start:
+       ldr     fiq_rtmp, fiq_rx_irq_ack
+       str     fiq_rtmp, [ fiq_rirq, # S3C2410_SRCPND - S3C24XX_VA_IRQ ]
+
+       ldrb    fiq_rtmp, [ fiq_rspi, #  S3C2410_SPRDAT ]
+       strb    fiq_rtmp, [ fiq_rrx ], #1
+
+       mov     fiq_rtmp, #0xff
+       strb    fiq_rtmp, [ fiq_rspi, # S3C2410_SPTDAT ]
+
+       subs    fiq_rcount, fiq_rcount, #1
+       subnes  pc, lr, #4              @@ return, still have work to do
+
+       @@ set IRQ controller so that next op will trigger IRQ
+       mov     fiq_rtmp, #0
+       str     fiq_rtmp, [ fiq_rirq, # S3C2410_INTMOD  - S3C24XX_VA_IRQ ]
+       subs    pc, lr, #4
+
+fiq_rx_irq_ack:
+       .word   0
+fiq_rx_end:
+
+ENTRY(s3c24xx_spi_fiq_txrx)
+s3c24xx_spi_fiq_txrx:
+       .word   fiq_txrx_end - fiq_txrx_start
+       .word   fiq_txrx_irq_ack - fiq_txrx_start
+fiq_txrx_start:
+
+       ldrb    fiq_rtmp, [ fiq_rspi, #  S3C2410_SPRDAT ]
+       strb    fiq_rtmp, [ fiq_rrx ], #1
+
+       ldr     fiq_rtmp, fiq_txrx_irq_ack
+       str     fiq_rtmp, [ fiq_rirq, # S3C2410_SRCPND - S3C24XX_VA_IRQ ]
+
+       ldrb    fiq_rtmp, [ fiq_rtx ], #1
+       strb    fiq_rtmp, [ fiq_rspi, # S3C2410_SPTDAT ]
+
+       subs    fiq_rcount, fiq_rcount, #1
+       subnes  pc, lr, #4              @@ return, still have work to do
+
+       mov     fiq_rtmp, #0
+       str     fiq_rtmp, [ fiq_rirq, # S3C2410_INTMOD  - S3C24XX_VA_IRQ ]
+       subs    pc, lr, #4
+
+fiq_txrx_irq_ack:
+       .word   0
+
+fiq_txrx_end:
+
+ENTRY(s3c24xx_spi_fiq_tx)
+s3c24xx_spi_fix_tx:
+       .word   fiq_tx_end - fiq_tx_start
+       .word   fiq_tx_irq_ack - fiq_tx_start
+fiq_tx_start:
+       ldrb    fiq_rtmp, [ fiq_rspi, #  S3C2410_SPRDAT ]
+
+       ldr     fiq_rtmp, fiq_tx_irq_ack
+       str     fiq_rtmp, [ fiq_rirq, # S3C2410_SRCPND - S3C24XX_VA_IRQ ]
+
+       ldrb    fiq_rtmp, [ fiq_rtx ], #1
+       strb    fiq_rtmp, [ fiq_rspi, # S3C2410_SPTDAT ]
+
+       subs    fiq_rcount, fiq_rcount, #1
+       subnes  pc, lr, #4              @@ return, still have work to do
+
+       mov     fiq_rtmp, #0
+       str     fiq_rtmp, [ fiq_rirq, # S3C2410_INTMOD  - S3C24XX_VA_IRQ ]
+       subs    pc, lr, #4
+
+fiq_tx_irq_ack:
+       .word   0
+
+fiq_tx_end:
+
+       .end
diff --git a/drivers/spi/spi_s3c24xx_fiq.h b/drivers/spi/spi_s3c24xx_fiq.h
new file mode 100644 (file)
index 0000000..a5950bb
--- /dev/null
@@ -0,0 +1,26 @@
+/* linux/drivers/spi/spi_s3c24xx_fiq.h
+ *
+ * Copyright 2009 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C24XX SPI - FIQ pseudo-DMA transfer support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+/* We have R8 through R13 to play with */
+
+#ifdef __ASSEMBLY__
+#define __REG_NR(x)     r##x
+#else
+#define __REG_NR(x)     (x)
+#endif
+
+#define fiq_rspi       __REG_NR(8)
+#define fiq_rtmp       __REG_NR(9)
+#define fiq_rrx                __REG_NR(10)
+#define fiq_rtx                __REG_NR(11)
+#define fiq_rcount     __REG_NR(12)
+#define fiq_rirq       __REG_NR(13)
diff --git a/drivers/spi/spi_s3c64xx.c b/drivers/spi/spi_s3c64xx.c
new file mode 100644 (file)
index 0000000..88a456d
--- /dev/null
@@ -0,0 +1,1196 @@
+/* linux/drivers/spi/spi_s3c64xx.c
+ *
+ * Copyright (C) 2009 Samsung Electronics Ltd.
+ *     Jaswinder Singh <jassi.brar@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+
+#include <mach/dma.h>
+#include <plat/spi.h>
+
+/* Registers and bit-fields */
+
+#define S3C64XX_SPI_CH_CFG             0x00
+#define S3C64XX_SPI_CLK_CFG            0x04
+#define S3C64XX_SPI_MODE_CFG   0x08
+#define S3C64XX_SPI_SLAVE_SEL  0x0C
+#define S3C64XX_SPI_INT_EN             0x10
+#define S3C64XX_SPI_STATUS             0x14
+#define S3C64XX_SPI_TX_DATA            0x18
+#define S3C64XX_SPI_RX_DATA            0x1C
+#define S3C64XX_SPI_PACKET_CNT 0x20
+#define S3C64XX_SPI_PENDING_CLR        0x24
+#define S3C64XX_SPI_SWAP_CFG   0x28
+#define S3C64XX_SPI_FB_CLK             0x2C
+
+#define S3C64XX_SPI_CH_HS_EN           (1<<6)  /* High Speed Enable */
+#define S3C64XX_SPI_CH_SW_RST          (1<<5)
+#define S3C64XX_SPI_CH_SLAVE           (1<<4)
+#define S3C64XX_SPI_CPOL_L             (1<<3)
+#define S3C64XX_SPI_CPHA_B             (1<<2)
+#define S3C64XX_SPI_CH_RXCH_ON         (1<<1)
+#define S3C64XX_SPI_CH_TXCH_ON         (1<<0)
+
+#define S3C64XX_SPI_CLKSEL_SRCMSK      (3<<9)
+#define S3C64XX_SPI_CLKSEL_SRCSHFT     9
+#define S3C64XX_SPI_ENCLK_ENABLE       (1<<8)
+#define S3C64XX_SPI_PSR_MASK           0xff
+
+#define S3C64XX_SPI_MODE_CH_TSZ_BYTE           (0<<29)
+#define S3C64XX_SPI_MODE_CH_TSZ_HALFWORD       (1<<29)
+#define S3C64XX_SPI_MODE_CH_TSZ_WORD           (2<<29)
+#define S3C64XX_SPI_MODE_CH_TSZ_MASK           (3<<29)
+#define S3C64XX_SPI_MODE_BUS_TSZ_BYTE          (0<<17)
+#define S3C64XX_SPI_MODE_BUS_TSZ_HALFWORD      (1<<17)
+#define S3C64XX_SPI_MODE_BUS_TSZ_WORD          (2<<17)
+#define S3C64XX_SPI_MODE_BUS_TSZ_MASK          (3<<17)
+#define S3C64XX_SPI_MODE_RXDMA_ON              (1<<2)
+#define S3C64XX_SPI_MODE_TXDMA_ON              (1<<1)
+#define S3C64XX_SPI_MODE_4BURST                        (1<<0)
+
+#define S3C64XX_SPI_SLAVE_AUTO                 (1<<1)
+#define S3C64XX_SPI_SLAVE_SIG_INACT            (1<<0)
+
+#define S3C64XX_SPI_ACT(c) writel(0, (c)->regs + S3C64XX_SPI_SLAVE_SEL)
+
+#define S3C64XX_SPI_DEACT(c) writel(S3C64XX_SPI_SLAVE_SIG_INACT, \
+                                       (c)->regs + S3C64XX_SPI_SLAVE_SEL)
+
+#define S3C64XX_SPI_INT_TRAILING_EN            (1<<6)
+#define S3C64XX_SPI_INT_RX_OVERRUN_EN          (1<<5)
+#define S3C64XX_SPI_INT_RX_UNDERRUN_EN         (1<<4)
+#define S3C64XX_SPI_INT_TX_OVERRUN_EN          (1<<3)
+#define S3C64XX_SPI_INT_TX_UNDERRUN_EN         (1<<2)
+#define S3C64XX_SPI_INT_RX_FIFORDY_EN          (1<<1)
+#define S3C64XX_SPI_INT_TX_FIFORDY_EN          (1<<0)
+
+#define S3C64XX_SPI_ST_RX_OVERRUN_ERR          (1<<5)
+#define S3C64XX_SPI_ST_RX_UNDERRUN_ERR (1<<4)
+#define S3C64XX_SPI_ST_TX_OVERRUN_ERR          (1<<3)
+#define S3C64XX_SPI_ST_TX_UNDERRUN_ERR (1<<2)
+#define S3C64XX_SPI_ST_RX_FIFORDY              (1<<1)
+#define S3C64XX_SPI_ST_TX_FIFORDY              (1<<0)
+
+#define S3C64XX_SPI_PACKET_CNT_EN              (1<<16)
+
+#define S3C64XX_SPI_PND_TX_UNDERRUN_CLR                (1<<4)
+#define S3C64XX_SPI_PND_TX_OVERRUN_CLR         (1<<3)
+#define S3C64XX_SPI_PND_RX_UNDERRUN_CLR                (1<<2)
+#define S3C64XX_SPI_PND_RX_OVERRUN_CLR         (1<<1)
+#define S3C64XX_SPI_PND_TRAILING_CLR           (1<<0)
+
+#define S3C64XX_SPI_SWAP_RX_HALF_WORD          (1<<7)
+#define S3C64XX_SPI_SWAP_RX_BYTE               (1<<6)
+#define S3C64XX_SPI_SWAP_RX_BIT                        (1<<5)
+#define S3C64XX_SPI_SWAP_RX_EN                 (1<<4)
+#define S3C64XX_SPI_SWAP_TX_HALF_WORD          (1<<3)
+#define S3C64XX_SPI_SWAP_TX_BYTE               (1<<2)
+#define S3C64XX_SPI_SWAP_TX_BIT                        (1<<1)
+#define S3C64XX_SPI_SWAP_TX_EN                 (1<<0)
+
+#define S3C64XX_SPI_FBCLK_MSK          (3<<0)
+
+#define S3C64XX_SPI_ST_TRLCNTZ(v, i) ((((v) >> (i)->rx_lvl_offset) & \
+                                       (((i)->fifo_lvl_mask + 1))) \
+                                       ? 1 : 0)
+
+#define S3C64XX_SPI_ST_TX_DONE(v, i) ((((v) >> (i)->rx_lvl_offset) & \
+                                       (((i)->fifo_lvl_mask + 1) << 1)) \
+                                       ? 1 : 0)
+#define TX_FIFO_LVL(v, i) (((v) >> 6) & (i)->fifo_lvl_mask)
+#define RX_FIFO_LVL(v, i) (((v) >> (i)->rx_lvl_offset) & (i)->fifo_lvl_mask)
+
+#define S3C64XX_SPI_MAX_TRAILCNT       0x3ff
+#define S3C64XX_SPI_TRAILCNT_OFF       19
+
+#define S3C64XX_SPI_TRAILCNT           S3C64XX_SPI_MAX_TRAILCNT
+
+#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
+
+#define SUSPND    (1<<0)
+#define SPIBUSY   (1<<1)
+#define RXBUSY    (1<<2)
+#define TXBUSY    (1<<3)
+
+/**
+ * struct s3c64xx_spi_driver_data - Runtime info holder for SPI driver.
+ * @clk: Pointer to the spi clock.
+ * @master: Pointer to the SPI Protocol master.
+ * @workqueue: Work queue for the SPI xfer requests.
+ * @cntrlr_info: Platform specific data for the controller this driver manages.
+ * @tgl_spi: Pointer to the last CS left untoggled by the cs_change hint.
+ * @work: Work
+ * @queue: To log SPI xfer requests.
+ * @lock: Controller specific lock.
+ * @state: Set of FLAGS to indicate status.
+ * @rx_dmach: Controller's DMA channel for Rx.
+ * @tx_dmach: Controller's DMA channel for Tx.
+ * @sfr_start: BUS address of SPI controller regs.
+ * @regs: Pointer to ioremap'ed controller registers.
+ * @xfer_completion: To indicate completion of xfer task.
+ * @cur_mode: Stores the active configuration of the controller.
+ * @cur_bpw: Stores the active bits per word settings.
+ * @cur_speed: Stores the active xfer clock speed.
+ */
+struct s3c64xx_spi_driver_data {
+       void __iomem                    *regs;
+       struct clk                      *clk;
+       struct platform_device          *pdev;
+       struct spi_master               *master;
+       struct workqueue_struct         *workqueue;
+       struct s3c64xx_spi_cntrlr_info  *cntrlr_info;
+       struct spi_device               *tgl_spi;
+       struct work_struct              work;
+       struct list_head                queue;
+       spinlock_t                      lock;
+       enum dma_ch                     rx_dmach;
+       enum dma_ch                     tx_dmach;
+       unsigned long                   sfr_start;
+       struct completion               xfer_completion;
+       unsigned                        state;
+       unsigned                        cur_mode, cur_bpw;
+       unsigned                        cur_speed;
+};
+
+static struct s3c2410_dma_client s3c64xx_spi_dma_client = {
+       .name = "samsung-spi-dma",
+};
+
+static void flush_fifo(struct s3c64xx_spi_driver_data *sdd)
+{
+       struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
+       void __iomem *regs = sdd->regs;
+       unsigned long loops;
+       u32 val;
+
+       writel(0, regs + S3C64XX_SPI_PACKET_CNT);
+
+       val = readl(regs + S3C64XX_SPI_CH_CFG);
+       val |= S3C64XX_SPI_CH_SW_RST;
+       val &= ~S3C64XX_SPI_CH_HS_EN;
+       writel(val, regs + S3C64XX_SPI_CH_CFG);
+
+       /* Flush TxFIFO*/
+       loops = msecs_to_loops(1);
+       do {
+               val = readl(regs + S3C64XX_SPI_STATUS);
+       } while (TX_FIFO_LVL(val, sci) && loops--);
+
+       /* Flush RxFIFO*/
+       loops = msecs_to_loops(1);
+       do {
+               val = readl(regs + S3C64XX_SPI_STATUS);
+               if (RX_FIFO_LVL(val, sci))
+                       readl(regs + S3C64XX_SPI_RX_DATA);
+               else
+                       break;
+       } while (loops--);
+
+       val = readl(regs + S3C64XX_SPI_CH_CFG);
+       val &= ~S3C64XX_SPI_CH_SW_RST;
+       writel(val, regs + S3C64XX_SPI_CH_CFG);
+
+       val = readl(regs + S3C64XX_SPI_MODE_CFG);
+       val &= ~(S3C64XX_SPI_MODE_TXDMA_ON | S3C64XX_SPI_MODE_RXDMA_ON);
+       writel(val, regs + S3C64XX_SPI_MODE_CFG);
+
+       val = readl(regs + S3C64XX_SPI_CH_CFG);
+       val &= ~(S3C64XX_SPI_CH_RXCH_ON | S3C64XX_SPI_CH_TXCH_ON);
+       writel(val, regs + S3C64XX_SPI_CH_CFG);
+}
+
+static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
+                               struct spi_device *spi,
+                               struct spi_transfer *xfer, int dma_mode)
+{
+       struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
+       void __iomem *regs = sdd->regs;
+       u32 modecfg, chcfg;
+
+       modecfg = readl(regs + S3C64XX_SPI_MODE_CFG);
+       modecfg &= ~(S3C64XX_SPI_MODE_TXDMA_ON | S3C64XX_SPI_MODE_RXDMA_ON);
+
+       chcfg = readl(regs + S3C64XX_SPI_CH_CFG);
+       chcfg &= ~S3C64XX_SPI_CH_TXCH_ON;
+
+       if (dma_mode) {
+               chcfg &= ~S3C64XX_SPI_CH_RXCH_ON;
+       } else {
+               /* Always shift in data in FIFO, even if xfer is Tx only,
+                * this helps setting PCKT_CNT value for generating clocks
+                * as exactly needed.
+                */
+               chcfg |= S3C64XX_SPI_CH_RXCH_ON;
+               writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff)
+                                       | S3C64XX_SPI_PACKET_CNT_EN,
+                                       regs + S3C64XX_SPI_PACKET_CNT);
+       }
+
+       if (xfer->tx_buf != NULL) {
+               sdd->state |= TXBUSY;
+               chcfg |= S3C64XX_SPI_CH_TXCH_ON;
+               if (dma_mode) {
+                       modecfg |= S3C64XX_SPI_MODE_TXDMA_ON;
+                       s3c2410_dma_config(sdd->tx_dmach, 1);
+                       s3c2410_dma_enqueue(sdd->tx_dmach, (void *)sdd,
+                                               xfer->tx_dma, xfer->len);
+                       s3c2410_dma_ctrl(sdd->tx_dmach, S3C2410_DMAOP_START);
+               } else {
+                       unsigned char *buf = (unsigned char *) xfer->tx_buf;
+                       int i = 0;
+                       while (i < xfer->len)
+                               writeb(buf[i++], regs + S3C64XX_SPI_TX_DATA);
+               }
+       }
+
+       if (xfer->rx_buf != NULL) {
+               sdd->state |= RXBUSY;
+
+               if (sci->high_speed && sdd->cur_speed >= 30000000UL
+                                       && !(sdd->cur_mode & SPI_CPHA))
+                       chcfg |= S3C64XX_SPI_CH_HS_EN;
+
+               if (dma_mode) {
+                       modecfg |= S3C64XX_SPI_MODE_RXDMA_ON;
+                       chcfg |= S3C64XX_SPI_CH_RXCH_ON;
+                       writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff)
+                                       | S3C64XX_SPI_PACKET_CNT_EN,
+                                       regs + S3C64XX_SPI_PACKET_CNT);
+                       s3c2410_dma_config(sdd->rx_dmach, 1);
+                       s3c2410_dma_enqueue(sdd->rx_dmach, (void *)sdd,
+                                               xfer->rx_dma, xfer->len);
+                       s3c2410_dma_ctrl(sdd->rx_dmach, S3C2410_DMAOP_START);
+               }
+       }
+
+       writel(modecfg, regs + S3C64XX_SPI_MODE_CFG);
+       writel(chcfg, regs + S3C64XX_SPI_CH_CFG);
+}
+
+static inline void enable_cs(struct s3c64xx_spi_driver_data *sdd,
+                                               struct spi_device *spi)
+{
+       struct s3c64xx_spi_csinfo *cs;
+
+       if (sdd->tgl_spi != NULL) { /* If last device toggled after mssg */
+               if (sdd->tgl_spi != spi) { /* if last mssg on diff device */
+                       /* Deselect the last toggled device */
+                       cs = sdd->tgl_spi->controller_data;
+                       cs->set_level(spi->mode & SPI_CS_HIGH ? 0 : 1);
+               }
+               sdd->tgl_spi = NULL;
+       }
+
+       cs = spi->controller_data;
+       cs->set_level(spi->mode & SPI_CS_HIGH ? 1 : 0);
+}
+
+static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd,
+                               struct spi_transfer *xfer, int dma_mode)
+{
+       struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
+       void __iomem *regs = sdd->regs;
+       unsigned long val;
+       int ms;
+
+       /* millisecs to xfer 'len' bytes @ 'cur_speed' */
+       ms = xfer->len * 8 * 1000 / sdd->cur_speed;
+       ms += 5; /* some tolerance */
+
+       if (dma_mode) {
+               val = msecs_to_jiffies(ms) + 10;
+               val = wait_for_completion_timeout(&sdd->xfer_completion, val);
+       } else {
+               val = msecs_to_loops(ms);
+               do {
+                       val = readl(regs + S3C64XX_SPI_STATUS);
+               } while (RX_FIFO_LVL(val, sci) < xfer->len && --val);
+       }
+
+       if (!val)
+               return -EIO;
+
+       if (dma_mode) {
+               u32 status;
+
+               /*
+                * DmaTx returns after simply writing data in the FIFO,
+                * w/o waiting for real transmission on the bus to finish.
+                * DmaRx returns only after Dma read data from FIFO which
+                * needs bus transmission to finish, so we don't worry if
+                * Xfer involved Rx(with or without Tx).
+                */
+               if (xfer->rx_buf == NULL) {
+                       val = msecs_to_loops(10);
+                       status = readl(regs + S3C64XX_SPI_STATUS);
+                       while ((TX_FIFO_LVL(status, sci)
+                               || !S3C64XX_SPI_ST_TX_DONE(status, sci))
+                                       && --val) {
+                               cpu_relax();
+                               status = readl(regs + S3C64XX_SPI_STATUS);
+                       }
+
+                       if (!val)
+                               return -EIO;
+               }
+       } else {
+               unsigned char *buf;
+               int i;
+
+               /* If it was only Tx */
+               if (xfer->rx_buf == NULL) {
+                       sdd->state &= ~TXBUSY;
+                       return 0;
+               }
+
+               i = 0;
+               buf = xfer->rx_buf;
+               while (i < xfer->len)
+                       buf[i++] = readb(regs + S3C64XX_SPI_RX_DATA);
+
+               sdd->state &= ~RXBUSY;
+       }
+
+       return 0;
+}
+
+static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd,
+                                               struct spi_device *spi)
+{
+       struct s3c64xx_spi_csinfo *cs = spi->controller_data;
+
+       if (sdd->tgl_spi == spi)
+               sdd->tgl_spi = NULL;
+
+       cs->set_level(spi->mode & SPI_CS_HIGH ? 0 : 1);
+}
+
+static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
+{
+       struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
+       void __iomem *regs = sdd->regs;
+       u32 val;
+
+       /* Disable Clock */
+       val = readl(regs + S3C64XX_SPI_CLK_CFG);
+       val &= ~S3C64XX_SPI_ENCLK_ENABLE;
+       writel(val, regs + S3C64XX_SPI_CLK_CFG);
+
+       /* Set Polarity and Phase */
+       val = readl(regs + S3C64XX_SPI_CH_CFG);
+       val &= ~(S3C64XX_SPI_CH_SLAVE |
+                       S3C64XX_SPI_CPOL_L |
+                       S3C64XX_SPI_CPHA_B);
+
+       if (sdd->cur_mode & SPI_CPOL)
+               val |= S3C64XX_SPI_CPOL_L;
+
+       if (sdd->cur_mode & SPI_CPHA)
+               val |= S3C64XX_SPI_CPHA_B;
+
+       writel(val, regs + S3C64XX_SPI_CH_CFG);
+
+       /* Set Channel & DMA Mode */
+       val = readl(regs + S3C64XX_SPI_MODE_CFG);
+       val &= ~(S3C64XX_SPI_MODE_BUS_TSZ_MASK
+                       | S3C64XX_SPI_MODE_CH_TSZ_MASK);
+
+       switch (sdd->cur_bpw) {
+       case 32:
+               val |= S3C64XX_SPI_MODE_BUS_TSZ_WORD;
+               break;
+       case 16:
+               val |= S3C64XX_SPI_MODE_BUS_TSZ_HALFWORD;
+               break;
+       default:
+               val |= S3C64XX_SPI_MODE_BUS_TSZ_BYTE;
+               break;
+       }
+       val |= S3C64XX_SPI_MODE_CH_TSZ_BYTE; /* Always 8bits wide */
+
+       writel(val, regs + S3C64XX_SPI_MODE_CFG);
+
+       /* Configure Clock */
+       val = readl(regs + S3C64XX_SPI_CLK_CFG);
+       val &= ~S3C64XX_SPI_PSR_MASK;
+       val |= ((clk_get_rate(sci->src_clk) / sdd->cur_speed / 2 - 1)
+                       & S3C64XX_SPI_PSR_MASK);
+       writel(val, regs + S3C64XX_SPI_CLK_CFG);
+
+       /* Enable Clock */
+       val = readl(regs + S3C64XX_SPI_CLK_CFG);
+       val |= S3C64XX_SPI_ENCLK_ENABLE;
+       writel(val, regs + S3C64XX_SPI_CLK_CFG);
+}
+
+void s3c64xx_spi_dma_rxcb(struct s3c2410_dma_chan *chan, void *buf_id,
+                               int size, enum s3c2410_dma_buffresult res)
+{
+       struct s3c64xx_spi_driver_data *sdd = buf_id;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sdd->lock, flags);
+
+       if (res == S3C2410_RES_OK)
+               sdd->state &= ~RXBUSY;
+       else
+               dev_err(&sdd->pdev->dev, "DmaAbrtRx-%d\n", size);
+
+       /* If the other done */
+       if (!(sdd->state & TXBUSY))
+               complete(&sdd->xfer_completion);
+
+       spin_unlock_irqrestore(&sdd->lock, flags);
+}
+
+void s3c64xx_spi_dma_txcb(struct s3c2410_dma_chan *chan, void *buf_id,
+                               int size, enum s3c2410_dma_buffresult res)
+{
+       struct s3c64xx_spi_driver_data *sdd = buf_id;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sdd->lock, flags);
+
+       if (res == S3C2410_RES_OK)
+               sdd->state &= ~TXBUSY;
+       else
+               dev_err(&sdd->pdev->dev, "DmaAbrtTx-%d \n", size);
+
+       /* If the other done */
+       if (!(sdd->state & RXBUSY))
+               complete(&sdd->xfer_completion);
+
+       spin_unlock_irqrestore(&sdd->lock, flags);
+}
+
+#define XFER_DMAADDR_INVALID DMA_BIT_MASK(32)
+
+static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd,
+                                               struct spi_message *msg)
+{
+       struct device *dev = &sdd->pdev->dev;
+       struct spi_transfer *xfer;
+
+       if (msg->is_dma_mapped)
+               return 0;
+
+       /* First mark all xfer unmapped */
+       list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+               xfer->rx_dma = XFER_DMAADDR_INVALID;
+               xfer->tx_dma = XFER_DMAADDR_INVALID;
+       }
+
+       /* Map until end or first fail */
+       list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+
+               if (xfer->tx_buf != NULL) {
+                       xfer->tx_dma = dma_map_single(dev, xfer->tx_buf,
+                                               xfer->len, DMA_TO_DEVICE);
+                       if (dma_mapping_error(dev, xfer->tx_dma)) {
+                               dev_err(dev, "dma_map_single Tx failed\n");
+                               xfer->tx_dma = XFER_DMAADDR_INVALID;
+                               return -ENOMEM;
+                       }
+               }
+
+               if (xfer->rx_buf != NULL) {
+                       xfer->rx_dma = dma_map_single(dev, xfer->rx_buf,
+                                               xfer->len, DMA_FROM_DEVICE);
+                       if (dma_mapping_error(dev, xfer->rx_dma)) {
+                               dev_err(dev, "dma_map_single Rx failed\n");
+                               dma_unmap_single(dev, xfer->tx_dma,
+                                               xfer->len, DMA_TO_DEVICE);
+                               xfer->tx_dma = XFER_DMAADDR_INVALID;
+                               xfer->rx_dma = XFER_DMAADDR_INVALID;
+                               return -ENOMEM;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd,
+                                               struct spi_message *msg)
+{
+       struct device *dev = &sdd->pdev->dev;
+       struct spi_transfer *xfer;
+
+       if (msg->is_dma_mapped)
+               return;
+
+       list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+
+               if (xfer->rx_buf != NULL
+                               && xfer->rx_dma != XFER_DMAADDR_INVALID)
+                       dma_unmap_single(dev, xfer->rx_dma,
+                                               xfer->len, DMA_FROM_DEVICE);
+
+               if (xfer->tx_buf != NULL
+                               && xfer->tx_dma != XFER_DMAADDR_INVALID)
+                       dma_unmap_single(dev, xfer->tx_dma,
+                                               xfer->len, DMA_TO_DEVICE);
+       }
+}
+
+static void handle_msg(struct s3c64xx_spi_driver_data *sdd,
+                                       struct spi_message *msg)
+{
+       struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
+       struct spi_device *spi = msg->spi;
+       struct s3c64xx_spi_csinfo *cs = spi->controller_data;
+       struct spi_transfer *xfer;
+       int status = 0, cs_toggle = 0;
+       u32 speed;
+       u8 bpw;
+
+       /* If Master's(controller) state differs from that needed by Slave */
+       if (sdd->cur_speed != spi->max_speed_hz
+                       || sdd->cur_mode != spi->mode
+                       || sdd->cur_bpw != spi->bits_per_word) {
+               sdd->cur_bpw = spi->bits_per_word;
+               sdd->cur_speed = spi->max_speed_hz;
+               sdd->cur_mode = spi->mode;
+               s3c64xx_spi_config(sdd);
+       }
+
+       /* Map all the transfers if needed */
+       if (s3c64xx_spi_map_mssg(sdd, msg)) {
+               dev_err(&spi->dev,
+                       "Xfer: Unable to map message buffers!\n");
+               status = -ENOMEM;
+               goto out;
+       }
+
+       /* Configure feedback delay */
+       writel(cs->fb_delay & 0x3, sdd->regs + S3C64XX_SPI_FB_CLK);
+
+       list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+
+               unsigned long flags;
+               int use_dma;
+
+               INIT_COMPLETION(sdd->xfer_completion);
+
+               /* Only BPW and Speed may change across transfers */
+               bpw = xfer->bits_per_word ? : spi->bits_per_word;
+               speed = xfer->speed_hz ? : spi->max_speed_hz;
+
+               if (bpw != sdd->cur_bpw || speed != sdd->cur_speed) {
+                       sdd->cur_bpw = bpw;
+                       sdd->cur_speed = speed;
+                       s3c64xx_spi_config(sdd);
+               }
+
+               /* Polling method for xfers not bigger than FIFO capacity */
+               if (xfer->len <= ((sci->fifo_lvl_mask >> 1) + 1))
+                       use_dma = 0;
+               else
+                       use_dma = 1;
+
+               spin_lock_irqsave(&sdd->lock, flags);
+
+               /* Pending only which is to be done */
+               sdd->state &= ~RXBUSY;
+               sdd->state &= ~TXBUSY;
+
+               enable_datapath(sdd, spi, xfer, use_dma);
+
+               /* Slave Select */
+               enable_cs(sdd, spi);
+
+               /* Start the signals */
+               S3C64XX_SPI_ACT(sdd);
+
+               spin_unlock_irqrestore(&sdd->lock, flags);
+
+               status = wait_for_xfer(sdd, xfer, use_dma);
+
+               /* Quiese the signals */
+               S3C64XX_SPI_DEACT(sdd);
+
+               if (status) {
+                       dev_err(&spi->dev, "I/O Error: \
+                               rx-%d tx-%d res:rx-%c tx-%c len-%d\n",
+                               xfer->rx_buf ? 1 : 0, xfer->tx_buf ? 1 : 0,
+                               (sdd->state & RXBUSY) ? 'f' : 'p',
+                               (sdd->state & TXBUSY) ? 'f' : 'p',
+                               xfer->len);
+
+                       if (use_dma) {
+                               if (xfer->tx_buf != NULL
+                                               && (sdd->state & TXBUSY))
+                                       s3c2410_dma_ctrl(sdd->tx_dmach,
+                                                       S3C2410_DMAOP_FLUSH);
+                               if (xfer->rx_buf != NULL
+                                               && (sdd->state & RXBUSY))
+                                       s3c2410_dma_ctrl(sdd->rx_dmach,
+                                                       S3C2410_DMAOP_FLUSH);
+                       }
+
+                       goto out;
+               }
+
+               if (xfer->delay_usecs)
+                       udelay(xfer->delay_usecs);
+
+               if (xfer->cs_change) {
+                       /* Hint that the next mssg is gonna be
+                          for the same device */
+                       if (list_is_last(&xfer->transfer_list,
+                                               &msg->transfers))
+                               cs_toggle = 1;
+                       else
+                               disable_cs(sdd, spi);
+               }
+
+               msg->actual_length += xfer->len;
+
+               flush_fifo(sdd);
+       }
+
+out:
+       if (!cs_toggle || status)
+               disable_cs(sdd, spi);
+       else
+               sdd->tgl_spi = spi;
+
+       s3c64xx_spi_unmap_mssg(sdd, msg);
+
+       msg->status = status;
+
+       if (msg->complete)
+               msg->complete(msg->context);
+}
+
+static int acquire_dma(struct s3c64xx_spi_driver_data *sdd)
+{
+       if (s3c2410_dma_request(sdd->rx_dmach,
+                                       &s3c64xx_spi_dma_client, NULL) < 0) {
+               dev_err(&sdd->pdev->dev, "cannot get RxDMA\n");
+               return 0;
+       }
+       s3c2410_dma_set_buffdone_fn(sdd->rx_dmach, s3c64xx_spi_dma_rxcb);
+       s3c2410_dma_devconfig(sdd->rx_dmach, S3C2410_DMASRC_HW,
+                                       sdd->sfr_start + S3C64XX_SPI_RX_DATA);
+
+       if (s3c2410_dma_request(sdd->tx_dmach,
+                                       &s3c64xx_spi_dma_client, NULL) < 0) {
+               dev_err(&sdd->pdev->dev, "cannot get TxDMA\n");
+               s3c2410_dma_free(sdd->rx_dmach, &s3c64xx_spi_dma_client);
+               return 0;
+       }
+       s3c2410_dma_set_buffdone_fn(sdd->tx_dmach, s3c64xx_spi_dma_txcb);
+       s3c2410_dma_devconfig(sdd->tx_dmach, S3C2410_DMASRC_MEM,
+                                       sdd->sfr_start + S3C64XX_SPI_TX_DATA);
+
+       return 1;
+}
+
+static void s3c64xx_spi_work(struct work_struct *work)
+{
+       struct s3c64xx_spi_driver_data *sdd = container_of(work,
+                                       struct s3c64xx_spi_driver_data, work);
+       unsigned long flags;
+
+       /* Acquire DMA channels */
+       while (!acquire_dma(sdd))
+               msleep(10);
+
+       spin_lock_irqsave(&sdd->lock, flags);
+
+       while (!list_empty(&sdd->queue)
+                               && !(sdd->state & SUSPND)) {
+
+               struct spi_message *msg;
+
+               msg = container_of(sdd->queue.next, struct spi_message, queue);
+
+               list_del_init(&msg->queue);
+
+               /* Set Xfer busy flag */
+               sdd->state |= SPIBUSY;
+
+               spin_unlock_irqrestore(&sdd->lock, flags);
+
+               handle_msg(sdd, msg);
+
+               spin_lock_irqsave(&sdd->lock, flags);
+
+               sdd->state &= ~SPIBUSY;
+       }
+
+       spin_unlock_irqrestore(&sdd->lock, flags);
+
+       /* Free DMA channels */
+       s3c2410_dma_free(sdd->tx_dmach, &s3c64xx_spi_dma_client);
+       s3c2410_dma_free(sdd->rx_dmach, &s3c64xx_spi_dma_client);
+}
+
+static int s3c64xx_spi_transfer(struct spi_device *spi,
+                                               struct spi_message *msg)
+{
+       struct s3c64xx_spi_driver_data *sdd;
+       unsigned long flags;
+
+       sdd = spi_master_get_devdata(spi->master);
+
+       spin_lock_irqsave(&sdd->lock, flags);
+
+       if (sdd->state & SUSPND) {
+               spin_unlock_irqrestore(&sdd->lock, flags);
+               return -ESHUTDOWN;
+       }
+
+       msg->status = -EINPROGRESS;
+       msg->actual_length = 0;
+
+       list_add_tail(&msg->queue, &sdd->queue);
+
+       queue_work(sdd->workqueue, &sdd->work);
+
+       spin_unlock_irqrestore(&sdd->lock, flags);
+
+       return 0;
+}
+
+/*
+ * Here we only check the validity of requested configuration
+ * and save the configuration in a local data-structure.
+ * The controller is actually configured only just before we
+ * get a message to transfer.
+ */
+static int s3c64xx_spi_setup(struct spi_device *spi)
+{
+       struct s3c64xx_spi_csinfo *cs = spi->controller_data;
+       struct s3c64xx_spi_driver_data *sdd;
+       struct s3c64xx_spi_cntrlr_info *sci;
+       struct spi_message *msg;
+       u32 psr, speed;
+       unsigned long flags;
+       int err = 0;
+
+       if (cs == NULL || cs->set_level == NULL) {
+               dev_err(&spi->dev, "No CS for SPI(%d)\n", spi->chip_select);
+               return -ENODEV;
+       }
+
+       sdd = spi_master_get_devdata(spi->master);
+       sci = sdd->cntrlr_info;
+
+       spin_lock_irqsave(&sdd->lock, flags);
+
+       list_for_each_entry(msg, &sdd->queue, queue) {
+               /* Is some mssg is already queued for this device */
+               if (msg->spi == spi) {
+                       dev_err(&spi->dev,
+                               "setup: attempt while mssg in queue!\n");
+                       spin_unlock_irqrestore(&sdd->lock, flags);
+                       return -EBUSY;
+               }
+       }
+
+       if (sdd->state & SUSPND) {
+               spin_unlock_irqrestore(&sdd->lock, flags);
+               dev_err(&spi->dev,
+                       "setup: SPI-%d not active!\n", spi->master->bus_num);
+               return -ESHUTDOWN;
+       }
+
+       spin_unlock_irqrestore(&sdd->lock, flags);
+
+       if (spi->bits_per_word != 8
+                       && spi->bits_per_word != 16
+                       && spi->bits_per_word != 32) {
+               dev_err(&spi->dev, "setup: %dbits/wrd not supported!\n",
+                                                       spi->bits_per_word);
+               err = -EINVAL;
+               goto setup_exit;
+       }
+
+       /* Check if we can provide the requested rate */
+       speed = clk_get_rate(sci->src_clk) / 2 / (0 + 1); /* Max possible */
+
+       if (spi->max_speed_hz > speed)
+               spi->max_speed_hz = speed;
+
+       psr = clk_get_rate(sci->src_clk) / 2 / spi->max_speed_hz - 1;
+       psr &= S3C64XX_SPI_PSR_MASK;
+       if (psr == S3C64XX_SPI_PSR_MASK)
+               psr--;
+
+       speed = clk_get_rate(sci->src_clk) / 2 / (psr + 1);
+       if (spi->max_speed_hz < speed) {
+               if (psr+1 < S3C64XX_SPI_PSR_MASK) {
+                       psr++;
+               } else {
+                       err = -EINVAL;
+                       goto setup_exit;
+               }
+       }
+
+       speed = clk_get_rate(sci->src_clk) / 2 / (psr + 1);
+       if (spi->max_speed_hz >= speed)
+               spi->max_speed_hz = speed;
+       else
+               err = -EINVAL;
+
+setup_exit:
+
+       /* setup() returns with device de-selected */
+       disable_cs(sdd, spi);
+
+       return err;
+}
+
+static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel)
+{
+       struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
+       void __iomem *regs = sdd->regs;
+       unsigned int val;
+
+       sdd->cur_speed = 0;
+
+       S3C64XX_SPI_DEACT(sdd);
+
+       /* Disable Interrupts - we use Polling if not DMA mode */
+       writel(0, regs + S3C64XX_SPI_INT_EN);
+
+       writel(sci->src_clk_nr << S3C64XX_SPI_CLKSEL_SRCSHFT,
+                               regs + S3C64XX_SPI_CLK_CFG);
+       writel(0, regs + S3C64XX_SPI_MODE_CFG);
+       writel(0, regs + S3C64XX_SPI_PACKET_CNT);
+
+       /* Clear any irq pending bits */
+       writel(readl(regs + S3C64XX_SPI_PENDING_CLR),
+                               regs + S3C64XX_SPI_PENDING_CLR);
+
+       writel(0, regs + S3C64XX_SPI_SWAP_CFG);
+
+       val = readl(regs + S3C64XX_SPI_MODE_CFG);
+       val &= ~S3C64XX_SPI_MODE_4BURST;
+       val &= ~(S3C64XX_SPI_MAX_TRAILCNT << S3C64XX_SPI_TRAILCNT_OFF);
+       val |= (S3C64XX_SPI_TRAILCNT << S3C64XX_SPI_TRAILCNT_OFF);
+       writel(val, regs + S3C64XX_SPI_MODE_CFG);
+
+       flush_fifo(sdd);
+}
+
+static int __init s3c64xx_spi_probe(struct platform_device *pdev)
+{
+       struct resource *mem_res, *dmatx_res, *dmarx_res;
+       struct s3c64xx_spi_driver_data *sdd;
+       struct s3c64xx_spi_cntrlr_info *sci;
+       struct spi_master *master;
+       int ret;
+
+       if (pdev->id < 0) {
+               dev_err(&pdev->dev,
+                               "Invalid platform device id-%d\n", pdev->id);
+               return -ENODEV;
+       }
+
+       if (pdev->dev.platform_data == NULL) {
+               dev_err(&pdev->dev, "platform_data missing!\n");
+               return -ENODEV;
+       }
+
+       /* Check for availability of necessary resource */
+
+       dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+       if (dmatx_res == NULL) {
+               dev_err(&pdev->dev, "Unable to get SPI-Tx dma resource\n");
+               return -ENXIO;
+       }
+
+       dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+       if (dmarx_res == NULL) {
+               dev_err(&pdev->dev, "Unable to get SPI-Rx dma resource\n");
+               return -ENXIO;
+       }
+
+       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (mem_res == NULL) {
+               dev_err(&pdev->dev, "Unable to get SPI MEM resource\n");
+               return -ENXIO;
+       }
+
+       master = spi_alloc_master(&pdev->dev,
+                               sizeof(struct s3c64xx_spi_driver_data));
+       if (master == NULL) {
+               dev_err(&pdev->dev, "Unable to allocate SPI Master\n");
+               return -ENOMEM;
+       }
+
+       sci = pdev->dev.platform_data;
+
+       platform_set_drvdata(pdev, master);
+
+       sdd = spi_master_get_devdata(master);
+       sdd->master = master;
+       sdd->cntrlr_info = sci;
+       sdd->pdev = pdev;
+       sdd->sfr_start = mem_res->start;
+       sdd->tx_dmach = dmatx_res->start;
+       sdd->rx_dmach = dmarx_res->start;
+
+       sdd->cur_bpw = 8;
+
+       master->bus_num = pdev->id;
+       master->setup = s3c64xx_spi_setup;
+       master->transfer = s3c64xx_spi_transfer;
+       master->num_chipselect = sci->num_cs;
+       master->dma_alignment = 8;
+       /* the spi->mode bits understood by this driver: */
+       master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+
+       if (request_mem_region(mem_res->start,
+                       resource_size(mem_res), pdev->name) == NULL) {
+               dev_err(&pdev->dev, "Req mem region failed\n");
+               ret = -ENXIO;
+               goto err0;
+       }
+
+       sdd->regs = ioremap(mem_res->start, resource_size(mem_res));
+       if (sdd->regs == NULL) {
+               dev_err(&pdev->dev, "Unable to remap IO\n");
+               ret = -ENXIO;
+               goto err1;
+       }
+
+       if (sci->cfg_gpio == NULL || sci->cfg_gpio(pdev)) {
+               dev_err(&pdev->dev, "Unable to config gpio\n");
+               ret = -EBUSY;
+               goto err2;
+       }
+
+       /* Setup clocks */
+       sdd->clk = clk_get(&pdev->dev, "spi");
+       if (IS_ERR(sdd->clk)) {
+               dev_err(&pdev->dev, "Unable to acquire clock 'spi'\n");
+               ret = PTR_ERR(sdd->clk);
+               goto err3;
+       }
+
+       if (clk_enable(sdd->clk)) {
+               dev_err(&pdev->dev, "Couldn't enable clock 'spi'\n");
+               ret = -EBUSY;
+               goto err4;
+       }
+
+       if (sci->src_clk_nr == S3C64XX_SPI_SRCCLK_PCLK)
+               sci->src_clk = sdd->clk;
+       else
+               sci->src_clk = clk_get(&pdev->dev, sci->src_clk_name);
+       if (IS_ERR(sci->src_clk)) {
+               dev_err(&pdev->dev,
+                       "Unable to acquire clock '%s'\n", sci->src_clk_name);
+               ret = PTR_ERR(sci->src_clk);
+               goto err5;
+       }
+
+       if (sci->src_clk != sdd->clk && clk_enable(sci->src_clk)) {
+               dev_err(&pdev->dev, "Couldn't enable clock '%s'\n",
+                                                       sci->src_clk_name);
+               ret = -EBUSY;
+               goto err6;
+       }
+
+       sdd->workqueue = create_singlethread_workqueue(
+                                               dev_name(master->dev.parent));
+       if (sdd->workqueue == NULL) {
+               dev_err(&pdev->dev, "Unable to create workqueue\n");
+               ret = -ENOMEM;
+               goto err7;
+       }
+
+       /* Setup Deufult Mode */
+       s3c64xx_spi_hwinit(sdd, pdev->id);
+
+       spin_lock_init(&sdd->lock);
+       init_completion(&sdd->xfer_completion);
+       INIT_WORK(&sdd->work, s3c64xx_spi_work);
+       INIT_LIST_HEAD(&sdd->queue);
+
+       if (spi_register_master(master)) {
+               dev_err(&pdev->dev, "cannot register SPI master\n");
+               ret = -EBUSY;
+               goto err8;
+       }
+
+       dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d \
+                                       with %d Slaves attached\n",
+                                       pdev->id, master->num_chipselect);
+       dev_dbg(&pdev->dev, "\tIOmem=[0x%x-0x%x]\
+                                       \tDMA=[Rx-%d, Tx-%d]\n",
+                                       mem_res->end, mem_res->start,
+                                       sdd->rx_dmach, sdd->tx_dmach);
+
+       return 0;
+
+err8:
+       destroy_workqueue(sdd->workqueue);
+err7:
+       if (sci->src_clk != sdd->clk)
+               clk_disable(sci->src_clk);
+err6:
+       if (sci->src_clk != sdd->clk)
+               clk_put(sci->src_clk);
+err5:
+       clk_disable(sdd->clk);
+err4:
+       clk_put(sdd->clk);
+err3:
+err2:
+       iounmap((void *) sdd->regs);
+err1:
+       release_mem_region(mem_res->start, resource_size(mem_res));
+err0:
+       platform_set_drvdata(pdev, NULL);
+       spi_master_put(master);
+
+       return ret;
+}
+
+static int s3c64xx_spi_remove(struct platform_device *pdev)
+{
+       struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
+       struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
+       struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
+       struct resource *mem_res;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sdd->lock, flags);
+       sdd->state |= SUSPND;
+       spin_unlock_irqrestore(&sdd->lock, flags);
+
+       while (sdd->state & SPIBUSY)
+               msleep(10);
+
+       spi_unregister_master(master);
+
+       destroy_workqueue(sdd->workqueue);
+
+       if (sci->src_clk != sdd->clk)
+               clk_disable(sci->src_clk);
+
+       if (sci->src_clk != sdd->clk)
+               clk_put(sci->src_clk);
+
+       clk_disable(sdd->clk);
+       clk_put(sdd->clk);
+
+       iounmap((void *) sdd->regs);
+
+       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(mem_res->start, resource_size(mem_res));
+
+       platform_set_drvdata(pdev, NULL);
+       spi_master_put(master);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int s3c64xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
+       struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
+       struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
+       struct s3c64xx_spi_csinfo *cs;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sdd->lock, flags);
+       sdd->state |= SUSPND;
+       spin_unlock_irqrestore(&sdd->lock, flags);
+
+       while (sdd->state & SPIBUSY)
+               msleep(10);
+
+       /* Disable the clock */
+       if (sci->src_clk != sdd->clk)
+               clk_disable(sci->src_clk);
+
+       clk_disable(sdd->clk);
+
+       sdd->cur_speed = 0; /* Output Clock is stopped */
+
+       return 0;
+}
+
+static int s3c64xx_spi_resume(struct platform_device *pdev)
+{
+       struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
+       struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
+       struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
+       unsigned long flags;
+
+       sci->cfg_gpio(pdev);
+
+       /* Enable the clock */
+       if (sci->src_clk != sdd->clk)
+               clk_enable(sci->src_clk);
+
+       clk_enable(sdd->clk);
+
+       s3c64xx_spi_hwinit(sdd, pdev->id);
+
+       spin_lock_irqsave(&sdd->lock, flags);
+       sdd->state &= ~SUSPND;
+       spin_unlock_irqrestore(&sdd->lock, flags);
+
+       return 0;
+}
+#else
+#define s3c64xx_spi_suspend    NULL
+#define s3c64xx_spi_resume     NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver s3c64xx_spi_driver = {
+       .driver = {
+               .name   = "s3c64xx-spi",
+               .owner = THIS_MODULE,
+       },
+       .remove = s3c64xx_spi_remove,
+       .suspend = s3c64xx_spi_suspend,
+       .resume = s3c64xx_spi_resume,
+};
+MODULE_ALIAS("platform:s3c64xx-spi");
+
+static int __init s3c64xx_spi_init(void)
+{
+       return platform_driver_probe(&s3c64xx_spi_driver, s3c64xx_spi_probe);
+}
+module_init(s3c64xx_spi_init);
+
+static void __exit s3c64xx_spi_exit(void)
+{
+       platform_driver_unregister(&s3c64xx_spi_driver);
+}
+module_exit(s3c64xx_spi_exit);
+
+MODULE_AUTHOR("Jaswinder Singh <jassi.brar@samsung.com>");
+MODULE_DESCRIPTION("S3C64XX SPI Controller Driver");
+MODULE_LICENSE("GPL");
index 7d36720eb98299858878c777ffe09b74d6641a96..a65c12ffa73352a79a160dcc5ae665fecb862dc1 100644 (file)
@@ -148,7 +148,7 @@ static int sh_sci_spi_probe(struct platform_device *dev)
                ret = -ENOENT;
                goto err1;
        }
-       sp->membase = ioremap(r->start, r->end - r->start + 1);
+       sp->membase = ioremap(r->start, resource_size(r));
        if (!sp->membase) {
                ret = -ENXIO;
                goto err1;
index 19f75627c3deaf0dd0d31a38689a550abf66f488..dfa024b633e173787dd7c467d7581b27f2d0fd79 100644 (file)
@@ -375,12 +375,10 @@ static int __init txx9spi_probe(struct platform_device *dev)
        res = platform_get_resource(dev, IORESOURCE_MEM, 0);
        if (!res)
                goto exit_busy;
-       if (!devm_request_mem_region(&dev->dev,
-                                    res->start, res->end - res->start + 1,
+       if (!devm_request_mem_region(&dev->dev, res->start, resource_size(res),
                                     "spi_txx9"))
                goto exit_busy;
-       c->membase = devm_ioremap(&dev->dev,
-                                 res->start, res->end - res->start + 1);
+       c->membase = devm_ioremap(&dev->dev, res->start, resource_size(res));
        if (!c->membase)
                goto exit_busy;
 
index 9c446e6003d5c16bae4b9b7c5cb589411bc79770..ea1bec3c9a13359a4058a762e9f2f8de7755cc36 100644 (file)
@@ -53,7 +53,7 @@
 #define SPIDEV_MAJOR                   153     /* assigned */
 #define N_SPI_MINORS                   32      /* ... up to 256 */
 
-static unsigned long   minors[N_SPI_MINORS / BITS_PER_LONG];
+static DECLARE_BITMAP(minors, N_SPI_MINORS);
 
 
 /* Bit masks for spi_device.mode management.  Note that incorrect
@@ -558,7 +558,7 @@ static struct class *spidev_class;
 
 /*-------------------------------------------------------------------------*/
 
-static int spidev_probe(struct spi_device *spi)
+static int __devinit spidev_probe(struct spi_device *spi)
 {
        struct spidev_data      *spidev;
        int                     status;
@@ -607,7 +607,7 @@ static int spidev_probe(struct spi_device *spi)
        return status;
 }
 
-static int spidev_remove(struct spi_device *spi)
+static int __devexit spidev_remove(struct spi_device *spi)
 {
        struct spidev_data      *spidev = spi_get_drvdata(spi);
 
@@ -629,7 +629,7 @@ static int spidev_remove(struct spi_device *spi)
        return 0;
 }
 
-static struct spi_driver spidev_spi = {
+static struct spi_driver spidev_spi_driver = {
        .driver = {
                .name =         "spidev",
                .owner =        THIS_MODULE,
@@ -661,14 +661,14 @@ static int __init spidev_init(void)
 
        spidev_class = class_create(THIS_MODULE, "spidev");
        if (IS_ERR(spidev_class)) {
-               unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);
+               unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
                return PTR_ERR(spidev_class);
        }
 
-       status = spi_register_driver(&spidev_spi);
+       status = spi_register_driver(&spidev_spi_driver);
        if (status < 0) {
                class_destroy(spidev_class);
-               unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);
+               unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
        }
        return status;
 }
@@ -676,9 +676,9 @@ module_init(spidev_init);
 
 static void __exit spidev_exit(void)
 {
-       spi_unregister_driver(&spidev_spi);
+       spi_unregister_driver(&spidev_spi_driver);
        class_destroy(spidev_class);
-       unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);
+       unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
 }
 module_exit(spidev_exit);
 
index f0b86f02cd808afc287db224cc1f1f21b9cabe1f..fd677f008365115abd0b23f7b47d740e5ff873c9 100644 (file)
@@ -29,7 +29,6 @@
  * driver requests - some may support multiple options */
 
 
-#include <linux/autoconf.h>
 #include "iio.h"
 #include "ring_generic.h"
 
index 4ce399b6d237546961b826734ca8c77003915eb4..f98a52448eae93d2cb7f1ba9381a7d0e9769bfb4 100644 (file)
@@ -55,7 +55,7 @@
 #include <linux/list.h>
 #include <linux/notifier.h>
 #include <linux/reboot.h>
-#include <linux/utsrelease.h>
+#include <generated/utsrelease.h>
 
 #include <linux/io.h>
 #include <asm/uaccess.h>
index 2051c9dc813bf9fc1a1cb27c29f144322f039e91..b7687c55fe16b6d04efed50a5059dd1b100672ec 100644 (file)
@@ -2245,9 +2245,6 @@ static int ext_setcolreg(unsigned int regno, unsigned int red,
        if (regno > 255)
                return 1;
 
-       if (regno > 255)
-               return 1;
-
        switch (external_card_type) {
        case IS_VGA:
                OUTB(0x3c8, regno);
index 4c10edecfb6616070ce46610a5694f2fbf051080..86d95c228adb7289ec294f454b44e9575516d1f7 100644 (file)
@@ -85,7 +85,7 @@ static int adp5520_bl_get_brightness(struct backlight_device *bl)
        return error ? data->current_brightness : reg_val;
 }
 
-static struct backlight_ops adp5520_bl_ops = {
+static const struct backlight_ops adp5520_bl_ops = {
        .update_status  = adp5520_bl_update_status,
        .get_brightness = adp5520_bl_get_brightness,
 };
index 2c3bdfc620b74a0d92cdc0a7bfd5b932b347c682..d769b0bab21abfc5b41105f430210532a7bd948e 100644 (file)
@@ -61,7 +61,7 @@ static int adx_backlight_check_fb(struct fb_info *fb)
        return 1;
 }
 
-static struct backlight_ops adx_backlight_ops = {
+static const struct backlight_ops adx_backlight_ops = {
        .options = 0,
        .update_status = adx_backlight_update_status,
        .get_brightness = adx_backlight_get_brightness,
index 2cf7ba52f67c1f62ffd0f0ee61dc65650f67768e..f625ffc69ad3139cef6ba88688ac1e76878ff1e4 100644 (file)
@@ -113,7 +113,7 @@ static int atmel_pwm_bl_init_pwm(struct atmel_pwm_bl *pwmbl)
        return pwm_channel_enable(&pwmbl->pwmc);
 }
 
-static struct backlight_ops atmel_pwm_bl_ops = {
+static const struct backlight_ops atmel_pwm_bl_ops = {
        .get_brightness = atmel_pwm_bl_get_intensity,
        .update_status  = atmel_pwm_bl_set_intensity,
 };
index 6615ac7fa60a6124e31257a2ce1b09cf871ed719..18829cf68b1b97ca111af2d390820a3576ad68c1 100644 (file)
@@ -269,7 +269,7 @@ EXPORT_SYMBOL(backlight_force_update);
  * ERR_PTR() or a pointer to the newly allocated device.
  */
 struct backlight_device *backlight_device_register(const char *name,
-               struct device *parent, void *devdata, struct backlight_ops *ops)
+               struct device *parent, void *devdata, const struct backlight_ops *ops)
 {
        struct backlight_device *new_bd;
        int rc;
index 96774949cd30ba3964ea1340e47a3524f841c08b..b4bcf8043797d18ced2ab1618ee9ef57853e6399 100644 (file)
@@ -451,7 +451,7 @@ void corgi_lcd_limit_intensity(int limit)
 }
 EXPORT_SYMBOL(corgi_lcd_limit_intensity);
 
-static struct backlight_ops corgi_bl_ops = {
+static const struct backlight_ops corgi_bl_ops = {
        .get_brightness = corgi_bl_get_intensity,
        .update_status  = corgi_bl_update_status,
 };
index b9fe62b475c63a3fa953ea182958496cd4037d52..da86db4374a05a350084b2f06834d489e773f4ba 100644 (file)
@@ -108,7 +108,7 @@ static int cr_backlight_get_intensity(struct backlight_device *bd)
        return intensity;
 }
 
-static struct backlight_ops cr_backlight_ops = {
+static const struct backlight_ops cr_backlight_ops = {
        .get_brightness = cr_backlight_get_intensity,
        .update_status = cr_backlight_set_intensity,
 };
@@ -201,7 +201,7 @@ static int cr_backlight_probe(struct platform_device *pdev)
        if (IS_ERR(ldp)) {
                backlight_device_unregister(bdp);
                pci_dev_put(lpc_dev);
-               return PTR_ERR(bdp);
+               return PTR_ERR(ldp);
        }
 
        pci_read_config_dword(lpc_dev, CRVML_REG_GPIOBAR,
index f2d76dae1eb370813b7c31b338aa951d45e2267b..74cdc640173de5879af656d46cfaafa4ec8ad6bf 100644 (file)
@@ -95,7 +95,7 @@ static int da903x_backlight_get_brightness(struct backlight_device *bl)
        return data->current_brightness;
 }
 
-static struct backlight_ops da903x_backlight_ops = {
+static const struct backlight_ops da903x_backlight_ops = {
        .update_status  = da903x_backlight_update_status,
        .get_brightness = da903x_backlight_get_brightness,
 };
index 6d27f62fdcd09055db7bba7207a72905fc8aa36d..e6d348e63596455f06d4a3443e82ea4f982a91e6 100644 (file)
@@ -70,7 +70,7 @@ void corgibl_limit_intensity(int limit)
 }
 EXPORT_SYMBOL(corgibl_limit_intensity);
 
-static struct backlight_ops genericbl_ops = {
+static const struct backlight_ops genericbl_ops = {
        .options = BL_CORE_SUSPENDRESUME,
        .get_brightness = genericbl_get_intensity,
        .update_status  = genericbl_send_intensity,
index 7fb4eefff80daa497fdc4440508b5b3ca8739886..f7cc528d5be79a066347e43b3271c0d376e5275c 100644 (file)
@@ -98,7 +98,7 @@ static int hp680bl_get_intensity(struct backlight_device *bd)
        return current_intensity;
 }
 
-static struct backlight_ops hp680bl_ops = {
+static const struct backlight_ops hp680bl_ops = {
        .get_brightness = hp680bl_get_intensity,
        .update_status  = hp680bl_set_intensity,
 };
index 7aed2565c1bd1b666ab7b46f63e02879e6097a54..db9071fc56654add5b279b31845c75e34e7726cc 100644 (file)
@@ -93,7 +93,7 @@ out:
        return ret;
 }
 
-static struct backlight_ops jornada_bl_ops = {
+static const struct backlight_ops jornada_bl_ops = {
        .get_brightness = jornada_bl_get_brightness,
        .update_status = jornada_bl_update_status,
        .options = BL_CORE_SUSPENDRESUME,
index a38fda1742ddb58e374ad825218fd4bc06f6a332..939e7b830cf3f5afabaf104e694d465e63759bd5 100644 (file)
@@ -134,7 +134,7 @@ static int kb3886bl_get_intensity(struct backlight_device *bd)
        return kb3886bl_intensity;
 }
 
-static struct backlight_ops kb3886bl_ops = {
+static const struct backlight_ops kb3886bl_ops = {
        .get_brightness = kb3886bl_get_intensity,
        .update_status  = kb3886bl_send_intensity,
 };
index 6b488b8a7eee6cb6b0e5a9631239d57aac7e66e9..00a9591b00030f8a3bf744ec124cc163ff061ad9 100644 (file)
@@ -141,7 +141,7 @@ static int locomolcd_get_intensity(struct backlight_device *bd)
        return current_intensity;
 }
 
-static struct backlight_ops locomobl_data = {
+static const struct backlight_ops locomobl_data = {
        .get_brightness = locomolcd_get_intensity,
        .update_status  = locomolcd_set_intensity,
 };
index 9edb8d7c295f38ed02a31642b3eba3be1c5681c9..2e78b0784bdc8b1dae7083fbee8f052302a30227 100644 (file)
@@ -33,7 +33,7 @@ struct dmi_match_data {
        unsigned long iostart;
        unsigned long iolen;
        /* Backlight operations structure. */
-       struct backlight_ops backlight_ops;
+       const struct backlight_ops backlight_ops;
 };
 
 /* Module parameters. */
@@ -218,6 +218,24 @@ static const struct dmi_system_id __initdata mbp_device_table[] = {
                },
                .driver_data    = (void *)&nvidia_chipset_data,
        },
+       {
+               .callback       = mbp_dmi_match,
+               .ident          = "MacBookPro 5,3",
+               .matches        = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,3"),
+               },
+               .driver_data    = (void *)&nvidia_chipset_data,
+       },
+       {
+               .callback       = mbp_dmi_match,
+               .ident          = "MacBookPro 5,4",
+               .matches        = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,4"),
+               },
+               .driver_data    = (void *)&nvidia_chipset_data,
+       },
        {
                .callback       = mbp_dmi_match,
                .ident          = "MacBookPro 5,5",
index 8693e5fcd2eb83dea83083a5ff3126900c87abc9..409ca9643528b6d52a0906afdd97b3cbcf158a9b 100644 (file)
@@ -125,7 +125,7 @@ static int omapbl_get_intensity(struct backlight_device *dev)
        return bl->current_intensity;
 }
 
-static struct backlight_ops omapbl_ops = {
+static const struct backlight_ops omapbl_ops = {
        .get_brightness = omapbl_get_intensity,
        .update_status  = omapbl_update_status,
 };
index 9edaf24fd82d4e49f0bf439162fa156088cbc25e..075786e05034cc5defba6606a32e13b2e18f8de6 100644 (file)
@@ -54,7 +54,7 @@ static int progearbl_get_intensity(struct backlight_device *bd)
        return intensity - HW_LEVEL_MIN;
 }
 
-static struct backlight_ops progearbl_ops = {
+static const struct backlight_ops progearbl_ops = {
        .get_brightness = progearbl_get_intensity,
        .update_status = progearbl_set_intensity,
 };
index 88716626744391a89cae97a5658fb3cc0ffbd545..9d2ec2a1cce8fff721d40680277d45ac5bc1bb55 100644 (file)
 
 struct pwm_bl_data {
        struct pwm_device       *pwm;
+       struct device           *dev;
        unsigned int            period;
-       int                     (*notify)(int brightness);
+       int                     (*notify)(struct device *,
+                                         int brightness);
 };
 
 static int pwm_backlight_update_status(struct backlight_device *bl)
@@ -39,7 +41,7 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
                brightness = 0;
 
        if (pb->notify)
-               brightness = pb->notify(brightness);
+               brightness = pb->notify(pb->dev, brightness);
 
        if (brightness == 0) {
                pwm_config(pb->pwm, 0, pb->period);
@@ -56,7 +58,7 @@ static int pwm_backlight_get_brightness(struct backlight_device *bl)
        return bl->props.brightness;
 }
 
-static struct backlight_ops pwm_backlight_ops = {
+static const struct backlight_ops pwm_backlight_ops = {
        .update_status  = pwm_backlight_update_status,
        .get_brightness = pwm_backlight_get_brightness,
 };
@@ -88,6 +90,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
 
        pb->period = data->pwm_period_ns;
        pb->notify = data->notify;
+       pb->dev = &pdev->dev;
 
        pb->pwm = pwm_request(data->pwm_id, "backlight");
        if (IS_ERR(pb->pwm)) {
@@ -146,7 +149,7 @@ static int pwm_backlight_suspend(struct platform_device *pdev,
        struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
 
        if (pb->notify)
-               pb->notify(0);
+               pb->notify(pb->dev, 0);
        pwm_config(pb->pwm, 0, pb->period);
        pwm_disable(pb->pwm);
        return 0;
index 43edbada12d19156970d5b84f68e56de73333c25..e14ce4d469f57f1ed6525ba53113bcbd6bca6913 100644 (file)
@@ -72,7 +72,7 @@ static int tosa_bl_get_brightness(struct backlight_device *dev)
        return props->brightness;
 }
 
-static struct backlight_ops bl_ops = {
+static const struct backlight_ops bl_ops = {
        .get_brightness         = tosa_bl_get_brightness,
        .update_status          = tosa_bl_update_status,
 };
index 467bdb7efb231057160aa5333960057439fac502..e32add37a203453558c80a6c195276cb402094c6 100644 (file)
@@ -112,7 +112,7 @@ static int wm831x_backlight_get_brightness(struct backlight_device *bl)
        return data->current_brightness;
 }
 
-static struct backlight_ops wm831x_backlight_ops = {
+static const struct backlight_ops wm831x_backlight_ops = {
        .options = BL_CORE_SUSPENDRESUME,
        .update_status  = wm831x_backlight_update_status,
        .get_brightness = wm831x_backlight_get_brightness,
index 10d8c4b4baeb855f2ec54853e8988947e0231a12..d8df17a7d5fce50a0f2566f5ee06713eb0ae96bd 100644 (file)
@@ -680,7 +680,7 @@ static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
                if (!viafb_gamma_table)
                        return -ENOMEM;
                if (copy_from_user(viafb_gamma_table, argp,
-                               sizeof(viafb_gamma_table))) {
+                               256 * sizeof(u32))) {
                        kfree(viafb_gamma_table);
                        return -EFAULT;
                }
@@ -694,7 +694,7 @@ static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
                        return -ENOMEM;
                viafb_get_gamma_table(viafb_gamma_table);
                if (copy_to_user(argp, viafb_gamma_table,
-                       sizeof(viafb_gamma_table))) {
+                       256 * sizeof(u32))) {
                        kfree(viafb_gamma_table);
                        return -EFAULT;
                }
index f8fccaaad6282b097f75fae49f2aa4d6c2e6c390..64d44efad7a5d6752ad5c867ff7d10dd0b94b1e3 100644 (file)
@@ -6,10 +6,6 @@ menu "File systems"
 
 if BLOCK
 
-config FS_JOURNAL_INFO
-       bool
-       default n
-
 source "fs/ext2/Kconfig"
 source "fs/ext3/Kconfig"
 source "fs/ext4/Kconfig"
index 94f5110c4655167a769088e40e94e3a5159dedeb..2c994591f4d7a4fe89021c00110df70b5df8a433 100644 (file)
@@ -35,14 +35,13 @@ static int anon_inodefs_get_sb(struct file_system_type *fs_type, int flags,
                             mnt);
 }
 
-static int anon_inodefs_delete_dentry(struct dentry *dentry)
+/*
+ * anon_inodefs_dname() is called from d_path().
+ */
+static char *anon_inodefs_dname(struct dentry *dentry, char *buffer, int buflen)
 {
-       /*
-        * We faked vfs to believe the dentry was hashed when we created it.
-        * Now we restore the flag so that dput() will work correctly.
-        */
-       dentry->d_flags |= DCACHE_UNHASHED;
-       return 1;
+       return dynamic_dname(dentry, buffer, buflen, "anon_inode:%s",
+                               dentry->d_name.name);
 }
 
 static struct file_system_type anon_inode_fs_type = {
@@ -51,7 +50,7 @@ static struct file_system_type anon_inode_fs_type = {
        .kill_sb        = kill_anon_super,
 };
 static const struct dentry_operations anon_inodefs_dentry_operations = {
-       .d_delete       = anon_inodefs_delete_dentry,
+       .d_dname        = anon_inodefs_dname,
 };
 
 /*
@@ -119,8 +118,6 @@ struct file *anon_inode_getfile(const char *name,
        atomic_inc(&anon_inode_inode->i_count);
 
        path.dentry->d_op = &anon_inodefs_dentry_operations;
-       /* Do not publish this dentry inside the global dentry hash table */
-       path.dentry->d_flags &= ~DCACHE_UNHASHED;
        d_instantiate(path.dentry, anon_inode_inode);
 
        error = -ENFILE;
index b639dcf7c778cfc6f81eca964c8c6748a5840949..346b69405363b7419d7d4b591b240074d72bff6b 100644 (file)
@@ -32,7 +32,7 @@
 
 static int load_aout_binary(struct linux_binprm *, struct pt_regs * regs);
 static int load_aout_library(struct file*);
-static int aout_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit);
+static int aout_core_dump(struct coredump_params *cprm);
 
 static struct linux_binfmt aout_format = {
        .module         = THIS_MODULE,
@@ -89,8 +89,9 @@ if (file->f_op->llseek) { \
  * dumping of the process results in another error..
  */
 
-static int aout_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit)
+static int aout_core_dump(struct coredump_params *cprm)
 {
+       struct file *file = cprm->file;
        mm_segment_t fs;
        int has_dumped = 0;
        unsigned long dump_start, dump_size;
@@ -108,16 +109,16 @@ static int aout_core_dump(long signr, struct pt_regs *regs, struct file *file, u
        current->flags |= PF_DUMPCORE;
                strncpy(dump.u_comm, current->comm, sizeof(dump.u_comm));
        dump.u_ar0 = offsetof(struct user, regs);
-       dump.signal = signr;
-       aout_dump_thread(regs, &dump);
+       dump.signal = cprm->signr;
+       aout_dump_thread(cprm->regs, &dump);
 
 /* If the size of the dump file exceeds the rlimit, then see what would happen
    if we wrote the stack, but not the data area.  */
-       if ((dump.u_dsize + dump.u_ssize+1) * PAGE_SIZE > limit)
+       if ((dump.u_dsize + dump.u_ssize+1) * PAGE_SIZE > cprm->limit)
                dump.u_dsize = 0;
 
 /* Make sure we have enough room to write the stack and data areas. */
-       if ((dump.u_ssize + 1) * PAGE_SIZE > limit)
+       if ((dump.u_ssize + 1) * PAGE_SIZE > cprm->limit)
                dump.u_ssize = 0;
 
 /* make sure we actually have a data and stack area to dump */
index 97b6e9efeb7f356296ed03d5f1a9f4762067ce6b..edd90c49003cff3b2fdf62ecb0e406007369eedb 100644 (file)
@@ -45,7 +45,7 @@ static unsigned long elf_map(struct file *, unsigned long, struct elf_phdr *,
  * don't even try.
  */
 #ifdef CONFIG_ELF_CORE
-static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit);
+static int elf_core_dump(struct coredump_params *cprm);
 #else
 #define elf_core_dump  NULL
 #endif
@@ -1272,8 +1272,9 @@ static int writenote(struct memelfnote *men, struct file *file,
 }
 #undef DUMP_WRITE
 
-#define DUMP_WRITE(addr, nr)   \
-       if ((size += (nr)) > limit || !dump_write(file, (addr), (nr))) \
+#define DUMP_WRITE(addr, nr)                           \
+       if ((size += (nr)) > cprm->limit ||             \
+           !dump_write(cprm->file, (addr), (nr)))      \
                goto end_coredump;
 
 static void fill_elf_header(struct elfhdr *elf, int segs,
@@ -1901,7 +1902,7 @@ static struct vm_area_struct *next_vma(struct vm_area_struct *this_vma,
  * and then they are actually written out.  If we run out of core limit
  * we just truncate.
  */
-static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit)
+static int elf_core_dump(struct coredump_params *cprm)
 {
        int has_dumped = 0;
        mm_segment_t fs;
@@ -1947,7 +1948,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, un
         * notes.  This also sets up the file header.
         */
        if (!fill_note_info(elf, segs + 1, /* including notes section */
-                           &info, signr, regs))
+                           &info, cprm->signr, cprm->regs))
                goto cleanup;
 
        has_dumped = 1;
@@ -2009,14 +2010,14 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, un
 #endif
 
        /* write out the notes section */
-       if (!write_note_info(&info, file, &foffset))
+       if (!write_note_info(&info, cprm->file, &foffset))
                goto end_coredump;
 
-       if (elf_coredump_extra_notes_write(file, &foffset))
+       if (elf_coredump_extra_notes_write(cprm->file, &foffset))
                goto end_coredump;
 
        /* Align to page */
-       if (!dump_seek(file, dataoff - foffset))
+       if (!dump_seek(cprm->file, dataoff - foffset))
                goto end_coredump;
 
        for (vma = first_vma(current, gate_vma); vma != NULL;
@@ -2033,12 +2034,13 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, un
                        page = get_dump_page(addr);
                        if (page) {
                                void *kaddr = kmap(page);
-                               stop = ((size += PAGE_SIZE) > limit) ||
-                                       !dump_write(file, kaddr, PAGE_SIZE);
+                               stop = ((size += PAGE_SIZE) > cprm->limit) ||
+                                       !dump_write(cprm->file, kaddr,
+                                                   PAGE_SIZE);
                                kunmap(page);
                                page_cache_release(page);
                        } else
-                               stop = !dump_seek(file, PAGE_SIZE);
+                               stop = !dump_seek(cprm->file, PAGE_SIZE);
                        if (stop)
                                goto end_coredump;
                }
index 7b055385db8ee8a341bb1af9ed63859523324f2f..c25256a5c5b0e432f63fe3fd07d8e3a2c61a909b 100644 (file)
@@ -76,7 +76,7 @@ static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *,
                                             struct file *, struct mm_struct *);
 
 #ifdef CONFIG_ELF_CORE
-static int elf_fdpic_core_dump(long, struct pt_regs *, struct file *, unsigned long limit);
+static int elf_fdpic_core_dump(struct coredump_params *cprm);
 #endif
 
 static struct linux_binfmt elf_fdpic_format = {
@@ -1326,8 +1326,9 @@ static int writenote(struct memelfnote *men, struct file *file)
 #undef DUMP_WRITE
 #undef DUMP_SEEK
 
-#define DUMP_WRITE(addr, nr)   \
-       if ((size += (nr)) > limit || !dump_write(file, (addr), (nr))) \
+#define DUMP_WRITE(addr, nr)                           \
+       if ((size += (nr)) > cprm->limit ||             \
+           !dump_write(cprm->file, (addr), (nr)))      \
                goto end_coredump;
 
 static inline void fill_elf_fdpic_header(struct elfhdr *elf, int segs)
@@ -1582,8 +1583,7 @@ static int elf_fdpic_dump_segments(struct file *file, size_t *size,
  * and then they are actually written out.  If we run out of core limit
  * we just truncate.
  */
-static int elf_fdpic_core_dump(long signr, struct pt_regs *regs,
-                              struct file *file, unsigned long limit)
+static int elf_fdpic_core_dump(struct coredump_params *cprm)
 {
 #define        NUM_NOTES       6
        int has_dumped = 0;
@@ -1642,7 +1642,7 @@ static int elf_fdpic_core_dump(long signr, struct pt_regs *regs,
                goto cleanup;
 #endif
 
-       if (signr) {
+       if (cprm->signr) {
                struct core_thread *ct;
                struct elf_thread_status *tmp;
 
@@ -1661,14 +1661,14 @@ static int elf_fdpic_core_dump(long signr, struct pt_regs *regs,
                        int sz;
 
                        tmp = list_entry(t, struct elf_thread_status, list);
-                       sz = elf_dump_thread_status(signr, tmp);
+                       sz = elf_dump_thread_status(cprm->signr, tmp);
                        thread_status_size += sz;
                }
        }
 
        /* now collect the dump for the current */
-       fill_prstatus(prstatus, current, signr);
-       elf_core_copy_regs(&prstatus->pr_reg, regs);
+       fill_prstatus(prstatus, current, cprm->signr);
+       elf_core_copy_regs(&prstatus->pr_reg, cprm->regs);
 
        segs = current->mm->map_count;
 #ifdef ELF_CORE_EXTRA_PHDRS
@@ -1703,7 +1703,7 @@ static int elf_fdpic_core_dump(long signr, struct pt_regs *regs,
 
        /* Try to dump the FPU. */
        if ((prstatus->pr_fpvalid =
-            elf_core_copy_task_fpregs(current, regs, fpu)))
+            elf_core_copy_task_fpregs(current, cprm->regs, fpu)))
                fill_note(notes + numnote++,
                          "CORE", NT_PRFPREG, sizeof(*fpu), fpu);
 #ifdef ELF_CORE_COPY_XFPREGS
@@ -1774,7 +1774,7 @@ static int elf_fdpic_core_dump(long signr, struct pt_regs *regs,
 
        /* write out the notes section */
        for (i = 0; i < numnote; i++)
-               if (!writenote(notes + i, file))
+               if (!writenote(notes + i, cprm->file))
                        goto end_coredump;
 
        /* write out the thread status notes section */
@@ -1783,14 +1783,15 @@ static int elf_fdpic_core_dump(long signr, struct pt_regs *regs,
                                list_entry(t, struct elf_thread_status, list);
 
                for (i = 0; i < tmp->num_notes; i++)
-                       if (!writenote(&tmp->notes[i], file))
+                       if (!writenote(&tmp->notes[i], cprm->file))
                                goto end_coredump;
        }
 
-       if (!dump_seek(file, dataoff))
+       if (!dump_seek(cprm->file, dataoff))
                goto end_coredump;
 
-       if (elf_fdpic_dump_segments(file, &size, &limit, mm_flags) < 0)
+       if (elf_fdpic_dump_segments(cprm->file, &size, &cprm->limit,
+                                   mm_flags) < 0)
                goto end_coredump;
 
 #ifdef ELF_CORE_WRITE_EXTRA_DATA
index a2796651e75690eb8e8a875146be852bfb1d637b..d4a00ea1054c63f0401bb0b1ef0e78a245df8851 100644 (file)
@@ -87,7 +87,7 @@ static int load_flat_shared_library(int id, struct lib_info *p);
 #endif
 
 static int load_flat_binary(struct linux_binprm *, struct pt_regs * regs);
-static int flat_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit);
+static int flat_core_dump(struct coredump_params *cprm);
 
 static struct linux_binfmt flat_format = {
        .module         = THIS_MODULE,
@@ -102,10 +102,10 @@ static struct linux_binfmt flat_format = {
  * Currently only a stub-function.
  */
 
-static int flat_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit)
+static int flat_core_dump(struct coredump_params *cprm)
 {
        printk("Process %s:%d received signr %d and should have core dumped\n",
-                       current->comm, current->pid, (int) signr);
+                       current->comm, current->pid, (int) cprm->signr);
        return(1);
 }
 
index eff74b9c9e77cf8f0b933adb2addcc9aac899a46..2a9b5330cc5e9ada9c23f41c6007996f58b6b938 100644 (file)
@@ -43,7 +43,7 @@ static int load_som_library(struct file *);
  * don't even try.
  */
 #if 0
-static int som_core_dump(long signr, struct pt_regs *regs, unsigned long limit);
+static int som_core_dump(struct coredump_params *cprm);
 #else
 #define som_core_dump  NULL
 #endif
index 402afe0a0bfbbab01e307800716c8b2553dc6479..7bb3c020e570d9a1e0d2d640f6c9127df8e57a01 100644 (file)
@@ -4,7 +4,6 @@ config BTRFS_FS
        select LIBCRC32C
        select ZLIB_INFLATE
        select ZLIB_DEFLATE
-       select FS_JOURNAL_INFO
        help
          Btrfs is a new filesystem with extents, writable snapshotting,
          support for multiple devices and many more features.
index 52cbe47022bf659c29b728aa602a7c60f4c570ca..2e9e69987a82973208724b58899b3479d77feaff 100644 (file)
@@ -94,7 +94,8 @@ static int btrfs_xattr_acl_get(struct dentry *dentry, const char *name,
 /*
  * Needs to be called with fs_mutex held
  */
-static int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
+static int btrfs_set_acl(struct btrfs_trans_handle *trans,
+                        struct inode *inode, struct posix_acl *acl, int type)
 {
        int ret, size = 0;
        const char *name;
@@ -140,8 +141,7 @@ static int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
                        goto out;
        }
 
-       ret = __btrfs_setxattr(inode, name, value, size, 0);
-
+       ret = __btrfs_setxattr(trans, inode, name, value, size, 0);
 out:
        kfree(value);
 
@@ -154,7 +154,7 @@ out:
 static int btrfs_xattr_acl_set(struct dentry *dentry, const char *name,
                const void *value, size_t size, int flags, int type)
 {
-       int ret = 0;
+       int ret;
        struct posix_acl *acl = NULL;
 
        if (value) {
@@ -167,7 +167,7 @@ static int btrfs_xattr_acl_set(struct dentry *dentry, const char *name,
                }
        }
 
-       ret = btrfs_set_acl(dentry->d_inode, acl, type);
+       ret = btrfs_set_acl(NULL, dentry->d_inode, acl, type);
 
        posix_acl_release(acl);
 
@@ -196,7 +196,8 @@ int btrfs_check_acl(struct inode *inode, int mask)
  * stuff has been fixed to work with that.  If the locking stuff changes, we
  * need to re-evaluate the acl locking stuff.
  */
-int btrfs_init_acl(struct inode *inode, struct inode *dir)
+int btrfs_init_acl(struct btrfs_trans_handle *trans,
+                  struct inode *inode, struct inode *dir)
 {
        struct posix_acl *acl = NULL;
        int ret = 0;
@@ -221,7 +222,8 @@ int btrfs_init_acl(struct inode *inode, struct inode *dir)
                mode_t mode;
 
                if (S_ISDIR(inode->i_mode)) {
-                       ret = btrfs_set_acl(inode, acl, ACL_TYPE_DEFAULT);
+                       ret = btrfs_set_acl(trans, inode, acl,
+                                           ACL_TYPE_DEFAULT);
                        if (ret)
                                goto failed;
                }
@@ -236,7 +238,7 @@ int btrfs_init_acl(struct inode *inode, struct inode *dir)
                        inode->i_mode = mode;
                        if (ret > 0) {
                                /* we need an acl */
-                               ret = btrfs_set_acl(inode, clone,
+                               ret = btrfs_set_acl(trans, inode, clone,
                                                    ACL_TYPE_ACCESS);
                        }
                }
@@ -269,7 +271,7 @@ int btrfs_acl_chmod(struct inode *inode)
 
        ret = posix_acl_chmod_masq(clone, inode->i_mode);
        if (!ret)
-               ret = btrfs_set_acl(inode, clone, ACL_TYPE_ACCESS);
+               ret = btrfs_set_acl(NULL, inode, clone, ACL_TYPE_ACCESS);
 
        posix_acl_release(clone);
 
@@ -297,7 +299,8 @@ int btrfs_acl_chmod(struct inode *inode)
        return 0;
 }
 
-int btrfs_init_acl(struct inode *inode, struct inode *dir)
+int btrfs_init_acl(struct btrfs_trans_handle *trans,
+                  struct inode *inode, struct inode *dir)
 {
        return 0;
 }
index f6783a42f010965e344fddc68c2689a7d4a9fc14..3f1f50d9d916cf5e3c095101a3af0c220035f625 100644 (file)
@@ -44,9 +44,6 @@ struct btrfs_inode {
         */
        struct extent_io_tree io_failure_tree;
 
-       /* held while inesrting or deleting extents from files */
-       struct mutex extent_mutex;
-
        /* held while logging the inode in tree-log.c */
        struct mutex log_mutex;
 
@@ -166,7 +163,7 @@ static inline struct btrfs_inode *BTRFS_I(struct inode *inode)
 
 static inline void btrfs_i_size_write(struct inode *inode, u64 size)
 {
-       inode->i_size = size;
+       i_size_write(inode, size);
        BTRFS_I(inode)->disk_i_size = size;
 }
 
index ec96f3a6d536640919dd25a08c7ed22e4423ef15..c4bc570a396eebf5ede775dc39b004c9ff493227 100644 (file)
@@ -37,6 +37,11 @@ static int balance_node_right(struct btrfs_trans_handle *trans,
                              struct extent_buffer *src_buf);
 static int del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                   struct btrfs_path *path, int level, int slot);
+static int setup_items_for_insert(struct btrfs_trans_handle *trans,
+                       struct btrfs_root *root, struct btrfs_path *path,
+                       struct btrfs_key *cpu_key, u32 *data_size,
+                       u32 total_data, u32 total_size, int nr);
+
 
 struct btrfs_path *btrfs_alloc_path(void)
 {
@@ -451,9 +456,8 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
                extent_buffer_get(cow);
                spin_unlock(&root->node_lock);
 
-               btrfs_free_extent(trans, root, buf->start, buf->len,
-                                 parent_start, root->root_key.objectid,
-                                 level, 0);
+               btrfs_free_tree_block(trans, root, buf->start, buf->len,
+                               parent_start, root->root_key.objectid, level);
                free_extent_buffer(buf);
                add_root_to_dirty_list(root);
        } else {
@@ -468,9 +472,8 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
                btrfs_set_node_ptr_generation(parent, parent_slot,
                                              trans->transid);
                btrfs_mark_buffer_dirty(parent);
-               btrfs_free_extent(trans, root, buf->start, buf->len,
-                                 parent_start, root->root_key.objectid,
-                                 level, 0);
+               btrfs_free_tree_block(trans, root, buf->start, buf->len,
+                               parent_start, root->root_key.objectid, level);
        }
        if (unlock_orig)
                btrfs_tree_unlock(buf);
@@ -1030,8 +1033,8 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
                btrfs_tree_unlock(mid);
                /* once for the path */
                free_extent_buffer(mid);
-               ret = btrfs_free_extent(trans, root, mid->start, mid->len,
-                                       0, root->root_key.objectid, level, 1);
+               ret = btrfs_free_tree_block(trans, root, mid->start, mid->len,
+                                           0, root->root_key.objectid, level);
                /* once for the root ptr */
                free_extent_buffer(mid);
                return ret;
@@ -1095,10 +1098,10 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
                                       1);
                        if (wret)
                                ret = wret;
-                       wret = btrfs_free_extent(trans, root, bytenr,
-                                                blocksize, 0,
-                                                root->root_key.objectid,
-                                                level, 0);
+                       wret = btrfs_free_tree_block(trans, root,
+                                                    bytenr, blocksize, 0,
+                                                    root->root_key.objectid,
+                                                    level);
                        if (wret)
                                ret = wret;
                } else {
@@ -1143,9 +1146,8 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
                wret = del_ptr(trans, root, path, level + 1, pslot);
                if (wret)
                        ret = wret;
-               wret = btrfs_free_extent(trans, root, bytenr, blocksize,
-                                        0, root->root_key.objectid,
-                                        level, 0);
+               wret = btrfs_free_tree_block(trans, root, bytenr, blocksize,
+                                        0, root->root_key.objectid, level);
                if (wret)
                        ret = wret;
        } else {
@@ -2997,75 +2999,85 @@ again:
        return ret;
 }
 
-/*
- * This function splits a single item into two items,
- * giving 'new_key' to the new item and splitting the
- * old one at split_offset (from the start of the item).
- *
- * The path may be released by this operation.  After
- * the split, the path is pointing to the old item.  The
- * new item is going to be in the same node as the old one.
- *
- * Note, the item being split must be smaller enough to live alone on
- * a tree block with room for one extra struct btrfs_item
- *
- * This allows us to split the item in place, keeping a lock on the
- * leaf the entire time.
- */
-int btrfs_split_item(struct btrfs_trans_handle *trans,
-                    struct btrfs_root *root,
-                    struct btrfs_path *path,
-                    struct btrfs_key *new_key,
-                    unsigned long split_offset)
+static noinline int setup_leaf_for_split(struct btrfs_trans_handle *trans,
+                                        struct btrfs_root *root,
+                                        struct btrfs_path *path, int ins_len)
 {
-       u32 item_size;
+       struct btrfs_key key;
        struct extent_buffer *leaf;
-       struct btrfs_key orig_key;
-       struct btrfs_item *item;
-       struct btrfs_item *new_item;
-       int ret = 0;
-       int slot;
-       u32 nritems;
-       u32 orig_offset;
-       struct btrfs_disk_key disk_key;
-       char *buf;
+       struct btrfs_file_extent_item *fi;
+       u64 extent_len = 0;
+       u32 item_size;
+       int ret;
 
        leaf = path->nodes[0];
-       btrfs_item_key_to_cpu(leaf, &orig_key, path->slots[0]);
-       if (btrfs_leaf_free_space(root, leaf) >= sizeof(struct btrfs_item))
-               goto split;
+       btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
+
+       BUG_ON(key.type != BTRFS_EXTENT_DATA_KEY &&
+              key.type != BTRFS_EXTENT_CSUM_KEY);
+
+       if (btrfs_leaf_free_space(root, leaf) >= ins_len)
+               return 0;
 
        item_size = btrfs_item_size_nr(leaf, path->slots[0]);
+       if (key.type == BTRFS_EXTENT_DATA_KEY) {
+               fi = btrfs_item_ptr(leaf, path->slots[0],
+                                   struct btrfs_file_extent_item);
+               extent_len = btrfs_file_extent_num_bytes(leaf, fi);
+       }
        btrfs_release_path(root, path);
 
-       path->search_for_split = 1;
        path->keep_locks = 1;
-
-       ret = btrfs_search_slot(trans, root, &orig_key, path, 0, 1);
+       path->search_for_split = 1;
+       ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
        path->search_for_split = 0;
+       if (ret < 0)
+               goto err;
 
+       ret = -EAGAIN;
+       leaf = path->nodes[0];
        /* if our item isn't there or got smaller, return now */
-       if (ret != 0 || item_size != btrfs_item_size_nr(path->nodes[0],
-                                                       path->slots[0])) {
-               path->keep_locks = 0;
-               return -EAGAIN;
+       if (ret > 0 || item_size != btrfs_item_size_nr(leaf, path->slots[0]))
+               goto err;
+
+       if (key.type == BTRFS_EXTENT_DATA_KEY) {
+               fi = btrfs_item_ptr(leaf, path->slots[0],
+                                   struct btrfs_file_extent_item);
+               if (extent_len != btrfs_file_extent_num_bytes(leaf, fi))
+                       goto err;
        }
 
        btrfs_set_path_blocking(path);
-       ret = split_leaf(trans, root, &orig_key, path,
-                        sizeof(struct btrfs_item), 1);
-       path->keep_locks = 0;
+       ret = split_leaf(trans, root, &key, path, ins_len, 1);
        BUG_ON(ret);
 
+       path->keep_locks = 0;
        btrfs_unlock_up_safe(path, 1);
+       return 0;
+err:
+       path->keep_locks = 0;
+       return ret;
+}
+
+static noinline int split_item(struct btrfs_trans_handle *trans,
+                              struct btrfs_root *root,
+                              struct btrfs_path *path,
+                              struct btrfs_key *new_key,
+                              unsigned long split_offset)
+{
+       struct extent_buffer *leaf;
+       struct btrfs_item *item;
+       struct btrfs_item *new_item;
+       int slot;
+       char *buf;
+       u32 nritems;
+       u32 item_size;
+       u32 orig_offset;
+       struct btrfs_disk_key disk_key;
+
        leaf = path->nodes[0];
        BUG_ON(btrfs_leaf_free_space(root, leaf) < sizeof(struct btrfs_item));
 
-split:
-       /*
-        * make sure any changes to the path from split_leaf leave it
-        * in a blocking state
-        */
        btrfs_set_path_blocking(path);
 
        item = btrfs_item_nr(leaf, path->slots[0]);
@@ -3073,19 +3085,19 @@ split:
        item_size = btrfs_item_size(leaf, item);
 
        buf = kmalloc(item_size, GFP_NOFS);
+       if (!buf)
+               return -ENOMEM;
+
        read_extent_buffer(leaf, buf, btrfs_item_ptr_offset(leaf,
                            path->slots[0]), item_size);
-       slot = path->slots[0] + 1;
-       leaf = path->nodes[0];
 
+       slot = path->slots[0] + 1;
        nritems = btrfs_header_nritems(leaf);
-
        if (slot != nritems) {
                /* shift the items */
                memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot + 1),
-                             btrfs_item_nr_offset(slot),
-                             (nritems - slot) * sizeof(struct btrfs_item));
-
+                               btrfs_item_nr_offset(slot),
+                               (nritems - slot) * sizeof(struct btrfs_item));
        }
 
        btrfs_cpu_key_to_disk(&disk_key, new_key);
@@ -3113,15 +3125,80 @@ split:
                            item_size - split_offset);
        btrfs_mark_buffer_dirty(leaf);
 
-       ret = 0;
-       if (btrfs_leaf_free_space(root, leaf) < 0) {
-               btrfs_print_leaf(root, leaf);
-               BUG();
-       }
+       BUG_ON(btrfs_leaf_free_space(root, leaf) < 0);
        kfree(buf);
+       return 0;
+}
+
+/*
+ * This function splits a single item into two items,
+ * giving 'new_key' to the new item and splitting the
+ * old one at split_offset (from the start of the item).
+ *
+ * The path may be released by this operation.  After
+ * the split, the path is pointing to the old item.  The
+ * new item is going to be in the same node as the old one.
+ *
+ * Note, the item being split must be smaller enough to live alone on
+ * a tree block with room for one extra struct btrfs_item
+ *
+ * This allows us to split the item in place, keeping a lock on the
+ * leaf the entire time.
+ */
+int btrfs_split_item(struct btrfs_trans_handle *trans,
+                    struct btrfs_root *root,
+                    struct btrfs_path *path,
+                    struct btrfs_key *new_key,
+                    unsigned long split_offset)
+{
+       int ret;
+       ret = setup_leaf_for_split(trans, root, path,
+                                  sizeof(struct btrfs_item));
+       if (ret)
+               return ret;
+
+       ret = split_item(trans, root, path, new_key, split_offset);
        return ret;
 }
 
+/*
+ * This function duplicate a item, giving 'new_key' to the new item.
+ * It guarantees both items live in the same tree leaf and the new item
+ * is contiguous with the original item.
+ *
+ * This allows us to split file extent in place, keeping a lock on the
+ * leaf the entire time.
+ */
+int btrfs_duplicate_item(struct btrfs_trans_handle *trans,
+                        struct btrfs_root *root,
+                        struct btrfs_path *path,
+                        struct btrfs_key *new_key)
+{
+       struct extent_buffer *leaf;
+       int ret;
+       u32 item_size;
+
+       leaf = path->nodes[0];
+       item_size = btrfs_item_size_nr(leaf, path->slots[0]);
+       ret = setup_leaf_for_split(trans, root, path,
+                                  item_size + sizeof(struct btrfs_item));
+       if (ret)
+               return ret;
+
+       path->slots[0]++;
+       ret = setup_items_for_insert(trans, root, path, new_key, &item_size,
+                                    item_size, item_size +
+                                    sizeof(struct btrfs_item), 1);
+       BUG_ON(ret);
+
+       leaf = path->nodes[0];
+       memcpy_extent_buffer(leaf,
+                            btrfs_item_ptr_offset(leaf, path->slots[0]),
+                            btrfs_item_ptr_offset(leaf, path->slots[0] - 1),
+                            item_size);
+       return 0;
+}
+
 /*
  * make the item pointed to by the path smaller.  new_size indicates
  * how small to make it, and from_end tells us if we just chop bytes
@@ -3714,8 +3791,8 @@ static noinline int btrfs_del_leaf(struct btrfs_trans_handle *trans,
         */
        btrfs_unlock_up_safe(path, 0);
 
-       ret = btrfs_free_extent(trans, root, leaf->start, leaf->len,
-                               0, root->root_key.objectid, 0, 0);
+       ret = btrfs_free_tree_block(trans, root, leaf->start, leaf->len,
+                                   0, root->root_key.objectid, 0);
        return ret;
 }
 /*
index 444b3e9b92a4b88391fd610a76346530436baa01..9f806dd04c2704899bf28e5324eebaa14a923e27 100644 (file)
@@ -310,6 +310,9 @@ struct btrfs_header {
 #define BTRFS_MAX_INLINE_DATA_SIZE(r) (BTRFS_LEAF_DATA_SIZE(r) - \
                                        sizeof(struct btrfs_item) - \
                                        sizeof(struct btrfs_file_extent_item))
+#define BTRFS_MAX_XATTR_SIZE(r)        (BTRFS_LEAF_DATA_SIZE(r) - \
+                                sizeof(struct btrfs_item) -\
+                                sizeof(struct btrfs_dir_item))
 
 
 /*
@@ -859,8 +862,9 @@ struct btrfs_fs_info {
        struct mutex ordered_operations_mutex;
        struct rw_semaphore extent_commit_sem;
 
-       struct rw_semaphore subvol_sem;
+       struct rw_semaphore cleanup_work_sem;
 
+       struct rw_semaphore subvol_sem;
        struct srcu_struct subvol_srcu;
 
        struct list_head trans_list;
@@ -868,6 +872,9 @@ struct btrfs_fs_info {
        struct list_head dead_roots;
        struct list_head caching_block_groups;
 
+       spinlock_t delayed_iput_lock;
+       struct list_head delayed_iputs;
+
        atomic_t nr_async_submits;
        atomic_t async_submit_draining;
        atomic_t nr_async_bios;
@@ -1034,12 +1041,12 @@ struct btrfs_root {
        int ref_cows;
        int track_dirty;
        int in_radix;
+       int clean_orphans;
 
        u64 defrag_trans_start;
        struct btrfs_key defrag_progress;
        struct btrfs_key defrag_max;
        int defrag_running;
-       int defrag_level;
        char *name;
        int in_sysfs;
 
@@ -1975,6 +1982,10 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
                                        u64 parent, u64 root_objectid,
                                        struct btrfs_disk_key *key, int level,
                                        u64 hint, u64 empty_size);
+int btrfs_free_tree_block(struct btrfs_trans_handle *trans,
+                         struct btrfs_root *root,
+                         u64 bytenr, u32 blocksize,
+                         u64 parent, u64 root_objectid, int level);
 struct extent_buffer *btrfs_init_new_buffer(struct btrfs_trans_handle *trans,
                                            struct btrfs_root *root,
                                            u64 bytenr, u32 blocksize,
@@ -2089,6 +2100,10 @@ int btrfs_split_item(struct btrfs_trans_handle *trans,
                     struct btrfs_path *path,
                     struct btrfs_key *new_key,
                     unsigned long split_offset);
+int btrfs_duplicate_item(struct btrfs_trans_handle *trans,
+                        struct btrfs_root *root,
+                        struct btrfs_path *path,
+                        struct btrfs_key *new_key);
 int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
                      *root, struct btrfs_key *key, struct btrfs_path *p, int
                      ins_len, int cow);
@@ -2196,9 +2211,10 @@ int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
                              struct btrfs_path *path,
                              struct btrfs_dir_item *di);
 int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
-                           struct btrfs_root *root, const char *name,
-                           u16 name_len, const void *data, u16 data_len,
-                           u64 dir);
+                           struct btrfs_root *root,
+                           struct btrfs_path *path, u64 objectid,
+                           const char *name, u16 name_len,
+                           const void *data, u16 data_len);
 struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
                                          struct btrfs_root *root,
                                          struct btrfs_path *path, u64 dir,
@@ -2292,7 +2308,7 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
                               struct inode *inode, u64 new_size,
                               u32 min_type);
 
-int btrfs_start_delalloc_inodes(struct btrfs_root *root);
+int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput);
 int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end);
 int btrfs_writepages(struct address_space *mapping,
                     struct writeback_control *wbc);
@@ -2332,6 +2348,8 @@ int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode);
 void btrfs_orphan_cleanup(struct btrfs_root *root);
 int btrfs_cont_expand(struct inode *inode, loff_t size);
 int btrfs_invalidate_inodes(struct btrfs_root *root);
+void btrfs_add_delayed_iput(struct inode *inode);
+void btrfs_run_delayed_iputs(struct btrfs_root *root);
 extern const struct dentry_operations btrfs_dentry_operations;
 
 /* ioctl.c */
@@ -2345,12 +2363,9 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
                            int skip_pinned);
 int btrfs_check_file(struct btrfs_root *root, struct inode *inode);
 extern const struct file_operations btrfs_file_operations;
-int btrfs_drop_extents(struct btrfs_trans_handle *trans,
-                      struct btrfs_root *root, struct inode *inode,
-                      u64 start, u64 end, u64 locked_end,
-                      u64 inline_limit, u64 *hint_block, int drop_cache);
+int btrfs_drop_extents(struct btrfs_trans_handle *trans, struct inode *inode,
+                      u64 start, u64 end, u64 *hint_byte, int drop_cache);
 int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
-                             struct btrfs_root *root,
                              struct inode *inode, u64 start, u64 end);
 int btrfs_release_file(struct inode *inode, struct file *file);
 
@@ -2380,7 +2395,8 @@ int btrfs_check_acl(struct inode *inode, int mask);
 #else
 #define btrfs_check_acl NULL
 #endif
-int btrfs_init_acl(struct inode *inode, struct inode *dir);
+int btrfs_init_acl(struct btrfs_trans_handle *trans,
+                  struct inode *inode, struct inode *dir);
 int btrfs_acl_chmod(struct inode *inode);
 
 /* relocation.c */
index f3a6075519ccc1d96e42157f95769a5ad6641a12..e9103b3baa49f4309c94eca9e0d7b7069665359c 100644 (file)
@@ -68,12 +68,12 @@ static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
  * into the tree
  */
 int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
-                           struct btrfs_root *root, const char *name,
-                           u16 name_len, const void *data, u16 data_len,
-                           u64 dir)
+                           struct btrfs_root *root,
+                           struct btrfs_path *path, u64 objectid,
+                           const char *name, u16 name_len,
+                           const void *data, u16 data_len)
 {
        int ret = 0;
-       struct btrfs_path *path;
        struct btrfs_dir_item *dir_item;
        unsigned long name_ptr, data_ptr;
        struct btrfs_key key, location;
@@ -81,15 +81,11 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
        struct extent_buffer *leaf;
        u32 data_size;
 
-       key.objectid = dir;
+       BUG_ON(name_len + data_len > BTRFS_MAX_XATTR_SIZE(root));
+
+       key.objectid = objectid;
        btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY);
        key.offset = btrfs_name_hash(name, name_len);
-       path = btrfs_alloc_path();
-       if (!path)
-               return -ENOMEM;
-       if (name_len + data_len + sizeof(struct btrfs_dir_item) >
-           BTRFS_LEAF_DATA_SIZE(root) - sizeof(struct btrfs_item))
-               return -ENOSPC;
 
        data_size = sizeof(*dir_item) + name_len + data_len;
        dir_item = insert_with_overflow(trans, root, path, &key, data_size,
@@ -117,7 +113,6 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
        write_extent_buffer(leaf, data, data_ptr, data_len);
        btrfs_mark_buffer_dirty(path->nodes[0]);
 
-       btrfs_free_path(path);
        return ret;
 }
 
index 02b6afbd745020fb51bf43d88c93025459687e12..009e3bd18f23d986a685c50f60e3be73a5020f31 100644 (file)
@@ -892,6 +892,8 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
        root->stripesize = stripesize;
        root->ref_cows = 0;
        root->track_dirty = 0;
+       root->in_radix = 0;
+       root->clean_orphans = 0;
 
        root->fs_info = fs_info;
        root->objectid = objectid;
@@ -928,7 +930,6 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
        root->defrag_trans_start = fs_info->generation;
        init_completion(&root->kobj_unregister);
        root->defrag_running = 0;
-       root->defrag_level = 0;
        root->root_key.objectid = objectid;
        root->anon_super.s_root = NULL;
        root->anon_super.s_dev = 0;
@@ -980,12 +981,12 @@ int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans,
 
        while (1) {
                ret = find_first_extent_bit(&log_root_tree->dirty_log_pages,
-                                   0, &start, &end, EXTENT_DIRTY);
+                               0, &start, &end, EXTENT_DIRTY | EXTENT_NEW);
                if (ret)
                        break;
 
-               clear_extent_dirty(&log_root_tree->dirty_log_pages,
-                                  start, end, GFP_NOFS);
+               clear_extent_bits(&log_root_tree->dirty_log_pages, start, end,
+                                 EXTENT_DIRTY | EXTENT_NEW, GFP_NOFS);
        }
        eb = fs_info->log_root_tree->node;
 
@@ -1210,8 +1211,10 @@ again:
        ret = radix_tree_insert(&fs_info->fs_roots_radix,
                                (unsigned long)root->root_key.objectid,
                                root);
-       if (ret == 0)
+       if (ret == 0) {
                root->in_radix = 1;
+               root->clean_orphans = 1;
+       }
        spin_unlock(&fs_info->fs_roots_radix_lock);
        radix_tree_preload_end();
        if (ret) {
@@ -1225,10 +1228,6 @@ again:
        ret = btrfs_find_dead_roots(fs_info->tree_root,
                                    root->root_key.objectid);
        WARN_ON(ret);
-
-       if (!(fs_info->sb->s_flags & MS_RDONLY))
-               btrfs_orphan_cleanup(root);
-
        return root;
 fail:
        free_fs_root(root);
@@ -1477,6 +1476,7 @@ static int cleaner_kthread(void *arg)
 
                if (!(root->fs_info->sb->s_flags & MS_RDONLY) &&
                    mutex_trylock(&root->fs_info->cleaner_mutex)) {
+                       btrfs_run_delayed_iputs(root);
                        btrfs_clean_old_snapshots(root);
                        mutex_unlock(&root->fs_info->cleaner_mutex);
                }
@@ -1606,6 +1606,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_ATOMIC);
        INIT_LIST_HEAD(&fs_info->trans_list);
        INIT_LIST_HEAD(&fs_info->dead_roots);
+       INIT_LIST_HEAD(&fs_info->delayed_iputs);
        INIT_LIST_HEAD(&fs_info->hashers);
        INIT_LIST_HEAD(&fs_info->delalloc_inodes);
        INIT_LIST_HEAD(&fs_info->ordered_operations);
@@ -1614,6 +1615,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        spin_lock_init(&fs_info->new_trans_lock);
        spin_lock_init(&fs_info->ref_cache_lock);
        spin_lock_init(&fs_info->fs_roots_radix_lock);
+       spin_lock_init(&fs_info->delayed_iput_lock);
 
        init_completion(&fs_info->kobj_unregister);
        fs_info->tree_root = tree_root;
@@ -1689,6 +1691,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        mutex_init(&fs_info->cleaner_mutex);
        mutex_init(&fs_info->volume_mutex);
        init_rwsem(&fs_info->extent_commit_sem);
+       init_rwsem(&fs_info->cleanup_work_sem);
        init_rwsem(&fs_info->subvol_sem);
 
        btrfs_init_free_cluster(&fs_info->meta_alloc_cluster);
@@ -2386,8 +2389,14 @@ int btrfs_commit_super(struct btrfs_root *root)
        int ret;
 
        mutex_lock(&root->fs_info->cleaner_mutex);
+       btrfs_run_delayed_iputs(root);
        btrfs_clean_old_snapshots(root);
        mutex_unlock(&root->fs_info->cleaner_mutex);
+
+       /* wait until ongoing cleanup work done */
+       down_write(&root->fs_info->cleanup_work_sem);
+       up_write(&root->fs_info->cleanup_work_sem);
+
        trans = btrfs_start_transaction(root, 1);
        ret = btrfs_commit_transaction(trans, root);
        BUG_ON(ret);
index 94627c4cc193343aacc82b3aca1a6e9eaaefd8dd..56e50137d0e6d066266c074b1e07e10d10cb1b5f 100644 (file)
@@ -195,6 +195,14 @@ static int exclude_super_stripes(struct btrfs_root *root,
        int stripe_len;
        int i, nr, ret;
 
+       if (cache->key.objectid < BTRFS_SUPER_INFO_OFFSET) {
+               stripe_len = BTRFS_SUPER_INFO_OFFSET - cache->key.objectid;
+               cache->bytes_super += stripe_len;
+               ret = add_excluded_extent(root, cache->key.objectid,
+                                         stripe_len);
+               BUG_ON(ret);
+       }
+
        for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
                bytenr = btrfs_sb_offset(i);
                ret = btrfs_rmap_block(&root->fs_info->mapping_tree,
@@ -255,7 +263,7 @@ static u64 add_new_free_space(struct btrfs_block_group_cache *block_group,
                if (ret)
                        break;
 
-               if (extent_start == start) {
+               if (extent_start <= start) {
                        start = extent_end + 1;
                } else if (extent_start > start && extent_start < end) {
                        size = extent_start - start;
@@ -2880,9 +2888,9 @@ static noinline void flush_delalloc_async(struct btrfs_work *work)
        root = async->root;
        info = async->info;
 
-       btrfs_start_delalloc_inodes(root);
+       btrfs_start_delalloc_inodes(root, 0);
        wake_up(&info->flush_wait);
-       btrfs_wait_ordered_extents(root, 0);
+       btrfs_wait_ordered_extents(root, 0, 0);
 
        spin_lock(&info->lock);
        info->flushing = 0;
@@ -2956,8 +2964,8 @@ static void flush_delalloc(struct btrfs_root *root,
        return;
 
 flush:
-       btrfs_start_delalloc_inodes(root);
-       btrfs_wait_ordered_extents(root, 0);
+       btrfs_start_delalloc_inodes(root, 0);
+       btrfs_wait_ordered_extents(root, 0, 0);
 
        spin_lock(&info->lock);
        info->flushing = 0;
@@ -3454,14 +3462,6 @@ static int update_block_group(struct btrfs_trans_handle *trans,
        else
                old_val -= num_bytes;
        btrfs_set_super_bytes_used(&info->super_copy, old_val);
-
-       /* block accounting for root item */
-       old_val = btrfs_root_used(&root->root_item);
-       if (alloc)
-               old_val += num_bytes;
-       else
-               old_val -= num_bytes;
-       btrfs_set_root_used(&root->root_item, old_val);
        spin_unlock(&info->delalloc_lock);
 
        while (total) {
@@ -4049,6 +4049,21 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans,
        return ret;
 }
 
+int btrfs_free_tree_block(struct btrfs_trans_handle *trans,
+                         struct btrfs_root *root,
+                         u64 bytenr, u32 blocksize,
+                         u64 parent, u64 root_objectid, int level)
+{
+       u64 used;
+       spin_lock(&root->node_lock);
+       used = btrfs_root_used(&root->root_item) - blocksize;
+       btrfs_set_root_used(&root->root_item, used);
+       spin_unlock(&root->node_lock);
+
+       return btrfs_free_extent(trans, root, bytenr, blocksize,
+                                parent, root_objectid, level, 0);
+}
+
 static u64 stripe_align(struct btrfs_root *root, u64 val)
 {
        u64 mask = ((u64)root->stripesize - 1);
@@ -4578,7 +4593,6 @@ int btrfs_reserve_extent(struct btrfs_trans_handle *trans,
 {
        int ret;
        u64 search_start = 0;
-       struct btrfs_fs_info *info = root->fs_info;
 
        data = btrfs_get_alloc_profile(root, data);
 again:
@@ -4586,17 +4600,9 @@ again:
         * the only place that sets empty_size is btrfs_realloc_node, which
         * is not called recursively on allocations
         */
-       if (empty_size || root->ref_cows) {
-               if (!(data & BTRFS_BLOCK_GROUP_METADATA)) {
-                       ret = do_chunk_alloc(trans, root->fs_info->extent_root,
-                                    2 * 1024 * 1024,
-                                    BTRFS_BLOCK_GROUP_METADATA |
-                                    (info->metadata_alloc_profile &
-                                     info->avail_metadata_alloc_bits), 0);
-               }
+       if (empty_size || root->ref_cows)
                ret = do_chunk_alloc(trans, root->fs_info->extent_root,
                                     num_bytes + 2 * 1024 * 1024, data, 0);
-       }
 
        WARN_ON(num_bytes < root->sectorsize);
        ret = find_free_extent(trans, root, num_bytes, empty_size,
@@ -4897,6 +4903,14 @@ static int alloc_tree_block(struct btrfs_trans_handle *trans,
                                        extent_op);
                BUG_ON(ret);
        }
+
+       if (root_objectid == root->root_key.objectid) {
+               u64 used;
+               spin_lock(&root->node_lock);
+               used = btrfs_root_used(&root->root_item) + num_bytes;
+               btrfs_set_root_used(&root->root_item, used);
+               spin_unlock(&root->node_lock);
+       }
        return ret;
 }
 
@@ -4919,8 +4933,16 @@ struct extent_buffer *btrfs_init_new_buffer(struct btrfs_trans_handle *trans,
        btrfs_set_buffer_uptodate(buf);
 
        if (root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID) {
-               set_extent_dirty(&root->dirty_log_pages, buf->start,
-                        buf->start + buf->len - 1, GFP_NOFS);
+               /*
+                * we allow two log transactions at a time, use different
+                * EXENT bit to differentiate dirty pages.
+                */
+               if (root->log_transid % 2 == 0)
+                       set_extent_dirty(&root->dirty_log_pages, buf->start,
+                                       buf->start + buf->len - 1, GFP_NOFS);
+               else
+                       set_extent_new(&root->dirty_log_pages, buf->start,
+                                       buf->start + buf->len - 1, GFP_NOFS);
        } else {
                set_extent_dirty(&trans->transaction->dirty_pages, buf->start,
                         buf->start + buf->len - 1, GFP_NOFS);
index 77f759302e125da0467e8a3ff3341b6ee11f0b97..feaa13b105d953f1be72c50897fafa6943cd5e50 100644 (file)
@@ -179,18 +179,14 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
                }
                flags = em->flags;
                if (skip_pinned && test_bit(EXTENT_FLAG_PINNED, &em->flags)) {
-                       if (em->start <= start &&
-                           (!testend || em->start + em->len >= start + len)) {
+                       if (testend && em->start + em->len >= start + len) {
                                free_extent_map(em);
                                write_unlock(&em_tree->lock);
                                break;
                        }
-                       if (start < em->start) {
-                               len = em->start - start;
-                       } else {
+                       start = em->start + em->len;
+                       if (testend)
                                len = start + len - (em->start + em->len);
-                               start = em->start + em->len;
-                       }
                        free_extent_map(em);
                        write_unlock(&em_tree->lock);
                        continue;
@@ -265,319 +261,247 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
  * If an extent intersects the range but is not entirely inside the range
  * it is either truncated or split.  Anything entirely inside the range
  * is deleted from the tree.
- *
- * inline_limit is used to tell this code which offsets in the file to keep
- * if they contain inline extents.
  */
-noinline int btrfs_drop_extents(struct btrfs_trans_handle *trans,
-                      struct btrfs_root *root, struct inode *inode,
-                      u64 start, u64 end, u64 locked_end,
-                      u64 inline_limit, u64 *hint_byte, int drop_cache)
+int btrfs_drop_extents(struct btrfs_trans_handle *trans, struct inode *inode,
+                      u64 start, u64 end, u64 *hint_byte, int drop_cache)
 {
-       u64 extent_end = 0;
-       u64 search_start = start;
-       u64 ram_bytes = 0;
-       u64 disk_bytenr = 0;
-       u64 orig_locked_end = locked_end;
-       u8 compression;
-       u8 encryption;
-       u16 other_encoding = 0;
+       struct btrfs_root *root = BTRFS_I(inode)->root;
        struct extent_buffer *leaf;
-       struct btrfs_file_extent_item *extent;
+       struct btrfs_file_extent_item *fi;
        struct btrfs_path *path;
        struct btrfs_key key;
-       struct btrfs_file_extent_item old;
-       int keep;
-       int slot;
-       int bookend;
-       int found_type = 0;
-       int found_extent;
-       int found_inline;
+       struct btrfs_key new_key;
+       u64 search_start = start;
+       u64 disk_bytenr = 0;
+       u64 num_bytes = 0;
+       u64 extent_offset = 0;
+       u64 extent_end = 0;
+       int del_nr = 0;
+       int del_slot = 0;
+       int extent_type;
        int recow;
        int ret;
 
-       inline_limit = 0;
        if (drop_cache)
                btrfs_drop_extent_cache(inode, start, end - 1, 0);
 
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
+
        while (1) {
                recow = 0;
-               btrfs_release_path(root, path);
                ret = btrfs_lookup_file_extent(trans, root, path, inode->i_ino,
                                               search_start, -1);
                if (ret < 0)
-                       goto out;
-               if (ret > 0) {
-                       if (path->slots[0] == 0) {
-                               ret = 0;
-                               goto out;
-                       }
-                       path->slots[0]--;
+                       break;
+               if (ret > 0 && path->slots[0] > 0 && search_start == start) {
+                       leaf = path->nodes[0];
+                       btrfs_item_key_to_cpu(leaf, &key, path->slots[0] - 1);
+                       if (key.objectid == inode->i_ino &&
+                           key.type == BTRFS_EXTENT_DATA_KEY)
+                               path->slots[0]--;
                }
+               ret = 0;
 next_slot:
-               keep = 0;
-               bookend = 0;
-               found_extent = 0;
-               found_inline = 0;
-               compression = 0;
-               encryption = 0;
-               extent = NULL;
                leaf = path->nodes[0];
-               slot = path->slots[0];
-               ret = 0;
-               btrfs_item_key_to_cpu(leaf, &key, slot);
-               if (btrfs_key_type(&key) == BTRFS_EXTENT_DATA_KEY &&
-                   key.offset >= end) {
-                       goto out;
-               }
-               if (btrfs_key_type(&key) > BTRFS_EXTENT_DATA_KEY ||
-                   key.objectid != inode->i_ino) {
-                       goto out;
-               }
-               if (recow) {
-                       search_start = max(key.offset, start);
-                       continue;
-               }
-               if (btrfs_key_type(&key) == BTRFS_EXTENT_DATA_KEY) {
-                       extent = btrfs_item_ptr(leaf, slot,
-                                               struct btrfs_file_extent_item);
-                       found_type = btrfs_file_extent_type(leaf, extent);
-                       compression = btrfs_file_extent_compression(leaf,
-                                                                   extent);
-                       encryption = btrfs_file_extent_encryption(leaf,
-                                                                 extent);
-                       other_encoding = btrfs_file_extent_other_encoding(leaf,
-                                                                 extent);
-                       if (found_type == BTRFS_FILE_EXTENT_REG ||
-                           found_type == BTRFS_FILE_EXTENT_PREALLOC) {
-                               extent_end =
-                                    btrfs_file_extent_disk_bytenr(leaf,
-                                                                  extent);
-                               if (extent_end)
-                                       *hint_byte = extent_end;
-
-                               extent_end = key.offset +
-                                    btrfs_file_extent_num_bytes(leaf, extent);
-                               ram_bytes = btrfs_file_extent_ram_bytes(leaf,
-                                                               extent);
-                               found_extent = 1;
-                       } else if (found_type == BTRFS_FILE_EXTENT_INLINE) {
-                               found_inline = 1;
-                               extent_end = key.offset +
-                                    btrfs_file_extent_inline_len(leaf, extent);
+               if (path->slots[0] >= btrfs_header_nritems(leaf)) {
+                       BUG_ON(del_nr > 0);
+                       ret = btrfs_next_leaf(root, path);
+                       if (ret < 0)
+                               break;
+                       if (ret > 0) {
+                               ret = 0;
+                               break;
                        }
+                       leaf = path->nodes[0];
+                       recow = 1;
+               }
+
+               btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
+               if (key.objectid > inode->i_ino ||
+                   key.type > BTRFS_EXTENT_DATA_KEY || key.offset >= end)
+                       break;
+
+               fi = btrfs_item_ptr(leaf, path->slots[0],
+                                   struct btrfs_file_extent_item);
+               extent_type = btrfs_file_extent_type(leaf, fi);
+
+               if (extent_type == BTRFS_FILE_EXTENT_REG ||
+                   extent_type == BTRFS_FILE_EXTENT_PREALLOC) {
+                       disk_bytenr = btrfs_file_extent_disk_bytenr(leaf, fi);
+                       num_bytes = btrfs_file_extent_disk_num_bytes(leaf, fi);
+                       extent_offset = btrfs_file_extent_offset(leaf, fi);
+                       extent_end = key.offset +
+                               btrfs_file_extent_num_bytes(leaf, fi);
+               } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
+                       extent_end = key.offset +
+                               btrfs_file_extent_inline_len(leaf, fi);
                } else {
+                       WARN_ON(1);
                        extent_end = search_start;
                }
 
-               /* we found nothing we can drop */
-               if ((!found_extent && !found_inline) ||
-                   search_start >= extent_end) {
-                       int nextret;
-                       u32 nritems;
-                       nritems = btrfs_header_nritems(leaf);
-                       if (slot >= nritems - 1) {
-                               nextret = btrfs_next_leaf(root, path);
-                               if (nextret)
-                                       goto out;
-                               recow = 1;
-                       } else {
-                               path->slots[0]++;
-                       }
+               if (extent_end <= search_start) {
+                       path->slots[0]++;
                        goto next_slot;
                }
 
-               if (end <= extent_end && start >= key.offset && found_inline)
-                       *hint_byte = EXTENT_MAP_INLINE;
-
-               if (found_extent) {
-                       read_extent_buffer(leaf, &old, (unsigned long)extent,
-                                          sizeof(old));
-               }
-
-               if (end < extent_end && end >= key.offset) {
-                       bookend = 1;
-                       if (found_inline && start <= key.offset)
-                               keep = 1;
+               search_start = max(key.offset, start);
+               if (recow) {
+                       btrfs_release_path(root, path);
+                       continue;
                }
 
-               if (bookend && found_extent) {
-                       if (locked_end < extent_end) {
-                               ret = try_lock_extent(&BTRFS_I(inode)->io_tree,
-                                               locked_end, extent_end - 1,
-                                               GFP_NOFS);
-                               if (!ret) {
-                                       btrfs_release_path(root, path);
-                                       lock_extent(&BTRFS_I(inode)->io_tree,
-                                               locked_end, extent_end - 1,
-                                               GFP_NOFS);
-                                       locked_end = extent_end;
-                                       continue;
-                               }
-                               locked_end = extent_end;
+               /*
+                *     | - range to drop - |
+                *  | -------- extent -------- |
+                */
+               if (start > key.offset && end < extent_end) {
+                       BUG_ON(del_nr > 0);
+                       BUG_ON(extent_type == BTRFS_FILE_EXTENT_INLINE);
+
+                       memcpy(&new_key, &key, sizeof(new_key));
+                       new_key.offset = start;
+                       ret = btrfs_duplicate_item(trans, root, path,
+                                                  &new_key);
+                       if (ret == -EAGAIN) {
+                               btrfs_release_path(root, path);
+                               continue;
                        }
-                       disk_bytenr = le64_to_cpu(old.disk_bytenr);
-                       if (disk_bytenr != 0) {
+                       if (ret < 0)
+                               break;
+
+                       leaf = path->nodes[0];
+                       fi = btrfs_item_ptr(leaf, path->slots[0] - 1,
+                                           struct btrfs_file_extent_item);
+                       btrfs_set_file_extent_num_bytes(leaf, fi,
+                                                       start - key.offset);
+
+                       fi = btrfs_item_ptr(leaf, path->slots[0],
+                                           struct btrfs_file_extent_item);
+
+                       extent_offset += start - key.offset;
+                       btrfs_set_file_extent_offset(leaf, fi, extent_offset);
+                       btrfs_set_file_extent_num_bytes(leaf, fi,
+                                                       extent_end - start);
+                       btrfs_mark_buffer_dirty(leaf);
+
+                       if (disk_bytenr > 0) {
                                ret = btrfs_inc_extent_ref(trans, root,
-                                          disk_bytenr,
-                                          le64_to_cpu(old.disk_num_bytes), 0,
-                                          root->root_key.objectid,
-                                          key.objectid, key.offset -
-                                          le64_to_cpu(old.offset));
+                                               disk_bytenr, num_bytes, 0,
+                                               root->root_key.objectid,
+                                               new_key.objectid,
+                                               start - extent_offset);
                                BUG_ON(ret);
+                               *hint_byte = disk_bytenr;
                        }
+                       key.offset = start;
                }
+               /*
+                *  | ---- range to drop ----- |
+                *      | -------- extent -------- |
+                */
+               if (start <= key.offset && end < extent_end) {
+                       BUG_ON(extent_type == BTRFS_FILE_EXTENT_INLINE);
 
-               if (found_inline) {
-                       u64 mask = root->sectorsize - 1;
-                       search_start = (extent_end + mask) & ~mask;
-               } else
-                       search_start = extent_end;
-
-               /* truncate existing extent */
-               if (start > key.offset) {
-                       u64 new_num;
-                       u64 old_num;
-                       keep = 1;
-                       WARN_ON(start & (root->sectorsize - 1));
-                       if (found_extent) {
-                               new_num = start - key.offset;
-                               old_num = btrfs_file_extent_num_bytes(leaf,
-                                                                     extent);
-                               *hint_byte =
-                                       btrfs_file_extent_disk_bytenr(leaf,
-                                                                     extent);
-                               if (btrfs_file_extent_disk_bytenr(leaf,
-                                                                 extent)) {
-                                       inode_sub_bytes(inode, old_num -
-                                                       new_num);
-                               }
-                               btrfs_set_file_extent_num_bytes(leaf,
-                                                       extent, new_num);
-                               btrfs_mark_buffer_dirty(leaf);
-                       } else if (key.offset < inline_limit &&
-                                  (end > extent_end) &&
-                                  (inline_limit < extent_end)) {
-                               u32 new_size;
-                               new_size = btrfs_file_extent_calc_inline_size(
-                                                  inline_limit - key.offset);
-                               inode_sub_bytes(inode, extent_end -
-                                               inline_limit);
-                               btrfs_set_file_extent_ram_bytes(leaf, extent,
-                                                       new_size);
-                               if (!compression && !encryption) {
-                                       btrfs_truncate_item(trans, root, path,
-                                                           new_size, 1);
-                               }
+                       memcpy(&new_key, &key, sizeof(new_key));
+                       new_key.offset = end;
+                       btrfs_set_item_key_safe(trans, root, path, &new_key);
+
+                       extent_offset += end - key.offset;
+                       btrfs_set_file_extent_offset(leaf, fi, extent_offset);
+                       btrfs_set_file_extent_num_bytes(leaf, fi,
+                                                       extent_end - end);
+                       btrfs_mark_buffer_dirty(leaf);
+                       if (disk_bytenr > 0) {
+                               inode_sub_bytes(inode, end - key.offset);
+                               *hint_byte = disk_bytenr;
                        }
+                       break;
                }
-               /* delete the entire extent */
-               if (!keep) {
-                       if (found_inline)
-                               inode_sub_bytes(inode, extent_end -
-                                               key.offset);
-                       ret = btrfs_del_item(trans, root, path);
-                       /* TODO update progress marker and return */
-                       BUG_ON(ret);
-                       extent = NULL;
-                       btrfs_release_path(root, path);
-                       /* the extent will be freed later */
-               }
-               if (bookend && found_inline && start <= key.offset) {
-                       u32 new_size;
-                       new_size = btrfs_file_extent_calc_inline_size(
-                                                  extent_end - end);
-                       inode_sub_bytes(inode, end - key.offset);
-                       btrfs_set_file_extent_ram_bytes(leaf, extent,
-                                                       new_size);
-                       if (!compression && !encryption)
-                               ret = btrfs_truncate_item(trans, root, path,
-                                                         new_size, 0);
-                       BUG_ON(ret);
-               }
-               /* create bookend, splitting the extent in two */
-               if (bookend && found_extent) {
-                       struct btrfs_key ins;
-                       ins.objectid = inode->i_ino;
-                       ins.offset = end;
-                       btrfs_set_key_type(&ins, BTRFS_EXTENT_DATA_KEY);
 
-                       btrfs_release_path(root, path);
-                       path->leave_spinning = 1;
-                       ret = btrfs_insert_empty_item(trans, root, path, &ins,
-                                                     sizeof(*extent));
-                       BUG_ON(ret);
+               search_start = extent_end;
+               /*
+                *       | ---- range to drop ----- |
+                *  | -------- extent -------- |
+                */
+               if (start > key.offset && end >= extent_end) {
+                       BUG_ON(del_nr > 0);
+                       BUG_ON(extent_type == BTRFS_FILE_EXTENT_INLINE);
 
-                       leaf = path->nodes[0];
-                       extent = btrfs_item_ptr(leaf, path->slots[0],
-                                               struct btrfs_file_extent_item);
-                       write_extent_buffer(leaf, &old,
-                                           (unsigned long)extent, sizeof(old));
-
-                       btrfs_set_file_extent_compression(leaf, extent,
-                                                         compression);
-                       btrfs_set_file_extent_encryption(leaf, extent,
-                                                        encryption);
-                       btrfs_set_file_extent_other_encoding(leaf, extent,
-                                                            other_encoding);
-                       btrfs_set_file_extent_offset(leaf, extent,
-                                   le64_to_cpu(old.offset) + end - key.offset);
-                       WARN_ON(le64_to_cpu(old.num_bytes) <
-                               (extent_end - end));
-                       btrfs_set_file_extent_num_bytes(leaf, extent,
-                                                       extent_end - end);
+                       btrfs_set_file_extent_num_bytes(leaf, fi,
+                                                       start - key.offset);
+                       btrfs_mark_buffer_dirty(leaf);
+                       if (disk_bytenr > 0) {
+                               inode_sub_bytes(inode, extent_end - start);
+                               *hint_byte = disk_bytenr;
+                       }
+                       if (end == extent_end)
+                               break;
 
-                       /*
-                        * set the ram bytes to the size of the full extent
-                        * before splitting.  This is a worst case flag,
-                        * but its the best we can do because we don't know
-                        * how splitting affects compression
-                        */
-                       btrfs_set_file_extent_ram_bytes(leaf, extent,
-                                                       ram_bytes);
-                       btrfs_set_file_extent_type(leaf, extent, found_type);
-
-                       btrfs_unlock_up_safe(path, 1);
-                       btrfs_mark_buffer_dirty(path->nodes[0]);
-                       btrfs_set_lock_blocking(path->nodes[0]);
-
-                       path->leave_spinning = 0;
-                       btrfs_release_path(root, path);
-                       if (disk_bytenr != 0)
-                               inode_add_bytes(inode, extent_end - end);
+                       path->slots[0]++;
+                       goto next_slot;
                }
 
-               if (found_extent && !keep) {
-                       u64 old_disk_bytenr = le64_to_cpu(old.disk_bytenr);
+               /*
+                *  | ---- range to drop ----- |
+                *    | ------ extent ------ |
+                */
+               if (start <= key.offset && end >= extent_end) {
+                       if (del_nr == 0) {
+                               del_slot = path->slots[0];
+                               del_nr = 1;
+                       } else {
+                               BUG_ON(del_slot + del_nr != path->slots[0]);
+                               del_nr++;
+                       }
 
-                       if (old_disk_bytenr != 0) {
+                       if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
                                inode_sub_bytes(inode,
-                                               le64_to_cpu(old.num_bytes));
+                                               extent_end - key.offset);
+                               extent_end = ALIGN(extent_end,
+                                                  root->sectorsize);
+                       } else if (disk_bytenr > 0) {
                                ret = btrfs_free_extent(trans, root,
-                                               old_disk_bytenr,
-                                               le64_to_cpu(old.disk_num_bytes),
-                                               0, root->root_key.objectid,
+                                               disk_bytenr, num_bytes, 0,
+                                               root->root_key.objectid,
                                                key.objectid, key.offset -
-                                               le64_to_cpu(old.offset));
+                                               extent_offset);
                                BUG_ON(ret);
-                               *hint_byte = old_disk_bytenr;
+                               inode_sub_bytes(inode,
+                                               extent_end - key.offset);
+                               *hint_byte = disk_bytenr;
                        }
-               }
 
-               if (search_start >= end) {
-                       ret = 0;
-                       goto out;
+                       if (end == extent_end)
+                               break;
+
+                       if (path->slots[0] + 1 < btrfs_header_nritems(leaf)) {
+                               path->slots[0]++;
+                               goto next_slot;
+                       }
+
+                       ret = btrfs_del_items(trans, root, path, del_slot,
+                                             del_nr);
+                       BUG_ON(ret);
+
+                       del_nr = 0;
+                       del_slot = 0;
+
+                       btrfs_release_path(root, path);
+                       continue;
                }
+
+               BUG_ON(1);
        }
-out:
-       btrfs_free_path(path);
-       if (locked_end > orig_locked_end) {
-               unlock_extent(&BTRFS_I(inode)->io_tree, orig_locked_end,
-                             locked_end - 1, GFP_NOFS);
+
+       if (del_nr > 0) {
+               ret = btrfs_del_items(trans, root, path, del_slot, del_nr);
+               BUG_ON(ret);
        }
+
+       btrfs_free_path(path);
        return ret;
 }
 
@@ -620,23 +544,23 @@ static int extent_mergeable(struct extent_buffer *leaf, int slot,
  * two or three.
  */
 int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
-                             struct btrfs_root *root,
                              struct inode *inode, u64 start, u64 end)
 {
+       struct btrfs_root *root = BTRFS_I(inode)->root;
        struct extent_buffer *leaf;
        struct btrfs_path *path;
        struct btrfs_file_extent_item *fi;
        struct btrfs_key key;
+       struct btrfs_key new_key;
        u64 bytenr;
        u64 num_bytes;
        u64 extent_end;
        u64 orig_offset;
        u64 other_start;
        u64 other_end;
-       u64 split = start;
-       u64 locked_end = end;
-       int extent_type;
-       int split_end = 1;
+       u64 split;
+       int del_nr = 0;
+       int del_slot = 0;
        int ret;
 
        btrfs_drop_extent_cache(inode, start, end - 1, 0);
@@ -644,12 +568,10 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
        path = btrfs_alloc_path();
        BUG_ON(!path);
 again:
+       split = start;
        key.objectid = inode->i_ino;
        key.type = BTRFS_EXTENT_DATA_KEY;
-       if (split == start)
-               key.offset = split;
-       else
-               key.offset = split - 1;
+       key.offset = split;
 
        ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
        if (ret > 0 && path->slots[0] > 0)
@@ -661,8 +583,8 @@ again:
               key.type != BTRFS_EXTENT_DATA_KEY);
        fi = btrfs_item_ptr(leaf, path->slots[0],
                            struct btrfs_file_extent_item);
-       extent_type = btrfs_file_extent_type(leaf, fi);
-       BUG_ON(extent_type != BTRFS_FILE_EXTENT_PREALLOC);
+       BUG_ON(btrfs_file_extent_type(leaf, fi) !=
+              BTRFS_FILE_EXTENT_PREALLOC);
        extent_end = key.offset + btrfs_file_extent_num_bytes(leaf, fi);
        BUG_ON(key.offset > start || extent_end < end);
 
@@ -670,150 +592,91 @@ again:
        num_bytes = btrfs_file_extent_disk_num_bytes(leaf, fi);
        orig_offset = key.offset - btrfs_file_extent_offset(leaf, fi);
 
-       if (key.offset == start)
-               split = end;
-
-       if (key.offset == start && extent_end == end) {
-               int del_nr = 0;
-               int del_slot = 0;
-               other_start = end;
-               other_end = 0;
-               if (extent_mergeable(leaf, path->slots[0] + 1, inode->i_ino,
-                                    bytenr, &other_start, &other_end)) {
-                       extent_end = other_end;
-                       del_slot = path->slots[0] + 1;
-                       del_nr++;
-                       ret = btrfs_free_extent(trans, root, bytenr, num_bytes,
-                                               0, root->root_key.objectid,
-                                               inode->i_ino, orig_offset);
-                       BUG_ON(ret);
-               }
-               other_start = 0;
-               other_end = start;
-               if (extent_mergeable(leaf, path->slots[0] - 1, inode->i_ino,
-                                    bytenr, &other_start, &other_end)) {
-                       key.offset = other_start;
-                       del_slot = path->slots[0];
-                       del_nr++;
-                       ret = btrfs_free_extent(trans, root, bytenr, num_bytes,
-                                               0, root->root_key.objectid,
-                                               inode->i_ino, orig_offset);
-                       BUG_ON(ret);
-               }
-               split_end = 0;
-               if (del_nr == 0) {
-                       btrfs_set_file_extent_type(leaf, fi,
-                                                  BTRFS_FILE_EXTENT_REG);
-                       goto done;
+       while (start > key.offset || end < extent_end) {
+               if (key.offset == start)
+                       split = end;
+
+               memcpy(&new_key, &key, sizeof(new_key));
+               new_key.offset = split;
+               ret = btrfs_duplicate_item(trans, root, path, &new_key);
+               if (ret == -EAGAIN) {
+                       btrfs_release_path(root, path);
+                       goto again;
                }
+               BUG_ON(ret < 0);
 
-               fi = btrfs_item_ptr(leaf, del_slot - 1,
+               leaf = path->nodes[0];
+               fi = btrfs_item_ptr(leaf, path->slots[0] - 1,
                                    struct btrfs_file_extent_item);
-               btrfs_set_file_extent_type(leaf, fi, BTRFS_FILE_EXTENT_REG);
                btrfs_set_file_extent_num_bytes(leaf, fi,
-                                               extent_end - key.offset);
+                                               split - key.offset);
+
+               fi = btrfs_item_ptr(leaf, path->slots[0],
+                                   struct btrfs_file_extent_item);
+
+               btrfs_set_file_extent_offset(leaf, fi, split - orig_offset);
+               btrfs_set_file_extent_num_bytes(leaf, fi,
+                                               extent_end - split);
                btrfs_mark_buffer_dirty(leaf);
 
-               ret = btrfs_del_items(trans, root, path, del_slot, del_nr);
+               ret = btrfs_inc_extent_ref(trans, root, bytenr, num_bytes, 0,
+                                          root->root_key.objectid,
+                                          inode->i_ino, orig_offset);
                BUG_ON(ret);
-               goto release;
-       } else if (split == start) {
-               if (locked_end < extent_end) {
-                       ret = try_lock_extent(&BTRFS_I(inode)->io_tree,
-                                       locked_end, extent_end - 1, GFP_NOFS);
-                       if (!ret) {
-                               btrfs_release_path(root, path);
-                               lock_extent(&BTRFS_I(inode)->io_tree,
-                                       locked_end, extent_end - 1, GFP_NOFS);
-                               locked_end = extent_end;
-                               goto again;
-                       }
-                       locked_end = extent_end;
-               }
-               btrfs_set_file_extent_num_bytes(leaf, fi, split - key.offset);
-       } else  {
-               BUG_ON(key.offset != start);
-               key.offset = split;
-               btrfs_set_file_extent_offset(leaf, fi, key.offset -
-                                            orig_offset);
-               btrfs_set_file_extent_num_bytes(leaf, fi, extent_end - split);
-               btrfs_set_item_key_safe(trans, root, path, &key);
-               extent_end = split;
-       }
 
-       if (extent_end == end) {
-               split_end = 0;
-               extent_type = BTRFS_FILE_EXTENT_REG;
-       }
-       if (extent_end == end && split == start) {
-               other_start = end;
-               other_end = 0;
-               if (extent_mergeable(leaf, path->slots[0] + 1, inode->i_ino,
-                                    bytenr, &other_start, &other_end)) {
-                       path->slots[0]++;
-                       fi = btrfs_item_ptr(leaf, path->slots[0],
-                                           struct btrfs_file_extent_item);
-                       key.offset = split;
-                       btrfs_set_item_key_safe(trans, root, path, &key);
-                       btrfs_set_file_extent_offset(leaf, fi, key.offset -
-                                                    orig_offset);
-                       btrfs_set_file_extent_num_bytes(leaf, fi,
-                                                       other_end - split);
-                       goto done;
-               }
-       }
-       if (extent_end == end && split == end) {
-               other_start = 0;
-               other_end = start;
-               if (extent_mergeable(leaf, path->slots[0] - 1 , inode->i_ino,
-                                    bytenr, &other_start, &other_end)) {
+               if (split == start) {
+                       key.offset = start;
+               } else {
+                       BUG_ON(start != key.offset);
                        path->slots[0]--;
-                       fi = btrfs_item_ptr(leaf, path->slots[0],
-                                           struct btrfs_file_extent_item);
-                       btrfs_set_file_extent_num_bytes(leaf, fi, extent_end -
-                                                       other_start);
-                       goto done;
+                       extent_end = end;
                }
        }
 
-       btrfs_mark_buffer_dirty(leaf);
-
-       ret = btrfs_inc_extent_ref(trans, root, bytenr, num_bytes, 0,
-                                  root->root_key.objectid,
-                                  inode->i_ino, orig_offset);
-       BUG_ON(ret);
-       btrfs_release_path(root, path);
-
-       key.offset = start;
-       ret = btrfs_insert_empty_item(trans, root, path, &key, sizeof(*fi));
-       BUG_ON(ret);
-
-       leaf = path->nodes[0];
        fi = btrfs_item_ptr(leaf, path->slots[0],
                            struct btrfs_file_extent_item);
-       btrfs_set_file_extent_generation(leaf, fi, trans->transid);
-       btrfs_set_file_extent_type(leaf, fi, extent_type);
-       btrfs_set_file_extent_disk_bytenr(leaf, fi, bytenr);
-       btrfs_set_file_extent_disk_num_bytes(leaf, fi, num_bytes);
-       btrfs_set_file_extent_offset(leaf, fi, key.offset - orig_offset);
-       btrfs_set_file_extent_num_bytes(leaf, fi, extent_end - key.offset);
-       btrfs_set_file_extent_ram_bytes(leaf, fi, num_bytes);
-       btrfs_set_file_extent_compression(leaf, fi, 0);
-       btrfs_set_file_extent_encryption(leaf, fi, 0);
-       btrfs_set_file_extent_other_encoding(leaf, fi, 0);
-done:
-       btrfs_mark_buffer_dirty(leaf);
 
-release:
-       btrfs_release_path(root, path);
-       if (split_end && split == start) {
-               split = end;
-               goto again;
+       other_start = end;
+       other_end = 0;
+       if (extent_mergeable(leaf, path->slots[0] + 1, inode->i_ino,
+                            bytenr, &other_start, &other_end)) {
+               extent_end = other_end;
+               del_slot = path->slots[0] + 1;
+               del_nr++;
+               ret = btrfs_free_extent(trans, root, bytenr, num_bytes,
+                                       0, root->root_key.objectid,
+                                       inode->i_ino, orig_offset);
+               BUG_ON(ret);
        }
-       if (locked_end > end) {
-               unlock_extent(&BTRFS_I(inode)->io_tree, end, locked_end - 1,
-                             GFP_NOFS);
+       other_start = 0;
+       other_end = start;
+       if (extent_mergeable(leaf, path->slots[0] - 1, inode->i_ino,
+                            bytenr, &other_start, &other_end)) {
+               key.offset = other_start;
+               del_slot = path->slots[0];
+               del_nr++;
+               ret = btrfs_free_extent(trans, root, bytenr, num_bytes,
+                                       0, root->root_key.objectid,
+                                       inode->i_ino, orig_offset);
+               BUG_ON(ret);
        }
+       if (del_nr == 0) {
+               btrfs_set_file_extent_type(leaf, fi,
+                                          BTRFS_FILE_EXTENT_REG);
+               btrfs_mark_buffer_dirty(leaf);
+               goto out;
+       }
+
+       fi = btrfs_item_ptr(leaf, del_slot - 1,
+                           struct btrfs_file_extent_item);
+       btrfs_set_file_extent_type(leaf, fi, BTRFS_FILE_EXTENT_REG);
+       btrfs_set_file_extent_num_bytes(leaf, fi,
+                                       extent_end - key.offset);
+       btrfs_mark_buffer_dirty(leaf);
+
+       ret = btrfs_del_items(trans, root, path, del_slot, del_nr);
+       BUG_ON(ret);
+out:
        btrfs_free_path(path);
        return 0;
 }
index b3ad168a0bfc97906dd1fa556b61297250faae58..5440bab2363565e5c50399eb32b9f6e8ed103728 100644 (file)
@@ -88,13 +88,14 @@ static noinline int cow_file_range(struct inode *inode,
                                   u64 start, u64 end, int *page_started,
                                   unsigned long *nr_written, int unlock);
 
-static int btrfs_init_inode_security(struct inode *inode,  struct inode *dir)
+static int btrfs_init_inode_security(struct btrfs_trans_handle *trans,
+                                    struct inode *inode,  struct inode *dir)
 {
        int err;
 
-       err = btrfs_init_acl(inode, dir);
+       err = btrfs_init_acl(trans, inode, dir);
        if (!err)
-               err = btrfs_xattr_security_init(inode, dir);
+               err = btrfs_xattr_security_init(trans, inode, dir);
        return err;
 }
 
@@ -188,8 +189,18 @@ static noinline int insert_inline_extent(struct btrfs_trans_handle *trans,
        btrfs_mark_buffer_dirty(leaf);
        btrfs_free_path(path);
 
+       /*
+        * we're an inline extent, so nobody can
+        * extend the file past i_size without locking
+        * a page we already have locked.
+        *
+        * We must do any isize and inode updates
+        * before we unlock the pages.  Otherwise we
+        * could end up racing with unlink.
+        */
        BTRFS_I(inode)->disk_i_size = inode->i_size;
        btrfs_update_inode(trans, root, inode);
+
        return 0;
 fail:
        btrfs_free_path(path);
@@ -230,8 +241,7 @@ static noinline int cow_file_range_inline(struct btrfs_trans_handle *trans,
                return 1;
        }
 
-       ret = btrfs_drop_extents(trans, root, inode, start,
-                                aligned_end, aligned_end, start,
+       ret = btrfs_drop_extents(trans, inode, start, aligned_end,
                                 &hint_byte, 1);
        BUG_ON(ret);
 
@@ -416,7 +426,6 @@ again:
                                                    start, end,
                                                    total_compressed, pages);
                }
-               btrfs_end_transaction(trans, root);
                if (ret == 0) {
                        /*
                         * inline extent creation worked, we don't need
@@ -430,9 +439,11 @@ again:
                             EXTENT_CLEAR_DELALLOC |
                             EXTENT_CLEAR_ACCOUNTING |
                             EXTENT_SET_WRITEBACK | EXTENT_END_WRITEBACK);
-                       ret = 0;
+
+                       btrfs_end_transaction(trans, root);
                        goto free_pages_out;
                }
+               btrfs_end_transaction(trans, root);
        }
 
        if (will_compress) {
@@ -543,7 +554,6 @@ static noinline int submit_compressed_extents(struct inode *inode,
        if (list_empty(&async_cow->extents))
                return 0;
 
-       trans = btrfs_join_transaction(root, 1);
 
        while (!list_empty(&async_cow->extents)) {
                async_extent = list_entry(async_cow->extents.next,
@@ -590,19 +600,15 @@ retry:
                lock_extent(io_tree, async_extent->start,
                            async_extent->start + async_extent->ram_size - 1,
                            GFP_NOFS);
-               /*
-                * here we're doing allocation and writeback of the
-                * compressed pages
-                */
-               btrfs_drop_extent_cache(inode, async_extent->start,
-                                       async_extent->start +
-                                       async_extent->ram_size - 1, 0);
 
+               trans = btrfs_join_transaction(root, 1);
                ret = btrfs_reserve_extent(trans, root,
                                           async_extent->compressed_size,
                                           async_extent->compressed_size,
                                           0, alloc_hint,
                                           (u64)-1, &ins, 1);
+               btrfs_end_transaction(trans, root);
+
                if (ret) {
                        int i;
                        for (i = 0; i < async_extent->nr_pages; i++) {
@@ -618,6 +624,14 @@ retry:
                        goto retry;
                }
 
+               /*
+                * here we're doing allocation and writeback of the
+                * compressed pages
+                */
+               btrfs_drop_extent_cache(inode, async_extent->start,
+                                       async_extent->start +
+                                       async_extent->ram_size - 1, 0);
+
                em = alloc_extent_map(GFP_NOFS);
                em->start = async_extent->start;
                em->len = async_extent->ram_size;
@@ -649,8 +663,6 @@ retry:
                                               BTRFS_ORDERED_COMPRESSED);
                BUG_ON(ret);
 
-               btrfs_end_transaction(trans, root);
-
                /*
                 * clear dirty, set writeback and unlock the pages.
                 */
@@ -672,13 +684,11 @@ retry:
                                    async_extent->nr_pages);
 
                BUG_ON(ret);
-               trans = btrfs_join_transaction(root, 1);
                alloc_hint = ins.objectid + ins.offset;
                kfree(async_extent);
                cond_resched();
        }
 
-       btrfs_end_transaction(trans, root);
        return 0;
 }
 
@@ -742,6 +752,7 @@ static noinline int cow_file_range(struct inode *inode,
                                     EXTENT_CLEAR_DIRTY |
                                     EXTENT_SET_WRITEBACK |
                                     EXTENT_END_WRITEBACK);
+
                        *nr_written = *nr_written +
                             (end - start + PAGE_CACHE_SIZE) / PAGE_CACHE_SIZE;
                        *page_started = 1;
@@ -1596,7 +1607,6 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
                                       struct inode *inode, u64 file_pos,
                                       u64 disk_bytenr, u64 disk_num_bytes,
                                       u64 num_bytes, u64 ram_bytes,
-                                      u64 locked_end,
                                       u8 compression, u8 encryption,
                                       u16 other_encoding, int extent_type)
 {
@@ -1622,9 +1632,8 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
         * the caller is expected to unpin it and allow it to be merged
         * with the others.
         */
-       ret = btrfs_drop_extents(trans, root, inode, file_pos,
-                                file_pos + num_bytes, locked_end,
-                                file_pos, &hint, 0);
+       ret = btrfs_drop_extents(trans, inode, file_pos, file_pos + num_bytes,
+                                &hint, 0);
        BUG_ON(ret);
 
        ins.objectid = inode->i_ino;
@@ -1730,23 +1739,32 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
                }
        }
 
-       trans = btrfs_join_transaction(root, 1);
-
        if (!ordered_extent)
                ordered_extent = btrfs_lookup_ordered_extent(inode, start);
        BUG_ON(!ordered_extent);
-       if (test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags))
-               goto nocow;
+       if (test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags)) {
+               BUG_ON(!list_empty(&ordered_extent->list));
+               ret = btrfs_ordered_update_i_size(inode, 0, ordered_extent);
+               if (!ret) {
+                       trans = btrfs_join_transaction(root, 1);
+                       ret = btrfs_update_inode(trans, root, inode);
+                       BUG_ON(ret);
+                       btrfs_end_transaction(trans, root);
+               }
+               goto out;
+       }
 
        lock_extent(io_tree, ordered_extent->file_offset,
                    ordered_extent->file_offset + ordered_extent->len - 1,
                    GFP_NOFS);
 
+       trans = btrfs_join_transaction(root, 1);
+
        if (test_bit(BTRFS_ORDERED_COMPRESSED, &ordered_extent->flags))
                compressed = 1;
        if (test_bit(BTRFS_ORDERED_PREALLOC, &ordered_extent->flags)) {
                BUG_ON(compressed);
-               ret = btrfs_mark_extent_written(trans, root, inode,
+               ret = btrfs_mark_extent_written(trans, inode,
                                                ordered_extent->file_offset,
                                                ordered_extent->file_offset +
                                                ordered_extent->len);
@@ -1758,8 +1776,6 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
                                                ordered_extent->disk_len,
                                                ordered_extent->len,
                                                ordered_extent->len,
-                                               ordered_extent->file_offset +
-                                               ordered_extent->len,
                                                compressed, 0, 0,
                                                BTRFS_FILE_EXTENT_REG);
                unpin_extent_cache(&BTRFS_I(inode)->extent_tree,
@@ -1770,22 +1786,20 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
        unlock_extent(io_tree, ordered_extent->file_offset,
                    ordered_extent->file_offset + ordered_extent->len - 1,
                    GFP_NOFS);
-nocow:
        add_pending_csums(trans, inode, ordered_extent->file_offset,
                          &ordered_extent->list);
 
-       mutex_lock(&BTRFS_I(inode)->extent_mutex);
-       btrfs_ordered_update_i_size(inode, ordered_extent);
-       btrfs_update_inode(trans, root, inode);
-       btrfs_remove_ordered_extent(inode, ordered_extent);
-       mutex_unlock(&BTRFS_I(inode)->extent_mutex);
-
+       /* this also removes the ordered extent from the tree */
+       btrfs_ordered_update_i_size(inode, 0, ordered_extent);
+       ret = btrfs_update_inode(trans, root, inode);
+       BUG_ON(ret);
+       btrfs_end_transaction(trans, root);
+out:
        /* once for us */
        btrfs_put_ordered_extent(ordered_extent);
        /* once for the tree */
        btrfs_put_ordered_extent(ordered_extent);
 
-       btrfs_end_transaction(trans, root);
        return 0;
 }
 
@@ -2008,6 +2022,54 @@ zeroit:
        return -EIO;
 }
 
+struct delayed_iput {
+       struct list_head list;
+       struct inode *inode;
+};
+
+void btrfs_add_delayed_iput(struct inode *inode)
+{
+       struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info;
+       struct delayed_iput *delayed;
+
+       if (atomic_add_unless(&inode->i_count, -1, 1))
+               return;
+
+       delayed = kmalloc(sizeof(*delayed), GFP_NOFS | __GFP_NOFAIL);
+       delayed->inode = inode;
+
+       spin_lock(&fs_info->delayed_iput_lock);
+       list_add_tail(&delayed->list, &fs_info->delayed_iputs);
+       spin_unlock(&fs_info->delayed_iput_lock);
+}
+
+void btrfs_run_delayed_iputs(struct btrfs_root *root)
+{
+       LIST_HEAD(list);
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       struct delayed_iput *delayed;
+       int empty;
+
+       spin_lock(&fs_info->delayed_iput_lock);
+       empty = list_empty(&fs_info->delayed_iputs);
+       spin_unlock(&fs_info->delayed_iput_lock);
+       if (empty)
+               return;
+
+       down_read(&root->fs_info->cleanup_work_sem);
+       spin_lock(&fs_info->delayed_iput_lock);
+       list_splice_init(&fs_info->delayed_iputs, &list);
+       spin_unlock(&fs_info->delayed_iput_lock);
+
+       while (!list_empty(&list)) {
+               delayed = list_entry(list.next, struct delayed_iput, list);
+               list_del(&delayed->list);
+               iput(delayed->inode);
+               kfree(delayed);
+       }
+       up_read(&root->fs_info->cleanup_work_sem);
+}
+
 /*
  * This creates an orphan entry for the given inode in case something goes
  * wrong in the middle of an unlink/truncate.
@@ -2080,16 +2142,17 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
        struct inode *inode;
        int ret = 0, nr_unlink = 0, nr_truncate = 0;
 
-       path = btrfs_alloc_path();
-       if (!path)
+       if (!xchg(&root->clean_orphans, 0))
                return;
+
+       path = btrfs_alloc_path();
+       BUG_ON(!path);
        path->reada = -1;
 
        key.objectid = BTRFS_ORPHAN_OBJECTID;
        btrfs_set_key_type(&key, BTRFS_ORPHAN_ITEM_KEY);
        key.offset = (u64)-1;
 
-
        while (1) {
                ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
                if (ret < 0) {
@@ -2834,37 +2897,40 @@ out:
  * min_type is the minimum key type to truncate down to.  If set to 0, this
  * will kill all the items on this inode, including the INODE_ITEM_KEY.
  */
-noinline int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
-                                       struct btrfs_root *root,
-                                       struct inode *inode,
-                                       u64 new_size, u32 min_type)
+int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
+                              struct btrfs_root *root,
+                              struct inode *inode,
+                              u64 new_size, u32 min_type)
 {
-       int ret;
        struct btrfs_path *path;
-       struct btrfs_key key;
-       struct btrfs_key found_key;
-       u32 found_type = (u8)-1;
        struct extent_buffer *leaf;
        struct btrfs_file_extent_item *fi;
+       struct btrfs_key key;
+       struct btrfs_key found_key;
        u64 extent_start = 0;
        u64 extent_num_bytes = 0;
        u64 extent_offset = 0;
        u64 item_end = 0;
+       u64 mask = root->sectorsize - 1;
+       u32 found_type = (u8)-1;
        int found_extent;
        int del_item;
        int pending_del_nr = 0;
        int pending_del_slot = 0;
        int extent_type = -1;
        int encoding;
-       u64 mask = root->sectorsize - 1;
+       int ret;
+       int err = 0;
+
+       BUG_ON(new_size > 0 && min_type != BTRFS_EXTENT_DATA_KEY);
 
        if (root->ref_cows)
                btrfs_drop_extent_cache(inode, new_size & (~mask), (u64)-1, 0);
+
        path = btrfs_alloc_path();
        BUG_ON(!path);
        path->reada = -1;
 
-       /* FIXME, add redo link to tree so we don't leak on crash */
        key.objectid = inode->i_ino;
        key.offset = (u64)-1;
        key.type = (u8)-1;
@@ -2872,17 +2938,17 @@ noinline int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
 search_again:
        path->leave_spinning = 1;
        ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
-       if (ret < 0)
-               goto error;
+       if (ret < 0) {
+               err = ret;
+               goto out;
+       }
 
        if (ret > 0) {
                /* there are no items in the tree for us to truncate, we're
                 * done
                 */
-               if (path->slots[0] == 0) {
-                       ret = 0;
-                       goto error;
-               }
+               if (path->slots[0] == 0)
+                       goto out;
                path->slots[0]--;
        }
 
@@ -2917,28 +2983,17 @@ search_again:
                        }
                        item_end--;
                }
-               if (item_end < new_size) {
-                       if (found_type == BTRFS_DIR_ITEM_KEY)
-                               found_type = BTRFS_INODE_ITEM_KEY;
-                       else if (found_type == BTRFS_EXTENT_ITEM_KEY)
-                               found_type = BTRFS_EXTENT_DATA_KEY;
-                       else if (found_type == BTRFS_EXTENT_DATA_KEY)
-                               found_type = BTRFS_XATTR_ITEM_KEY;
-                       else if (found_type == BTRFS_XATTR_ITEM_KEY)
-                               found_type = BTRFS_INODE_REF_KEY;
-                       else if (found_type)
-                               found_type--;
-                       else
+               if (found_type > min_type) {
+                       del_item = 1;
+               } else {
+                       if (item_end < new_size)
                                break;
-                       btrfs_set_key_type(&key, found_type);
-                       goto next;
+                       if (found_key.offset >= new_size)
+                               del_item = 1;
+                       else
+                               del_item = 0;
                }
-               if (found_key.offset >= new_size)
-                       del_item = 1;
-               else
-                       del_item = 0;
                found_extent = 0;
-
                /* FIXME, shrink the extent if the ref count is only 1 */
                if (found_type != BTRFS_EXTENT_DATA_KEY)
                        goto delete;
@@ -3025,42 +3080,36 @@ delete:
                                                inode->i_ino, extent_offset);
                        BUG_ON(ret);
                }
-next:
-               if (path->slots[0] == 0) {
-                       if (pending_del_nr)
-                               goto del_pending;
-                       btrfs_release_path(root, path);
-                       if (found_type == BTRFS_INODE_ITEM_KEY)
-                               break;
-                       goto search_again;
-               }
 
-               path->slots[0]--;
-               if (pending_del_nr &&
-                   path->slots[0] + 1 != pending_del_slot) {
-                       struct btrfs_key debug;
-del_pending:
-                       btrfs_item_key_to_cpu(path->nodes[0], &debug,
-                                             pending_del_slot);
-                       ret = btrfs_del_items(trans, root, path,
-                                             pending_del_slot,
-                                             pending_del_nr);
-                       BUG_ON(ret);
-                       pending_del_nr = 0;
+               if (found_type == BTRFS_INODE_ITEM_KEY)
+                       break;
+
+               if (path->slots[0] == 0 ||
+                   path->slots[0] != pending_del_slot) {
+                       if (root->ref_cows) {
+                               err = -EAGAIN;
+                               goto out;
+                       }
+                       if (pending_del_nr) {
+                               ret = btrfs_del_items(trans, root, path,
+                                               pending_del_slot,
+                                               pending_del_nr);
+                               BUG_ON(ret);
+                               pending_del_nr = 0;
+                       }
                        btrfs_release_path(root, path);
-                       if (found_type == BTRFS_INODE_ITEM_KEY)
-                               break;
                        goto search_again;
+               } else {
+                       path->slots[0]--;
                }
        }
-       ret = 0;
-error:
+out:
        if (pending_del_nr) {
                ret = btrfs_del_items(trans, root, path, pending_del_slot,
                                      pending_del_nr);
        }
        btrfs_free_path(path);
-       return ret;
+       return err;
 }
 
 /*
@@ -3180,10 +3229,6 @@ int btrfs_cont_expand(struct inode *inode, loff_t size)
        if (size <= hole_start)
                return 0;
 
-       err = btrfs_truncate_page(inode->i_mapping, inode->i_size);
-       if (err)
-               return err;
-
        while (1) {
                struct btrfs_ordered_extent *ordered;
                btrfs_wait_ordered_range(inode, hole_start,
@@ -3196,9 +3241,6 @@ int btrfs_cont_expand(struct inode *inode, loff_t size)
                btrfs_put_ordered_extent(ordered);
        }
 
-       trans = btrfs_start_transaction(root, 1);
-       btrfs_set_trans_block_group(trans, inode);
-
        cur_offset = hole_start;
        while (1) {
                em = btrfs_get_extent(inode, NULL, 0, cur_offset,
@@ -3206,40 +3248,120 @@ int btrfs_cont_expand(struct inode *inode, loff_t size)
                BUG_ON(IS_ERR(em) || !em);
                last_byte = min(extent_map_end(em), block_end);
                last_byte = (last_byte + mask) & ~mask;
-               if (test_bit(EXTENT_FLAG_VACANCY, &em->flags)) {
+               if (!test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) {
                        u64 hint_byte = 0;
                        hole_size = last_byte - cur_offset;
-                       err = btrfs_drop_extents(trans, root, inode,
-                                                cur_offset,
-                                                cur_offset + hole_size,
-                                                block_end,
-                                                cur_offset, &hint_byte, 1);
-                       if (err)
-                               break;
 
-                       err = btrfs_reserve_metadata_space(root, 1);
+                       err = btrfs_reserve_metadata_space(root, 2);
                        if (err)
                                break;
 
+                       trans = btrfs_start_transaction(root, 1);
+                       btrfs_set_trans_block_group(trans, inode);
+
+                       err = btrfs_drop_extents(trans, inode, cur_offset,
+                                                cur_offset + hole_size,
+                                                &hint_byte, 1);
+                       BUG_ON(err);
+
                        err = btrfs_insert_file_extent(trans, root,
                                        inode->i_ino, cur_offset, 0,
                                        0, hole_size, 0, hole_size,
                                        0, 0, 0);
+                       BUG_ON(err);
+
                        btrfs_drop_extent_cache(inode, hole_start,
                                        last_byte - 1, 0);
-                       btrfs_unreserve_metadata_space(root, 1);
+
+                       btrfs_end_transaction(trans, root);
+                       btrfs_unreserve_metadata_space(root, 2);
                }
                free_extent_map(em);
                cur_offset = last_byte;
-               if (err || cur_offset >= block_end)
+               if (cur_offset >= block_end)
                        break;
        }
 
-       btrfs_end_transaction(trans, root);
        unlock_extent(io_tree, hole_start, block_end - 1, GFP_NOFS);
        return err;
 }
 
+static int btrfs_setattr_size(struct inode *inode, struct iattr *attr)
+{
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       struct btrfs_trans_handle *trans;
+       unsigned long nr;
+       int ret;
+
+       if (attr->ia_size == inode->i_size)
+               return 0;
+
+       if (attr->ia_size > inode->i_size) {
+               unsigned long limit;
+               limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
+               if (attr->ia_size > inode->i_sb->s_maxbytes)
+                       return -EFBIG;
+               if (limit != RLIM_INFINITY && attr->ia_size > limit) {
+                       send_sig(SIGXFSZ, current, 0);
+                       return -EFBIG;
+               }
+       }
+
+       ret = btrfs_reserve_metadata_space(root, 1);
+       if (ret)
+               return ret;
+
+       trans = btrfs_start_transaction(root, 1);
+       btrfs_set_trans_block_group(trans, inode);
+
+       ret = btrfs_orphan_add(trans, inode);
+       BUG_ON(ret);
+
+       nr = trans->blocks_used;
+       btrfs_end_transaction(trans, root);
+       btrfs_unreserve_metadata_space(root, 1);
+       btrfs_btree_balance_dirty(root, nr);
+
+       if (attr->ia_size > inode->i_size) {
+               ret = btrfs_cont_expand(inode, attr->ia_size);
+               if (ret) {
+                       btrfs_truncate(inode);
+                       return ret;
+               }
+
+               i_size_write(inode, attr->ia_size);
+               btrfs_ordered_update_i_size(inode, inode->i_size, NULL);
+
+               trans = btrfs_start_transaction(root, 1);
+               btrfs_set_trans_block_group(trans, inode);
+
+               ret = btrfs_update_inode(trans, root, inode);
+               BUG_ON(ret);
+               if (inode->i_nlink > 0) {
+                       ret = btrfs_orphan_del(trans, inode);
+                       BUG_ON(ret);
+               }
+               nr = trans->blocks_used;
+               btrfs_end_transaction(trans, root);
+               btrfs_btree_balance_dirty(root, nr);
+               return 0;
+       }
+
+       /*
+        * We're truncating a file that used to have good data down to
+        * zero. Make sure it gets into the ordered flush list so that
+        * any new writes get down to disk quickly.
+        */
+       if (attr->ia_size == 0)
+               BTRFS_I(inode)->ordered_data_close = 1;
+
+       /* we don't support swapfiles, so vmtruncate shouldn't fail */
+       ret = vmtruncate(inode, attr->ia_size);
+       BUG_ON(ret);
+
+       return 0;
+}
+
 static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
 {
        struct inode *inode = dentry->d_inode;
@@ -3250,23 +3372,14 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
                return err;
 
        if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE)) {
-               if (attr->ia_size > inode->i_size) {
-                       err = btrfs_cont_expand(inode, attr->ia_size);
-                       if (err)
-                               return err;
-               } else if (inode->i_size > 0 &&
-                          attr->ia_size == 0) {
-
-                       /* we're truncating a file that used to have good
-                        * data down to zero.  Make sure it gets into
-                        * the ordered flush list so that any new writes
-                        * get down to disk quickly.
-                        */
-                       BTRFS_I(inode)->ordered_data_close = 1;
-               }
+               err = btrfs_setattr_size(inode, attr);
+               if (err)
+                       return err;
        }
+       attr->ia_valid &= ~ATTR_SIZE;
 
-       err = inode_setattr(inode, attr);
+       if (attr->ia_valid)
+               err = inode_setattr(inode, attr);
 
        if (!err && ((attr->ia_valid & ATTR_MODE)))
                err = btrfs_acl_chmod(inode);
@@ -3287,36 +3400,43 @@ void btrfs_delete_inode(struct inode *inode)
        }
        btrfs_wait_ordered_range(inode, 0, (u64)-1);
 
+       if (root->fs_info->log_root_recovering) {
+               BUG_ON(!list_empty(&BTRFS_I(inode)->i_orphan));
+               goto no_delete;
+       }
+
        if (inode->i_nlink > 0) {
                BUG_ON(btrfs_root_refs(&root->root_item) != 0);
                goto no_delete;
        }
 
        btrfs_i_size_write(inode, 0);
-       trans = btrfs_join_transaction(root, 1);
 
-       btrfs_set_trans_block_group(trans, inode);
-       ret = btrfs_truncate_inode_items(trans, root, inode, inode->i_size, 0);
-       if (ret) {
-               btrfs_orphan_del(NULL, inode);
-               goto no_delete_lock;
-       }
+       while (1) {
+               trans = btrfs_start_transaction(root, 1);
+               btrfs_set_trans_block_group(trans, inode);
+               ret = btrfs_truncate_inode_items(trans, root, inode, 0, 0);
 
-       btrfs_orphan_del(trans, inode);
+               if (ret != -EAGAIN)
+                       break;
 
-       nr = trans->blocks_used;
-       clear_inode(inode);
+               nr = trans->blocks_used;
+               btrfs_end_transaction(trans, root);
+               trans = NULL;
+               btrfs_btree_balance_dirty(root, nr);
+       }
 
-       btrfs_end_transaction(trans, root);
-       btrfs_btree_balance_dirty(root, nr);
-       return;
+       if (ret == 0) {
+               ret = btrfs_orphan_del(trans, inode);
+               BUG_ON(ret);
+       }
 
-no_delete_lock:
        nr = trans->blocks_used;
        btrfs_end_transaction(trans, root);
        btrfs_btree_balance_dirty(root, nr);
 no_delete:
        clear_inode(inode);
+       return;
 }
 
 /*
@@ -3569,7 +3689,6 @@ static noinline void init_btrfs_i(struct inode *inode)
        INIT_LIST_HEAD(&BTRFS_I(inode)->ordered_operations);
        RB_CLEAR_NODE(&BTRFS_I(inode)->rb_node);
        btrfs_ordered_inode_tree_init(&BTRFS_I(inode)->ordered_tree);
-       mutex_init(&BTRFS_I(inode)->extent_mutex);
        mutex_init(&BTRFS_I(inode)->log_mutex);
 }
 
@@ -3695,6 +3814,13 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
        }
        srcu_read_unlock(&root->fs_info->subvol_srcu, index);
 
+       if (root != sub_root) {
+               down_read(&root->fs_info->cleanup_work_sem);
+               if (!(inode->i_sb->s_flags & MS_RDONLY))
+                       btrfs_orphan_cleanup(sub_root);
+               up_read(&root->fs_info->cleanup_work_sem);
+       }
+
        return inode;
 }
 
@@ -4219,7 +4345,7 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry,
        if (IS_ERR(inode))
                goto out_unlock;
 
-       err = btrfs_init_inode_security(inode, dir);
+       err = btrfs_init_inode_security(trans, inode, dir);
        if (err) {
                drop_inode = 1;
                goto out_unlock;
@@ -4290,7 +4416,7 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
        if (IS_ERR(inode))
                goto out_unlock;
 
-       err = btrfs_init_inode_security(inode, dir);
+       err = btrfs_init_inode_security(trans, inode, dir);
        if (err) {
                drop_inode = 1;
                goto out_unlock;
@@ -4336,6 +4462,10 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
        if (inode->i_nlink == 0)
                return -ENOENT;
 
+       /* do not allow sys_link's with other subvols of the same device */
+       if (root->objectid != BTRFS_I(inode)->root->objectid)
+               return -EPERM;
+
        /*
         * 1 item for inode ref
         * 2 items for dir items
@@ -4423,7 +4553,7 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 
        drop_on_err = 1;
 
-       err = btrfs_init_inode_security(inode, dir);
+       err = btrfs_init_inode_security(trans, inode, dir);
        if (err)
                goto out_fail;
 
@@ -5074,17 +5204,20 @@ static void btrfs_truncate(struct inode *inode)
        unsigned long nr;
        u64 mask = root->sectorsize - 1;
 
-       if (!S_ISREG(inode->i_mode))
-               return;
-       if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+       if (!S_ISREG(inode->i_mode)) {
+               WARN_ON(1);
                return;
+       }
 
        ret = btrfs_truncate_page(inode->i_mapping, inode->i_size);
        if (ret)
                return;
+
        btrfs_wait_ordered_range(inode, inode->i_size & (~mask), (u64)-1);
+       btrfs_ordered_update_i_size(inode, inode->i_size, NULL);
 
        trans = btrfs_start_transaction(root, 1);
+       btrfs_set_trans_block_group(trans, inode);
 
        /*
         * setattr is responsible for setting the ordered_data_close flag,
@@ -5106,21 +5239,32 @@ static void btrfs_truncate(struct inode *inode)
        if (inode->i_size == 0 && BTRFS_I(inode)->ordered_data_close)
                btrfs_add_ordered_operation(trans, root, inode);
 
-       btrfs_set_trans_block_group(trans, inode);
-       btrfs_i_size_write(inode, inode->i_size);
+       while (1) {
+               ret = btrfs_truncate_inode_items(trans, root, inode,
+                                                inode->i_size,
+                                                BTRFS_EXTENT_DATA_KEY);
+               if (ret != -EAGAIN)
+                       break;
 
-       ret = btrfs_orphan_add(trans, inode);
-       if (ret)
-               goto out;
-       /* FIXME, add redo link to tree so we don't leak on crash */
-       ret = btrfs_truncate_inode_items(trans, root, inode, inode->i_size,
-                                     BTRFS_EXTENT_DATA_KEY);
-       btrfs_update_inode(trans, root, inode);
+               ret = btrfs_update_inode(trans, root, inode);
+               BUG_ON(ret);
+
+               nr = trans->blocks_used;
+               btrfs_end_transaction(trans, root);
+               btrfs_btree_balance_dirty(root, nr);
+
+               trans = btrfs_start_transaction(root, 1);
+               btrfs_set_trans_block_group(trans, inode);
+       }
 
-       ret = btrfs_orphan_del(trans, inode);
+       if (ret == 0 && inode->i_nlink > 0) {
+               ret = btrfs_orphan_del(trans, inode);
+               BUG_ON(ret);
+       }
+
+       ret = btrfs_update_inode(trans, root, inode);
        BUG_ON(ret);
 
-out:
        nr = trans->blocks_used;
        ret = btrfs_end_transaction_throttle(trans, root);
        BUG_ON(ret);
@@ -5217,9 +5361,9 @@ void btrfs_destroy_inode(struct inode *inode)
 
        spin_lock(&root->list_lock);
        if (!list_empty(&BTRFS_I(inode)->i_orphan)) {
-               printk(KERN_ERR "BTRFS: inode %lu: inode still on the orphan"
-                      " list\n", inode->i_ino);
-               dump_stack();
+               printk(KERN_INFO "BTRFS: inode %lu still on the orphan list\n",
+                      inode->i_ino);
+               list_del_init(&BTRFS_I(inode)->i_orphan);
        }
        spin_unlock(&root->list_lock);
 
@@ -5476,7 +5620,7 @@ out_fail:
  * some fairly slow code that needs optimization. This walks the list
  * of all the inodes with pending delalloc and forces them to disk.
  */
-int btrfs_start_delalloc_inodes(struct btrfs_root *root)
+int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput)
 {
        struct list_head *head = &root->fs_info->delalloc_inodes;
        struct btrfs_inode *binode;
@@ -5495,7 +5639,10 @@ int btrfs_start_delalloc_inodes(struct btrfs_root *root)
                spin_unlock(&root->fs_info->delalloc_lock);
                if (inode) {
                        filemap_flush(inode->i_mapping);
-                       iput(inode);
+                       if (delay_iput)
+                               btrfs_add_delayed_iput(inode);
+                       else
+                               iput(inode);
                }
                cond_resched();
                spin_lock(&root->fs_info->delalloc_lock);
@@ -5569,7 +5716,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
        if (IS_ERR(inode))
                goto out_unlock;
 
-       err = btrfs_init_inode_security(inode, dir);
+       err = btrfs_init_inode_security(trans, inode, dir);
        if (err) {
                drop_inode = 1;
                goto out_unlock;
@@ -5641,10 +5788,10 @@ out_fail:
        return err;
 }
 
-static int prealloc_file_range(struct btrfs_trans_handle *trans,
-                              struct inode *inode, u64 start, u64 end,
-                              u64 locked_end, u64 alloc_hint, int mode)
+static int prealloc_file_range(struct inode *inode, u64 start, u64 end,
+                              u64 alloc_hint, int mode)
 {
+       struct btrfs_trans_handle *trans;
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct btrfs_key ins;
        u64 alloc_size;
@@ -5655,43 +5802,56 @@ static int prealloc_file_range(struct btrfs_trans_handle *trans,
        while (num_bytes > 0) {
                alloc_size = min(num_bytes, root->fs_info->max_extent);
 
-               ret = btrfs_reserve_metadata_space(root, 1);
-               if (ret)
-                       goto out;
+               trans = btrfs_start_transaction(root, 1);
 
                ret = btrfs_reserve_extent(trans, root, alloc_size,
                                           root->sectorsize, 0, alloc_hint,
                                           (u64)-1, &ins, 1);
                if (ret) {
                        WARN_ON(1);
-                       goto out;
+                       goto stop_trans;
+               }
+
+               ret = btrfs_reserve_metadata_space(root, 3);
+               if (ret) {
+                       btrfs_free_reserved_extent(root, ins.objectid,
+                                                  ins.offset);
+                       goto stop_trans;
                }
+
                ret = insert_reserved_file_extent(trans, inode,
                                                  cur_offset, ins.objectid,
                                                  ins.offset, ins.offset,
-                                                 ins.offset, locked_end,
-                                                 0, 0, 0,
+                                                 ins.offset, 0, 0, 0,
                                                  BTRFS_FILE_EXTENT_PREALLOC);
                BUG_ON(ret);
                btrfs_drop_extent_cache(inode, cur_offset,
                                        cur_offset + ins.offset -1, 0);
+
                num_bytes -= ins.offset;
                cur_offset += ins.offset;
                alloc_hint = ins.objectid + ins.offset;
-               btrfs_unreserve_metadata_space(root, 1);
-       }
-out:
-       if (cur_offset > start) {
+
                inode->i_ctime = CURRENT_TIME;
                BTRFS_I(inode)->flags |= BTRFS_INODE_PREALLOC;
                if (!(mode & FALLOC_FL_KEEP_SIZE) &&
-                   cur_offset > i_size_read(inode))
-                       btrfs_i_size_write(inode, cur_offset);
+                   cur_offset > inode->i_size) {
+                       i_size_write(inode, cur_offset);
+                       btrfs_ordered_update_i_size(inode, cur_offset, NULL);
+               }
+
                ret = btrfs_update_inode(trans, root, inode);
                BUG_ON(ret);
+
+               btrfs_end_transaction(trans, root);
+               btrfs_unreserve_metadata_space(root, 3);
        }
+       return ret;
 
+stop_trans:
+       btrfs_end_transaction(trans, root);
        return ret;
+
 }
 
 static long btrfs_fallocate(struct inode *inode, int mode,
@@ -5705,8 +5865,6 @@ static long btrfs_fallocate(struct inode *inode, int mode,
        u64 locked_end;
        u64 mask = BTRFS_I(inode)->root->sectorsize - 1;
        struct extent_map *em;
-       struct btrfs_trans_handle *trans;
-       struct btrfs_root *root;
        int ret;
 
        alloc_start = offset & ~mask;
@@ -5725,9 +5883,7 @@ static long btrfs_fallocate(struct inode *inode, int mode,
                        goto out;
        }
 
-       root = BTRFS_I(inode)->root;
-
-       ret = btrfs_check_data_free_space(root, inode,
+       ret = btrfs_check_data_free_space(BTRFS_I(inode)->root, inode,
                                          alloc_end - alloc_start);
        if (ret)
                goto out;
@@ -5736,12 +5892,6 @@ static long btrfs_fallocate(struct inode *inode, int mode,
        while (1) {
                struct btrfs_ordered_extent *ordered;
 
-               trans = btrfs_start_transaction(BTRFS_I(inode)->root, 1);
-               if (!trans) {
-                       ret = -EIO;
-                       goto out_free;
-               }
-
                /* the extent lock is ordered inside the running
                 * transaction
                 */
@@ -5755,8 +5905,6 @@ static long btrfs_fallocate(struct inode *inode, int mode,
                        btrfs_put_ordered_extent(ordered);
                        unlock_extent(&BTRFS_I(inode)->io_tree,
                                      alloc_start, locked_end, GFP_NOFS);
-                       btrfs_end_transaction(trans, BTRFS_I(inode)->root);
-
                        /*
                         * we can't wait on the range with the transaction
                         * running or with the extent lock held
@@ -5777,10 +5925,12 @@ static long btrfs_fallocate(struct inode *inode, int mode,
                BUG_ON(IS_ERR(em) || !em);
                last_byte = min(extent_map_end(em), alloc_end);
                last_byte = (last_byte + mask) & ~mask;
-               if (em->block_start == EXTENT_MAP_HOLE) {
-                       ret = prealloc_file_range(trans, inode, cur_offset,
-                                       last_byte, locked_end + 1,
-                                       alloc_hint, mode);
+               if (em->block_start == EXTENT_MAP_HOLE ||
+                   (cur_offset >= inode->i_size &&
+                    !test_bit(EXTENT_FLAG_PREALLOC, &em->flags))) {
+                       ret = prealloc_file_range(inode,
+                                                 cur_offset, last_byte,
+                                                 alloc_hint, mode);
                        if (ret < 0) {
                                free_extent_map(em);
                                break;
@@ -5799,9 +5949,8 @@ static long btrfs_fallocate(struct inode *inode, int mode,
        unlock_extent(&BTRFS_I(inode)->io_tree, alloc_start, locked_end,
                      GFP_NOFS);
 
-       btrfs_end_transaction(trans, BTRFS_I(inode)->root);
-out_free:
-       btrfs_free_reserved_data_space(root, inode, alloc_end - alloc_start);
+       btrfs_free_reserved_data_space(BTRFS_I(inode)->root, inode,
+                                      alloc_end - alloc_start);
 out:
        mutex_unlock(&inode->i_mutex);
        return ret;
index cdbb054102b9f860ee4d119dfff39e891ac29438..645a17927a8f7c8edf9b9b1866695f3ab6982b23 100644 (file)
@@ -237,7 +237,6 @@ static noinline int create_subvol(struct btrfs_root *root,
        u64 objectid;
        u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID;
        u64 index = 0;
-       unsigned long nr = 1;
 
        /*
         * 1 - inode item
@@ -290,7 +289,7 @@ static noinline int create_subvol(struct btrfs_root *root,
        btrfs_set_root_generation(&root_item, trans->transid);
        btrfs_set_root_level(&root_item, 0);
        btrfs_set_root_refs(&root_item, 1);
-       btrfs_set_root_used(&root_item, 0);
+       btrfs_set_root_used(&root_item, leaf->len);
        btrfs_set_root_last_snapshot(&root_item, 0);
 
        memset(&root_item.drop_progress, 0, sizeof(root_item.drop_progress));
@@ -342,24 +341,21 @@ static noinline int create_subvol(struct btrfs_root *root,
 
        d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry));
 fail:
-       nr = trans->blocks_used;
        err = btrfs_commit_transaction(trans, root);
        if (err && !ret)
                ret = err;
 
        btrfs_unreserve_metadata_space(root, 6);
-       btrfs_btree_balance_dirty(root, nr);
        return ret;
 }
 
 static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
                           char *name, int namelen)
 {
+       struct inode *inode;
        struct btrfs_pending_snapshot *pending_snapshot;
        struct btrfs_trans_handle *trans;
-       int ret = 0;
-       int err;
-       unsigned long nr = 0;
+       int ret;
 
        if (!root->ref_cows)
                return -EINVAL;
@@ -372,20 +368,20 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
         */
        ret = btrfs_reserve_metadata_space(root, 6);
        if (ret)
-               goto fail_unlock;
+               goto fail;
 
        pending_snapshot = kzalloc(sizeof(*pending_snapshot), GFP_NOFS);
        if (!pending_snapshot) {
                ret = -ENOMEM;
                btrfs_unreserve_metadata_space(root, 6);
-               goto fail_unlock;
+               goto fail;
        }
        pending_snapshot->name = kmalloc(namelen + 1, GFP_NOFS);
        if (!pending_snapshot->name) {
                ret = -ENOMEM;
                kfree(pending_snapshot);
                btrfs_unreserve_metadata_space(root, 6);
-               goto fail_unlock;
+               goto fail;
        }
        memcpy(pending_snapshot->name, name, namelen);
        pending_snapshot->name[namelen] = '\0';
@@ -395,10 +391,19 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
        pending_snapshot->root = root;
        list_add(&pending_snapshot->list,
                 &trans->transaction->pending_snapshots);
-       err = btrfs_commit_transaction(trans, root);
+       ret = btrfs_commit_transaction(trans, root);
+       BUG_ON(ret);
+       btrfs_unreserve_metadata_space(root, 6);
 
-fail_unlock:
-       btrfs_btree_balance_dirty(root, nr);
+       inode = btrfs_lookup_dentry(dentry->d_parent->d_inode, dentry);
+       if (IS_ERR(inode)) {
+               ret = PTR_ERR(inode);
+               goto fail;
+       }
+       BUG_ON(!inode);
+       d_instantiate(dentry, inode);
+       ret = 0;
+fail:
        return ret;
 }
 
@@ -1027,8 +1032,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
        BUG_ON(!trans);
 
        /* punch hole in destination first */
-       btrfs_drop_extents(trans, root, inode, off, off + len,
-                          off + len, 0, &hint_byte, 1);
+       btrfs_drop_extents(trans, inode, off, off + len, &hint_byte, 1);
 
        /* clone data */
        key.objectid = src->i_ino;
index 5799bc46a30993a1cb477fb3a4dd9db23dcad6da..b10a49d4bc6a258d1439825388e4685fbb7abb8a 100644 (file)
@@ -291,16 +291,16 @@ int btrfs_put_ordered_extent(struct btrfs_ordered_extent *entry)
 
 /*
  * remove an ordered extent from the tree.  No references are dropped
- * but, anyone waiting on this extent is woken up.
+ * and you must wake_up entry->wait.  You must hold the tree mutex
+ * while you call this function.
  */
-int btrfs_remove_ordered_extent(struct inode *inode,
+static int __btrfs_remove_ordered_extent(struct inode *inode,
                                struct btrfs_ordered_extent *entry)
 {
        struct btrfs_ordered_inode_tree *tree;
        struct rb_node *node;
 
        tree = &BTRFS_I(inode)->ordered_tree;
-       mutex_lock(&tree->mutex);
        node = &entry->rb_node;
        rb_erase(node, &tree->tree);
        tree->last = NULL;
@@ -326,16 +326,34 @@ int btrfs_remove_ordered_extent(struct inode *inode,
        }
        spin_unlock(&BTRFS_I(inode)->root->fs_info->ordered_extent_lock);
 
+       return 0;
+}
+
+/*
+ * remove an ordered extent from the tree.  No references are dropped
+ * but any waiters are woken.
+ */
+int btrfs_remove_ordered_extent(struct inode *inode,
+                               struct btrfs_ordered_extent *entry)
+{
+       struct btrfs_ordered_inode_tree *tree;
+       int ret;
+
+       tree = &BTRFS_I(inode)->ordered_tree;
+       mutex_lock(&tree->mutex);
+       ret = __btrfs_remove_ordered_extent(inode, entry);
        mutex_unlock(&tree->mutex);
        wake_up(&entry->wait);
-       return 0;
+
+       return ret;
 }
 
 /*
  * wait for all the ordered extents in a root.  This is done when balancing
  * space between drives.
  */
-int btrfs_wait_ordered_extents(struct btrfs_root *root, int nocow_only)
+int btrfs_wait_ordered_extents(struct btrfs_root *root,
+                              int nocow_only, int delay_iput)
 {
        struct list_head splice;
        struct list_head *cur;
@@ -372,7 +390,10 @@ int btrfs_wait_ordered_extents(struct btrfs_root *root, int nocow_only)
                if (inode) {
                        btrfs_start_ordered_extent(inode, ordered, 1);
                        btrfs_put_ordered_extent(ordered);
-                       iput(inode);
+                       if (delay_iput)
+                               btrfs_add_delayed_iput(inode);
+                       else
+                               iput(inode);
                } else {
                        btrfs_put_ordered_extent(ordered);
                }
@@ -430,7 +451,7 @@ again:
                                btrfs_wait_ordered_range(inode, 0, (u64)-1);
                        else
                                filemap_flush(inode->i_mapping);
-                       iput(inode);
+                       btrfs_add_delayed_iput(inode);
                }
 
                cond_resched();
@@ -589,7 +610,7 @@ out:
  * After an extent is done, call this to conditionally update the on disk
  * i_size.  i_size is updated to cover any fully written part of the file.
  */
-int btrfs_ordered_update_i_size(struct inode *inode,
+int btrfs_ordered_update_i_size(struct inode *inode, u64 offset,
                                struct btrfs_ordered_extent *ordered)
 {
        struct btrfs_ordered_inode_tree *tree = &BTRFS_I(inode)->ordered_tree;
@@ -597,18 +618,30 @@ int btrfs_ordered_update_i_size(struct inode *inode,
        u64 disk_i_size;
        u64 new_i_size;
        u64 i_size_test;
+       u64 i_size = i_size_read(inode);
        struct rb_node *node;
+       struct rb_node *prev = NULL;
        struct btrfs_ordered_extent *test;
+       int ret = 1;
+
+       if (ordered)
+               offset = entry_end(ordered);
 
        mutex_lock(&tree->mutex);
        disk_i_size = BTRFS_I(inode)->disk_i_size;
 
+       /* truncate file */
+       if (disk_i_size > i_size) {
+               BTRFS_I(inode)->disk_i_size = i_size;
+               ret = 0;
+               goto out;
+       }
+
        /*
         * if the disk i_size is already at the inode->i_size, or
         * this ordered extent is inside the disk i_size, we're done
         */
-       if (disk_i_size >= inode->i_size ||
-           ordered->file_offset + ordered->len <= disk_i_size) {
+       if (disk_i_size == i_size || offset <= disk_i_size) {
                goto out;
        }
 
@@ -616,8 +649,7 @@ int btrfs_ordered_update_i_size(struct inode *inode,
         * we can't update the disk_isize if there are delalloc bytes
         * between disk_i_size and  this ordered extent
         */
-       if (test_range_bit(io_tree, disk_i_size,
-                          ordered->file_offset + ordered->len - 1,
+       if (test_range_bit(io_tree, disk_i_size, offset - 1,
                           EXTENT_DELALLOC, 0, NULL)) {
                goto out;
        }
@@ -626,20 +658,32 @@ int btrfs_ordered_update_i_size(struct inode *inode,
         * if we find an ordered extent then we can't update disk i_size
         * yet
         */
-       node = &ordered->rb_node;
-       while (1) {
-               node = rb_prev(node);
-               if (!node)
-                       break;
+       if (ordered) {
+               node = rb_prev(&ordered->rb_node);
+       } else {
+               prev = tree_search(tree, offset);
+               /*
+                * we insert file extents without involving ordered struct,
+                * so there should be no ordered struct cover this offset
+                */
+               if (prev) {
+                       test = rb_entry(prev, struct btrfs_ordered_extent,
+                                       rb_node);
+                       BUG_ON(offset_in_entry(test, offset));
+               }
+               node = prev;
+       }
+       while (node) {
                test = rb_entry(node, struct btrfs_ordered_extent, rb_node);
                if (test->file_offset + test->len <= disk_i_size)
                        break;
-               if (test->file_offset >= inode->i_size)
+               if (test->file_offset >= i_size)
                        break;
                if (test->file_offset >= disk_i_size)
                        goto out;
+               node = rb_prev(node);
        }
-       new_i_size = min_t(u64, entry_end(ordered), i_size_read(inode));
+       new_i_size = min_t(u64, offset, i_size);
 
        /*
         * at this point, we know we can safely update i_size to at least
@@ -647,7 +691,14 @@ int btrfs_ordered_update_i_size(struct inode *inode,
         * walk forward and see if ios from higher up in the file have
         * finished.
         */
-       node = rb_next(&ordered->rb_node);
+       if (ordered) {
+               node = rb_next(&ordered->rb_node);
+       } else {
+               if (prev)
+                       node = rb_next(prev);
+               else
+                       node = rb_first(&tree->tree);
+       }
        i_size_test = 0;
        if (node) {
                /*
@@ -655,10 +706,10 @@ int btrfs_ordered_update_i_size(struct inode *inode,
                 * between our ordered extent and the next one.
                 */
                test = rb_entry(node, struct btrfs_ordered_extent, rb_node);
-               if (test->file_offset > entry_end(ordered))
+               if (test->file_offset > offset)
                        i_size_test = test->file_offset;
        } else {
-               i_size_test = i_size_read(inode);
+               i_size_test = i_size;
        }
 
        /*
@@ -667,15 +718,25 @@ int btrfs_ordered_update_i_size(struct inode *inode,
         * are no delalloc bytes in this area, it is safe to update
         * disk_i_size to the end of the region.
         */
-       if (i_size_test > entry_end(ordered) &&
-           !test_range_bit(io_tree, entry_end(ordered), i_size_test - 1,
-                          EXTENT_DELALLOC, 0, NULL)) {
-               new_i_size = min_t(u64, i_size_test, i_size_read(inode));
+       if (i_size_test > offset &&
+           !test_range_bit(io_tree, offset, i_size_test - 1,
+                           EXTENT_DELALLOC, 0, NULL)) {
+               new_i_size = min_t(u64, i_size_test, i_size);
        }
        BTRFS_I(inode)->disk_i_size = new_i_size;
+       ret = 0;
 out:
+       /*
+        * we need to remove the ordered extent with the tree lock held
+        * so that other people calling this function don't find our fully
+        * processed ordered entry and skip updating the i_size
+        */
+       if (ordered)
+               __btrfs_remove_ordered_extent(inode, ordered);
        mutex_unlock(&tree->mutex);
-       return 0;
+       if (ordered)
+               wake_up(&ordered->wait);
+       return ret;
 }
 
 /*
index f82e87488ca8f47d158c37281a3aafa746d5031d..1fe1282ef47c998aa9cde1c0c43e4f088e7e767c 100644 (file)
@@ -150,12 +150,13 @@ void btrfs_start_ordered_extent(struct inode *inode,
 int btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len);
 struct btrfs_ordered_extent *
 btrfs_lookup_first_ordered_extent(struct inode * inode, u64 file_offset);
-int btrfs_ordered_update_i_size(struct inode *inode,
+int btrfs_ordered_update_i_size(struct inode *inode, u64 offset,
                                struct btrfs_ordered_extent *ordered);
 int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr, u32 *sum);
-int btrfs_wait_ordered_extents(struct btrfs_root *root, int nocow_only);
 int btrfs_run_ordered_operations(struct btrfs_root *root, int wait);
 int btrfs_add_ordered_operation(struct btrfs_trans_handle *trans,
                                struct btrfs_root *root,
                                struct inode *inode);
+int btrfs_wait_ordered_extents(struct btrfs_root *root,
+                              int nocow_only, int delay_iput);
 #endif
index cfcc93c93a7b4db99b87ef3b91b30cc8d2f7e36b..a9728680eca8ed299deb7fc322be97deeeb6f51b 100644 (file)
@@ -1561,6 +1561,20 @@ static int invalidate_extent_cache(struct btrfs_root *root,
        return 0;
 }
 
+static void put_inodes(struct list_head *list)
+{
+       struct inodevec *ivec;
+       while (!list_empty(list)) {
+               ivec = list_entry(list->next, struct inodevec, list);
+               list_del(&ivec->list);
+               while (ivec->nr > 0) {
+                       ivec->nr--;
+                       iput(ivec->inode[ivec->nr]);
+               }
+               kfree(ivec);
+       }
+}
+
 static int find_next_key(struct btrfs_path *path, int level,
                         struct btrfs_key *key)
 
@@ -1723,6 +1737,11 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc,
 
                btrfs_btree_balance_dirty(root, nr);
 
+               /*
+                * put inodes outside transaction, otherwise we may deadlock.
+                */
+               put_inodes(&inode_list);
+
                if (replaced && rc->stage == UPDATE_DATA_PTRS)
                        invalidate_extent_cache(root, &key, &next_key);
        }
@@ -1752,19 +1771,7 @@ out:
 
        btrfs_btree_balance_dirty(root, nr);
 
-       /*
-        * put inodes while we aren't holding the tree locks
-        */
-       while (!list_empty(&inode_list)) {
-               struct inodevec *ivec;
-               ivec = list_entry(inode_list.next, struct inodevec, list);
-               list_del(&ivec->list);
-               while (ivec->nr > 0) {
-                       ivec->nr--;
-                       iput(ivec->inode[ivec->nr]);
-               }
-               kfree(ivec);
-       }
+       put_inodes(&inode_list);
 
        if (replaced && rc->stage == UPDATE_DATA_PTRS)
                invalidate_extent_cache(root, &key, &next_key);
@@ -3534,8 +3541,8 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start)
               (unsigned long long)rc->block_group->key.objectid,
               (unsigned long long)rc->block_group->flags);
 
-       btrfs_start_delalloc_inodes(fs_info->tree_root);
-       btrfs_wait_ordered_extents(fs_info->tree_root, 0);
+       btrfs_start_delalloc_inodes(fs_info->tree_root, 0);
+       btrfs_wait_ordered_extents(fs_info->tree_root, 0, 0);
 
        while (1) {
                rc->extents_found = 0;
@@ -3755,6 +3762,7 @@ out:
                                       BTRFS_DATA_RELOC_TREE_OBJECTID);
                if (IS_ERR(fs_root))
                        err = PTR_ERR(fs_root);
+               btrfs_orphan_cleanup(fs_root);
        }
        return err;
 }
index 752a5463bf53aee147068c2a0a9f678e12250f38..3f9b45704fcdfb83eeda6a55740c56de7a048ce5 100644 (file)
@@ -128,6 +128,7 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
        substring_t args[MAX_OPT_ARGS];
        char *p, *num;
        int intarg;
+       int ret = 0;
 
        if (!options)
                return 0;
@@ -262,12 +263,18 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                case Opt_discard:
                        btrfs_set_opt(info->mount_opt, DISCARD);
                        break;
+               case Opt_err:
+                       printk(KERN_INFO "btrfs: unrecognized mount option "
+                              "'%s'\n", p);
+                       ret = -EINVAL;
+                       goto out;
                default:
                        break;
                }
        }
+out:
        kfree(options);
-       return 0;
+       return ret;
 }
 
 /*
@@ -405,8 +412,8 @@ int btrfs_sync_fs(struct super_block *sb, int wait)
                return 0;
        }
 
-       btrfs_start_delalloc_inodes(root);
-       btrfs_wait_ordered_extents(root, 0);
+       btrfs_start_delalloc_inodes(root, 0);
+       btrfs_wait_ordered_extents(root, 0, 0);
 
        trans = btrfs_start_transaction(root, 1);
        ret = btrfs_commit_transaction(trans, root);
@@ -450,6 +457,8 @@ static int btrfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
                seq_puts(seq, ",notreelog");
        if (btrfs_test_opt(root, FLUSHONCOMMIT))
                seq_puts(seq, ",flushoncommit");
+       if (btrfs_test_opt(root, DISCARD))
+               seq_puts(seq, ",discard");
        if (!(root->fs_info->sb->s_flags & MS_POSIXACL))
                seq_puts(seq, ",noacl");
        return 0;
index c207e8c32c9bfc5212e111edb440adf4b59f2059..b2acc79f1b342e651a4c31da168c2952efa57ff2 100644 (file)
@@ -333,6 +333,9 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
        memset(trans, 0, sizeof(*trans));
        kmem_cache_free(btrfs_trans_handle_cachep, trans);
 
+       if (throttle)
+               btrfs_run_delayed_iputs(root);
+
        return 0;
 }
 
@@ -354,7 +357,7 @@ int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans,
  * those extents are sent to disk but does not wait on them
  */
 int btrfs_write_marked_extents(struct btrfs_root *root,
-                              struct extent_io_tree *dirty_pages)
+                              struct extent_io_tree *dirty_pages, int mark)
 {
        int ret;
        int err = 0;
@@ -367,7 +370,7 @@ int btrfs_write_marked_extents(struct btrfs_root *root,
 
        while (1) {
                ret = find_first_extent_bit(dirty_pages, start, &start, &end,
-                                           EXTENT_DIRTY);
+                                           mark);
                if (ret)
                        break;
                while (start <= end) {
@@ -413,7 +416,7 @@ int btrfs_write_marked_extents(struct btrfs_root *root,
  * on all the pages and clear them from the dirty pages state tree
  */
 int btrfs_wait_marked_extents(struct btrfs_root *root,
-                             struct extent_io_tree *dirty_pages)
+                             struct extent_io_tree *dirty_pages, int mark)
 {
        int ret;
        int err = 0;
@@ -425,12 +428,12 @@ int btrfs_wait_marked_extents(struct btrfs_root *root,
        unsigned long index;
 
        while (1) {
-               ret = find_first_extent_bit(dirty_pages, 0, &start, &end,
-                                           EXTENT_DIRTY);
+               ret = find_first_extent_bit(dirty_pages, start, &start, &end,
+                                           mark);
                if (ret)
                        break;
 
-               clear_extent_dirty(dirty_pages, start, end, GFP_NOFS);
+               clear_extent_bits(dirty_pages, start, end, mark, GFP_NOFS);
                while (start <= end) {
                        index = start >> PAGE_CACHE_SHIFT;
                        start = (u64)(index + 1) << PAGE_CACHE_SHIFT;
@@ -460,13 +463,13 @@ int btrfs_wait_marked_extents(struct btrfs_root *root,
  * those extents are on disk for transaction or log commit
  */
 int btrfs_write_and_wait_marked_extents(struct btrfs_root *root,
-                                       struct extent_io_tree *dirty_pages)
+                               struct extent_io_tree *dirty_pages, int mark)
 {
        int ret;
        int ret2;
 
-       ret = btrfs_write_marked_extents(root, dirty_pages);
-       ret2 = btrfs_wait_marked_extents(root, dirty_pages);
+       ret = btrfs_write_marked_extents(root, dirty_pages, mark);
+       ret2 = btrfs_wait_marked_extents(root, dirty_pages, mark);
        return ret || ret2;
 }
 
@@ -479,7 +482,8 @@ int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans,
                return filemap_write_and_wait(btree_inode->i_mapping);
        }
        return btrfs_write_and_wait_marked_extents(root,
-                                          &trans->transaction->dirty_pages);
+                                          &trans->transaction->dirty_pages,
+                                          EXTENT_DIRTY);
 }
 
 /*
@@ -497,13 +501,16 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,
 {
        int ret;
        u64 old_root_bytenr;
+       u64 old_root_used;
        struct btrfs_root *tree_root = root->fs_info->tree_root;
 
+       old_root_used = btrfs_root_used(&root->root_item);
        btrfs_write_dirty_block_groups(trans, root);
 
        while (1) {
                old_root_bytenr = btrfs_root_bytenr(&root->root_item);
-               if (old_root_bytenr == root->node->start)
+               if (old_root_bytenr == root->node->start &&
+                   old_root_used == btrfs_root_used(&root->root_item))
                        break;
 
                btrfs_set_root_node(&root->root_item, root->node);
@@ -512,6 +519,7 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,
                                        &root->root_item);
                BUG_ON(ret);
 
+               old_root_used = btrfs_root_used(&root->root_item);
                ret = btrfs_write_dirty_block_groups(trans, root);
                BUG_ON(ret);
        }
@@ -795,7 +803,6 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
        memcpy(&pending->root_key, &key, sizeof(key));
 fail:
        kfree(new_root_item);
-       btrfs_unreserve_metadata_space(root, 6);
        return ret;
 }
 
@@ -807,7 +814,6 @@ static noinline int finish_pending_snapshot(struct btrfs_fs_info *fs_info,
        u64 index = 0;
        struct btrfs_trans_handle *trans;
        struct inode *parent_inode;
-       struct inode *inode;
        struct btrfs_root *parent_root;
 
        parent_inode = pending->dentry->d_parent->d_inode;
@@ -839,8 +845,6 @@ static noinline int finish_pending_snapshot(struct btrfs_fs_info *fs_info,
 
        BUG_ON(ret);
 
-       inode = btrfs_lookup_dentry(parent_inode, pending->dentry);
-       d_instantiate(pending->dentry, inode);
 fail:
        btrfs_end_transaction(trans, fs_info->fs_root);
        return ret;
@@ -994,11 +998,11 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
                mutex_unlock(&root->fs_info->trans_mutex);
 
                if (flush_on_commit) {
-                       btrfs_start_delalloc_inodes(root);
-                       ret = btrfs_wait_ordered_extents(root, 0);
+                       btrfs_start_delalloc_inodes(root, 1);
+                       ret = btrfs_wait_ordered_extents(root, 0, 1);
                        BUG_ON(ret);
                } else if (snap_pending) {
-                       ret = btrfs_wait_ordered_extents(root, 1);
+                       ret = btrfs_wait_ordered_extents(root, 0, 1);
                        BUG_ON(ret);
                }
 
@@ -1116,6 +1120,10 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
                current->journal_info = NULL;
 
        kmem_cache_free(btrfs_trans_handle_cachep, trans);
+
+       if (current != root->fs_info->transaction_kthread)
+               btrfs_run_delayed_iputs(root);
+
        return ret;
 }
 
index d4e3e7a6938cddebb56e05ae4131b7055f08be05..93c7ccb33118f38d420c00c3b790fe0040b7f0ca 100644 (file)
@@ -107,10 +107,10 @@ void btrfs_throttle(struct btrfs_root *root);
 int btrfs_record_root_in_trans(struct btrfs_trans_handle *trans,
                                struct btrfs_root *root);
 int btrfs_write_and_wait_marked_extents(struct btrfs_root *root,
-                                       struct extent_io_tree *dirty_pages);
+                               struct extent_io_tree *dirty_pages, int mark);
 int btrfs_write_marked_extents(struct btrfs_root *root,
-                                       struct extent_io_tree *dirty_pages);
+                               struct extent_io_tree *dirty_pages, int mark);
 int btrfs_wait_marked_extents(struct btrfs_root *root,
-                                       struct extent_io_tree *dirty_pages);
+                               struct extent_io_tree *dirty_pages, int mark);
 int btrfs_transaction_in_commit(struct btrfs_fs_info *info);
 #endif
index 741666a7676a80a6553f5b22a37a41dd31971d3e..4a9434b622ecfc0f571c32ea3abf54df3d878123 100644 (file)
@@ -542,8 +542,8 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
 
        saved_nbytes = inode_get_bytes(inode);
        /* drop any overlapping extents */
-       ret = btrfs_drop_extents(trans, root, inode,
-                        start, extent_end, extent_end, start, &alloc_hint, 1);
+       ret = btrfs_drop_extents(trans, inode, start, extent_end,
+                                &alloc_hint, 1);
        BUG_ON(ret);
 
        if (found_type == BTRFS_FILE_EXTENT_REG ||
@@ -930,6 +930,17 @@ out_nowrite:
        return 0;
 }
 
+static int insert_orphan_item(struct btrfs_trans_handle *trans,
+                             struct btrfs_root *root, u64 offset)
+{
+       int ret;
+       ret = btrfs_find_orphan_item(root, offset);
+       if (ret > 0)
+               ret = btrfs_insert_orphan_item(trans, root, offset);
+       return ret;
+}
+
+
 /*
  * There are a few corners where the link count of the file can't
  * be properly maintained during replay.  So, instead of adding
@@ -997,9 +1008,13 @@ static noinline int fixup_inode_link_count(struct btrfs_trans_handle *trans,
        }
        BTRFS_I(inode)->index_cnt = (u64)-1;
 
-       if (inode->i_nlink == 0 && S_ISDIR(inode->i_mode)) {
-               ret = replay_dir_deletes(trans, root, NULL, path,
-                                        inode->i_ino, 1);
+       if (inode->i_nlink == 0) {
+               if (S_ISDIR(inode->i_mode)) {
+                       ret = replay_dir_deletes(trans, root, NULL, path,
+                                                inode->i_ino, 1);
+                       BUG_ON(ret);
+               }
+               ret = insert_orphan_item(trans, root, inode->i_ino);
                BUG_ON(ret);
        }
        btrfs_free_path(path);
@@ -1587,7 +1602,6 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
                /* inode keys are done during the first stage */
                if (key.type == BTRFS_INODE_ITEM_KEY &&
                    wc->stage == LOG_WALK_REPLAY_INODES) {
-                       struct inode *inode;
                        struct btrfs_inode_item *inode_item;
                        u32 mode;
 
@@ -1603,31 +1617,16 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
                                             eb, i, &key);
                        BUG_ON(ret);
 
-                       /* for regular files, truncate away
-                        * extents past the new EOF
+                       /* for regular files, make sure corresponding
+                        * orhpan item exist. extents past the new EOF
+                        * will be truncated later by orphan cleanup.
                         */
                        if (S_ISREG(mode)) {
-                               inode = read_one_inode(root,
-                                                      key.objectid);
-                               BUG_ON(!inode);
-
-                               ret = btrfs_truncate_inode_items(wc->trans,
-                                       root, inode, inode->i_size,
-                                       BTRFS_EXTENT_DATA_KEY);
+                               ret = insert_orphan_item(wc->trans, root,
+                                                        key.objectid);
                                BUG_ON(ret);
-
-                               /* if the nlink count is zero here, the iput
-                                * will free the inode.  We bump it to make
-                                * sure it doesn't get freed until the link
-                                * count fixup is done
-                                */
-                               if (inode->i_nlink == 0) {
-                                       btrfs_inc_nlink(inode);
-                                       btrfs_update_inode(wc->trans,
-                                                          root, inode);
-                               }
-                               iput(inode);
                        }
+
                        ret = link_to_fixup_dir(wc->trans, root,
                                                path, key.objectid);
                        BUG_ON(ret);
@@ -1977,10 +1976,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
 {
        int index1;
        int index2;
+       int mark;
        int ret;
        struct btrfs_root *log = root->log_root;
        struct btrfs_root *log_root_tree = root->fs_info->log_root_tree;
-       u64 log_transid = 0;
+       unsigned long log_transid = 0;
 
        mutex_lock(&root->log_mutex);
        index1 = root->log_transid % 2;
@@ -2014,24 +2014,29 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
                goto out;
        }
 
+       log_transid = root->log_transid;
+       if (log_transid % 2 == 0)
+               mark = EXTENT_DIRTY;
+       else
+               mark = EXTENT_NEW;
+
        /* we start IO on  all the marked extents here, but we don't actually
         * wait for them until later.
         */
-       ret = btrfs_write_marked_extents(log, &log->dirty_log_pages);
+       ret = btrfs_write_marked_extents(log, &log->dirty_log_pages, mark);
        BUG_ON(ret);
 
        btrfs_set_root_node(&log->root_item, log->node);
 
        root->log_batch = 0;
-       log_transid = root->log_transid;
        root->log_transid++;
        log->log_transid = root->log_transid;
        root->log_start_pid = 0;
        smp_mb();
        /*
-        * log tree has been flushed to disk, new modifications of
-        * the log will be written to new positions. so it's safe to
-        * allow log writers to go in.
+        * IO has been started, blocks of the log tree have WRITTEN flag set
+        * in their headers. new modifications of the log will be written to
+        * new positions. so it's safe to allow log writers to go in.
         */
        mutex_unlock(&root->log_mutex);
 
@@ -2052,7 +2057,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
 
        index2 = log_root_tree->log_transid % 2;
        if (atomic_read(&log_root_tree->log_commit[index2])) {
-               btrfs_wait_marked_extents(log, &log->dirty_log_pages);
+               btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark);
                wait_log_commit(trans, log_root_tree,
                                log_root_tree->log_transid);
                mutex_unlock(&log_root_tree->log_mutex);
@@ -2072,16 +2077,17 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
         * check the full commit flag again
         */
        if (root->fs_info->last_trans_log_full_commit == trans->transid) {
-               btrfs_wait_marked_extents(log, &log->dirty_log_pages);
+               btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark);
                mutex_unlock(&log_root_tree->log_mutex);
                ret = -EAGAIN;
                goto out_wake_log_root;
        }
 
        ret = btrfs_write_and_wait_marked_extents(log_root_tree,
-                               &log_root_tree->dirty_log_pages);
+                               &log_root_tree->dirty_log_pages,
+                               EXTENT_DIRTY | EXTENT_NEW);
        BUG_ON(ret);
-       btrfs_wait_marked_extents(log, &log->dirty_log_pages);
+       btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark);
 
        btrfs_set_super_log_root(&root->fs_info->super_for_commit,
                                log_root_tree->node->start);
@@ -2147,12 +2153,12 @@ int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root)
 
        while (1) {
                ret = find_first_extent_bit(&log->dirty_log_pages,
-                                   0, &start, &end, EXTENT_DIRTY);
+                               0, &start, &end, EXTENT_DIRTY | EXTENT_NEW);
                if (ret)
                        break;
 
-               clear_extent_dirty(&log->dirty_log_pages,
-                                  start, end, GFP_NOFS);
+               clear_extent_bits(&log->dirty_log_pages, start, end,
+                                 EXTENT_DIRTY | EXTENT_NEW, GFP_NOFS);
        }
 
        if (log->log_transid > 0) {
index 7eda483d7b5aa0cd5e5bd96d149cca6fe2fc8f16..198cff28766d494f3a919673775fe679d560722f 100644 (file)
@@ -2209,7 +2209,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
                max_chunk_size = 10 * calc_size;
                min_stripe_size = 64 * 1024 * 1024;
        } else if (type & BTRFS_BLOCK_GROUP_METADATA) {
-               max_chunk_size = 4 * calc_size;
+               max_chunk_size = 256 * 1024 * 1024;
                min_stripe_size = 32 * 1024 * 1024;
        } else if (type & BTRFS_BLOCK_GROUP_SYSTEM) {
                calc_size = 8 * 1024 * 1024;
index b6dd5967c48a2785074f75db2dacd6a7370a9ec2..193b58f7d3f3b36d027a85756c917aa7191f99b2 100644 (file)
@@ -85,22 +85,23 @@ out:
        return ret;
 }
 
-int __btrfs_setxattr(struct inode *inode, const char *name,
-                           const void *value, size_t size, int flags)
+static int do_setxattr(struct btrfs_trans_handle *trans,
+                      struct inode *inode, const char *name,
+                      const void *value, size_t size, int flags)
 {
        struct btrfs_dir_item *di;
        struct btrfs_root *root = BTRFS_I(inode)->root;
-       struct btrfs_trans_handle *trans;
        struct btrfs_path *path;
-       int ret = 0, mod = 0;
+       size_t name_len = strlen(name);
+       int ret = 0;
+
+       if (name_len + size > BTRFS_MAX_XATTR_SIZE(root))
+               return -ENOSPC;
 
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
 
-       trans = btrfs_join_transaction(root, 1);
-       btrfs_set_trans_block_group(trans, inode);
-
        /* first lets see if we already have this xattr */
        di = btrfs_lookup_xattr(trans, root, path, inode->i_ino, name,
                                strlen(name), -1);
@@ -118,15 +119,12 @@ int __btrfs_setxattr(struct inode *inode, const char *name,
                }
 
                ret = btrfs_delete_one_dir_name(trans, root, path, di);
-               if (ret)
-                       goto out;
+               BUG_ON(ret);
                btrfs_release_path(root, path);
 
                /* if we don't have a value then we are removing the xattr */
-               if (!value) {
-                       mod = 1;
+               if (!value)
                        goto out;
-               }
        } else {
                btrfs_release_path(root, path);
 
@@ -138,20 +136,45 @@ int __btrfs_setxattr(struct inode *inode, const char *name,
        }
 
        /* ok we have to create a completely new xattr */
-       ret = btrfs_insert_xattr_item(trans, root, name, strlen(name),
-                                     value, size, inode->i_ino);
+       ret = btrfs_insert_xattr_item(trans, root, path, inode->i_ino,
+                                     name, name_len, value, size);
+       BUG_ON(ret);
+out:
+       btrfs_free_path(path);
+       return ret;
+}
+
+int __btrfs_setxattr(struct btrfs_trans_handle *trans,
+                    struct inode *inode, const char *name,
+                    const void *value, size_t size, int flags)
+{
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       int ret;
+
+       if (trans)
+               return do_setxattr(trans, inode, name, value, size, flags);
+
+       ret = btrfs_reserve_metadata_space(root, 2);
        if (ret)
-               goto out;
-       mod = 1;
+               return ret;
 
-out:
-       if (mod) {
-               inode->i_ctime = CURRENT_TIME;
-               ret = btrfs_update_inode(trans, root, inode);
+       trans = btrfs_start_transaction(root, 1);
+       if (!trans) {
+               ret = -ENOMEM;
+               goto out;
        }
+       btrfs_set_trans_block_group(trans, inode);
 
-       btrfs_end_transaction(trans, root);
-       btrfs_free_path(path);
+       ret = do_setxattr(trans, inode, name, value, size, flags);
+       if (ret)
+               goto out;
+
+       inode->i_ctime = CURRENT_TIME;
+       ret = btrfs_update_inode(trans, root, inode);
+       BUG_ON(ret);
+out:
+       btrfs_end_transaction_throttle(trans, root);
+       btrfs_unreserve_metadata_space(root, 2);
        return ret;
 }
 
@@ -314,7 +337,9 @@ int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value,
 
        if (size == 0)
                value = "";  /* empty EA, do not remove */
-       return __btrfs_setxattr(dentry->d_inode, name, value, size, flags);
+
+       return __btrfs_setxattr(NULL, dentry->d_inode, name, value, size,
+                               flags);
 }
 
 int btrfs_removexattr(struct dentry *dentry, const char *name)
@@ -329,10 +354,13 @@ int btrfs_removexattr(struct dentry *dentry, const char *name)
 
        if (!btrfs_is_valid_xattr(name))
                return -EOPNOTSUPP;
-       return __btrfs_setxattr(dentry->d_inode, name, NULL, 0, XATTR_REPLACE);
+
+       return __btrfs_setxattr(NULL, dentry->d_inode, name, NULL, 0,
+                               XATTR_REPLACE);
 }
 
-int btrfs_xattr_security_init(struct inode *inode, struct inode *dir)
+int btrfs_xattr_security_init(struct btrfs_trans_handle *trans,
+                             struct inode *inode, struct inode *dir)
 {
        int err;
        size_t len;
@@ -354,7 +382,7 @@ int btrfs_xattr_security_init(struct inode *inode, struct inode *dir)
        } else {
                strcpy(name, XATTR_SECURITY_PREFIX);
                strcpy(name + XATTR_SECURITY_PREFIX_LEN, suffix);
-               err = __btrfs_setxattr(inode, name, value, len, 0);
+               err = __btrfs_setxattr(trans, inode, name, value, len, 0);
                kfree(name);
        }
 
index c71e9c3cf3f749e8981d19433bef8ada685383aa..721efa0346e037c2f6f32c91d7f284fbc580c87f 100644 (file)
@@ -27,15 +27,16 @@ extern struct xattr_handler *btrfs_xattr_handlers[];
 
 extern ssize_t __btrfs_getxattr(struct inode *inode, const char *name,
                void *buffer, size_t size);
-extern int __btrfs_setxattr(struct inode *inode, const char *name,
-               const void *value, size_t size, int flags);
-
+extern int __btrfs_setxattr(struct btrfs_trans_handle *trans,
+                           struct inode *inode, const char *name,
+                           const void *value, size_t size, int flags);
 extern ssize_t btrfs_getxattr(struct dentry *dentry, const char *name,
                void *buffer, size_t size);
 extern int btrfs_setxattr(struct dentry *dentry, const char *name,
                const void *value, size_t size, int flags);
 extern int btrfs_removexattr(struct dentry *dentry, const char *name);
 
-extern int btrfs_xattr_security_init(struct inode *inode, struct inode *dir);
+extern int btrfs_xattr_security_init(struct btrfs_trans_handle *trans,
+                                    struct inode *inode, struct inode *dir);
 
 #endif /* __XATTR__ */
index 4012885d027fd7bd054acb2ee0404b2b82f8eda2..e82adc2debb73de9ae9ca916e65c6e2bed317ef2 100644 (file)
@@ -1206,7 +1206,7 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
         * NOTE: filesystems with their own locking have to handle this
         * on their own.
         */
-       if (dio->flags & DIO_LOCKING) {
+       if (flags & DIO_LOCKING) {
                if (unlikely((rw & WRITE) && retval < 0)) {
                        loff_t isize = i_size_read(inode);
                        if (end > isize)
index 2dda5ade75bc78a06461d0b62fbb9f74bde28678..8f006a0d6076f3dbe61ce9d2dd956e7b853d0132 100644 (file)
@@ -62,7 +62,7 @@ static int ecryptfs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
                struct inode *lower_inode =
                        ecryptfs_inode_to_lower(dentry->d_inode);
 
-               fsstack_copy_attr_all(dentry->d_inode, lower_inode, NULL);
+               fsstack_copy_attr_all(dentry->d_inode, lower_inode);
        }
 out:
        return rc;
index 056fed62d0de8beb39f6a0ab6f195bb2577976e1..429ca0b3ba0872f3be95bfc08417d0b8647298f5 100644 (file)
@@ -626,9 +626,9 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                        lower_new_dir_dentry->d_inode, lower_new_dentry);
        if (rc)
                goto out_lock;
-       fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode, NULL);
+       fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode);
        if (new_dir != old_dir)
-               fsstack_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode, NULL);
+               fsstack_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode);
 out_lock:
        unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
        dput(lower_new_dentry->d_parent);
@@ -967,7 +967,7 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
        rc = notify_change(lower_dentry, ia);
        mutex_unlock(&lower_dentry->d_inode->i_mutex);
 out:
-       fsstack_copy_attr_all(inode, lower_inode, NULL);
+       fsstack_copy_attr_all(inode, lower_inode);
        return rc;
 }
 
index 101fe4c7b1ee6db074eecdd56adf459736c271c3..567bc4b9f70a52029b4e6095a522a0b2f944b307 100644 (file)
@@ -189,7 +189,7 @@ int ecryptfs_interpose(struct dentry *lower_dentry, struct dentry *dentry,
                init_special_inode(inode, lower_inode->i_mode,
                                   lower_inode->i_rdev);
        dentry->d_op = &ecryptfs_dops;
-       fsstack_copy_attr_all(inode, lower_inode, NULL);
+       fsstack_copy_attr_all(inode, lower_inode);
        /* This size will be overwritten for real files w/ headers and
         * other metadata */
        fsstack_copy_inode_size(inode, lower_inode);
index 623a5cc3076a114af8808ca030f04bdd82638829..632b02e34ec72b17564602f9c944996e4889a9cf 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -826,7 +826,9 @@ static int de_thread(struct task_struct *tsk)
                attach_pid(tsk, PIDTYPE_PID,  task_pid(leader));
                transfer_pid(leader, tsk, PIDTYPE_PGID);
                transfer_pid(leader, tsk, PIDTYPE_SID);
+
                list_replace_rcu(&leader->tasks, &tsk->tasks);
+               list_replace_init(&leader->sibling, &tsk->sibling);
 
                tsk->group_leader = tsk;
                leader->group_leader = tsk;
@@ -1761,17 +1763,20 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
        struct mm_struct *mm = current->mm;
        struct linux_binfmt * binfmt;
        struct inode * inode;
-       struct file * file;
        const struct cred *old_cred;
        struct cred *cred;
        int retval = 0;
        int flag = 0;
        int ispipe = 0;
-       unsigned long core_limit = current->signal->rlim[RLIMIT_CORE].rlim_cur;
        char **helper_argv = NULL;
        int helper_argc = 0;
        int dump_count = 0;
        static atomic_t core_dump_count = ATOMIC_INIT(0);
+       struct coredump_params cprm = {
+               .signr = signr,
+               .regs = regs,
+               .limit = current->signal->rlim[RLIMIT_CORE].rlim_cur,
+       };
 
        audit_core_dumps(signr);
 
@@ -1827,15 +1832,15 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
        ispipe = format_corename(corename, signr);
        unlock_kernel();
 
-       if ((!ispipe) && (core_limit < binfmt->min_coredump))
+       if ((!ispipe) && (cprm.limit < binfmt->min_coredump))
                goto fail_unlock;
 
        if (ispipe) {
-               if (core_limit == 0) {
+               if (cprm.limit == 0) {
                        /*
                         * Normally core limits are irrelevant to pipes, since
                         * we're not writing to the file system, but we use
-                        * core_limit of 0 here as a speacial value. Any
+                        * cprm.limit of 0 here as a speacial value. Any
                         * non-zero limit gets set to RLIM_INFINITY below, but
                         * a limit of 0 skips the dump.  This is a consistent
                         * way to catch recursive crashes.  We can still crash
@@ -1868,25 +1873,25 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
                        goto fail_dropcount;
                }
 
-               core_limit = RLIM_INFINITY;
+               cprm.limit = RLIM_INFINITY;
 
                /* SIGPIPE can happen, but it's just never processed */
                if (call_usermodehelper_pipe(helper_argv[0], helper_argv, NULL,
-                               &file)) {
+                               &cprm.file)) {
                        printk(KERN_INFO "Core dump to %s pipe failed\n",
                               corename);
                        goto fail_dropcount;
                }
        } else
-               file = filp_open(corename,
+               cprm.file = filp_open(corename,
                                 O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag,
                                 0600);
-       if (IS_ERR(file))
+       if (IS_ERR(cprm.file))
                goto fail_dropcount;
-       inode = file->f_path.dentry->d_inode;
+       inode = cprm.file->f_path.dentry->d_inode;
        if (inode->i_nlink > 1)
                goto close_fail;        /* multiple links - don't dump */
-       if (!ispipe && d_unhashed(file->f_path.dentry))
+       if (!ispipe && d_unhashed(cprm.file->f_path.dentry))
                goto close_fail;
 
        /* AK: actually i see no reason to not allow this for named pipes etc.,
@@ -1899,21 +1904,22 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
         */
        if (inode->i_uid != current_fsuid())
                goto close_fail;
-       if (!file->f_op)
+       if (!cprm.file->f_op)
                goto close_fail;
-       if (!file->f_op->write)
+       if (!cprm.file->f_op->write)
                goto close_fail;
-       if (!ispipe && do_truncate(file->f_path.dentry, 0, 0, file) != 0)
+       if (!ispipe &&
+           do_truncate(cprm.file->f_path.dentry, 0, 0, cprm.file) != 0)
                goto close_fail;
 
-       retval = binfmt->core_dump(signr, regs, file, core_limit);
+       retval = binfmt->core_dump(&cprm);
 
        if (retval)
                current->signal->group_exit_code |= 0x80;
 close_fail:
        if (ispipe && core_pipe_limit)
-               wait_for_dump_helpers(file);
-       filp_close(file, NULL);
+               wait_for_dump_helpers(cprm.file);
+       filp_close(cprm.file, NULL);
 fail_dropcount:
        if (dump_count)
                atomic_dec(&core_dump_count);
index e5f6774846e46337d9e2e39790c239815f20caf3..9acf7e808139d3df688da7d66ffb33b5cf081d8e 100644 (file)
@@ -2,7 +2,6 @@ config EXT4_FS
        tristate "The Extended 4 (ext4) filesystem"
        select JBD2
        select CRC16
-       select FS_JOURNAL_INFO
        help
          This is the next generation of the ext3 filesystem.
 
index b192c661caa69a3c04b8d499c85721297a3cd9f2..4dcddf83326f45f7dd874587ef915b7844d60b0b 100644 (file)
@@ -10,7 +10,6 @@ config GFS2_FS
        select SLOW_WORK
        select QUOTA
        select QUOTACTL
-       select FS_JOURNAL_INFO
        help
          A cluster filesystem.
 
index 3ff32fa793dae4900415094fa616c8a8250c58ca..6e220f4eee7dbadc3ec5c8070533458429bec71a 100644 (file)
@@ -125,7 +125,7 @@ static struct inode *gfs2_iget_skip(struct super_block *sb,
  * directory entry when gfs2_inode_lookup() is invoked. Part of the code
  * segment inside gfs2_inode_lookup code needs to get moved around.
  *
- * Clean up I_LOCK and I_NEW as well.
+ * Clears I_NEW as well.
  **/
 
 void gfs2_set_iop(struct inode *inode)
index 06c1f02de611d51bc8d4218b29e083bc15eb9c43..03dfeb2e39287a75b2fccbe6c71d1451ebade3a0 100644 (file)
@@ -113,7 +113,7 @@ static void wake_up_inode(struct inode *inode)
         * Prevent speculative execution through spin_unlock(&inode_lock);
         */
        smp_mb();
-       wake_up_bit(&inode->i_state, __I_LOCK);
+       wake_up_bit(&inode->i_state, __I_NEW);
 }
 
 /**
@@ -690,17 +690,17 @@ void unlock_new_inode(struct inode *inode)
        }
 #endif
        /*
-        * This is special!  We do not need the spinlock when clearing I_LOCK,
+        * This is special!  We do not need the spinlock when clearing I_NEW,
         * because we're guaranteed that nobody else tries to do anything about
         * the state of the inode when it is locked, as we just created it (so
-        * there can be no old holders that haven't tested I_LOCK).
+        * there can be no old holders that haven't tested I_NEW).
         * However we must emit the memory barrier so that other CPUs reliably
-        * see the clearing of I_LOCK after the other inode initialisation has
+        * see the clearing of I_NEW after the other inode initialisation has
         * completed.
         */
        smp_mb();
-       WARN_ON((inode->i_state & (I_LOCK|I_NEW)) != (I_LOCK|I_NEW));
-       inode->i_state &= ~(I_LOCK|I_NEW);
+       WARN_ON(!(inode->i_state & I_NEW));
+       inode->i_state &= ~I_NEW;
        wake_up_inode(inode);
 }
 EXPORT_SYMBOL(unlock_new_inode);
@@ -731,7 +731,7 @@ static struct inode *get_new_inode(struct super_block *sb,
                                goto set_failed;
 
                        __inode_add_to_lists(sb, head, inode);
-                       inode->i_state = I_LOCK|I_NEW;
+                       inode->i_state = I_NEW;
                        spin_unlock(&inode_lock);
 
                        /* Return the locked inode with I_NEW set, the
@@ -778,7 +778,7 @@ static struct inode *get_new_inode_fast(struct super_block *sb,
                if (!old) {
                        inode->i_ino = ino;
                        __inode_add_to_lists(sb, head, inode);
-                       inode->i_state = I_LOCK|I_NEW;
+                       inode->i_state = I_NEW;
                        spin_unlock(&inode_lock);
 
                        /* Return the locked inode with I_NEW set, the
@@ -1083,7 +1083,7 @@ int insert_inode_locked(struct inode *inode)
        ino_t ino = inode->i_ino;
        struct hlist_head *head = inode_hashtable + hash(sb, ino);
 
-       inode->i_state |= I_LOCK|I_NEW;
+       inode->i_state |= I_NEW;
        while (1) {
                struct hlist_node *node;
                struct inode *old = NULL;
@@ -1120,7 +1120,7 @@ int insert_inode_locked4(struct inode *inode, unsigned long hashval,
        struct super_block *sb = inode->i_sb;
        struct hlist_head *head = inode_hashtable + hash(sb, hashval);
 
-       inode->i_state |= I_LOCK|I_NEW;
+       inode->i_state |= I_NEW;
 
        while (1) {
                struct hlist_node *node;
@@ -1510,7 +1510,7 @@ EXPORT_SYMBOL(inode_wait);
  * until the deletion _might_ have completed.  Callers are responsible
  * to recheck inode state.
  *
- * It doesn't matter if I_LOCK is not set initially, a call to
+ * It doesn't matter if I_NEW is not set initially, a call to
  * wake_up_inode() after removing from the hash list will DTRT.
  *
  * This is called with inode_lock held.
@@ -1518,8 +1518,8 @@ EXPORT_SYMBOL(inode_wait);
 static void __wait_on_freeing_inode(struct inode *inode)
 {
        wait_queue_head_t *wq;
-       DEFINE_WAIT_BIT(wait, &inode->i_state, __I_LOCK);
-       wq = bit_waitqueue(&inode->i_state, __I_LOCK);
+       DEFINE_WAIT_BIT(wait, &inode->i_state, __I_NEW);
+       wq = bit_waitqueue(&inode->i_state, __I_NEW);
        prepare_to_wait(wq, &wait.wait, TASK_UNINTERRUPTIBLE);
        spin_unlock(&inode_lock);
        schedule();
index a8408983abd4abbf32c356f4234aa63f63116b15..4e28beeed157236c7a73a9270972f46dddd3d69b 100644 (file)
@@ -1,6 +1,5 @@
 config JBD
        tristate
-       select FS_JOURNAL_INFO
        help
          This is a generic journalling layer for block devices.  It is
          currently used by the ext3 file system, but it could also be
index 0f7d1ceafdfd39a0a5c8a8cd7ddb0b8785cd8d4c..f32f346f4b0a521a5b6bbaedc7b0a5a7750c4b1e 100644 (file)
@@ -1,7 +1,6 @@
 config JBD2
        tristate
        select CRC32
-       select FS_JOURNAL_INFO
        help
          This is a generic journaling layer for block devices that support
          both 32-bit and 64-bit block numbers.  It is currently used by
index f26e4d03ada50aabc2e9870235cf297a838a1486..d945ea76b445249de68fece3be7dea631cf2b6b1 100644 (file)
@@ -1292,7 +1292,7 @@ int txCommit(tid_t tid,           /* transaction identifier */
                 */
                /*
                 * I believe this code is no longer needed.  Splitting I_LOCK
-                * into two bits, I_LOCK and I_SYNC should prevent this
+                * into two bits, I_NEW and I_SYNC should prevent this
                 * deadlock as well.  But since I don't have a JFS testload
                 * to verify this, only a trivial s/I_LOCK/I_SYNC/ was done.
                 * Joern
index d2783c8a770be81ea182e7b11d912ad3972b0a9a..dad4b80257db95759a615e392b3a300120fa9472 100644 (file)
@@ -1764,7 +1764,7 @@ do_last:
 
        path_to_nameidata(&path, &nd);
        error = -EISDIR;
-       if (path.dentry->d_inode && S_ISDIR(path.dentry->d_inode->i_mode))
+       if (S_ISDIR(path.dentry->d_inode->i_mode))
                goto exit;
 ok:
        /*
index faab1273281e6da035a36529a401701ffb67fc43..7d70d63ceb2948c6b8e25ef7628314a4c0eab3b8 100644 (file)
@@ -2068,7 +2068,7 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns,
  * create_mnt_ns - creates a private namespace and adds a root filesystem
  * @mnt: pointer to the new root filesystem mountpoint
  */
-static struct mnt_namespace *create_mnt_ns(struct vfsmount *mnt)
+struct mnt_namespace *create_mnt_ns(struct vfsmount *mnt)
 {
        struct mnt_namespace *new_ns;
 
@@ -2080,6 +2080,7 @@ static struct mnt_namespace *create_mnt_ns(struct vfsmount *mnt)
        }
        return new_ns;
 }
+EXPORT_SYMBOL(create_mnt_ns);
 
 SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,
                char __user *, type, unsigned long, flags, void __user *, data)
index d5b112bcf3ded1c423f1ef0585a82c55efcf26b5..ce907efc5508f049a9ff000a28f8d082159704ce 100644 (file)
@@ -2648,13 +2648,21 @@ out_freepage:
 static int nfs_follow_remote_path(struct vfsmount *root_mnt,
                const char *export_path, struct vfsmount *mnt_target)
 {
+       struct mnt_namespace *ns_private;
        struct nameidata nd;
        struct super_block *s;
        int ret;
 
+       ns_private = create_mnt_ns(root_mnt);
+       ret = PTR_ERR(ns_private);
+       if (IS_ERR(ns_private))
+               goto out_mntput;
+
        ret = vfs_path_lookup(root_mnt->mnt_root, root_mnt,
                        export_path, LOOKUP_FOLLOW, &nd);
 
+       put_mnt_ns(ns_private);
+
        if (ret != 0)
                goto out_err;
 
index 1225af7b21669a02368cea76868f0faae7c05b86..251da07b2a1ddab95bbfb1579ceb20845ddf3e6e 100644 (file)
@@ -2,7 +2,6 @@ config NILFS2_FS
        tristate "NILFS2 file system support (EXPERIMENTAL)"
        depends on EXPERIMENTAL
        select CRC32
-       select FS_JOURNAL_INFO
        help
          NILFS2 is a log-structured file system (LFS) supporting continuous
          snapshotting.  In addition to versioning capability of the entire
index 9938034762cca7867007dc841af663b0f097c574..dc2505abb6d7fd4b513cf63c3429863511b70e1d 100644 (file)
@@ -530,7 +530,7 @@ err_corrupt_attr:
  * the ntfs inode.
  *
  * Q: What locks are held when the function is called?
- * A: i_state has I_LOCK set, hence the inode is locked, also
+ * A: i_state has I_NEW set, hence the inode is locked, also
  *    i_count is set to 1, so it is not going to go away
  *    i_flags is set to 0 and we have no business touching it.  Only an ioctl()
  *    is allowed to write to them. We should of course be honouring them but
@@ -1207,7 +1207,7 @@ err_out:
  * necessary fields in @vi as well as initializing the ntfs inode.
  *
  * Q: What locks are held when the function is called?
- * A: i_state has I_LOCK set, hence the inode is locked, also
+ * A: i_state has I_NEW set, hence the inode is locked, also
  *    i_count is set to 1, so it is not going to go away
  *
  * Return 0 on success and -errno on error.  In the error case, the inode will
@@ -1474,7 +1474,7 @@ err_out:
  * normal directory inodes.
  *
  * Q: What locks are held when the function is called?
- * A: i_state has I_LOCK set, hence the inode is locked, also
+ * A: i_state has I_NEW set, hence the inode is locked, also
  *    i_count is set to 1, so it is not going to go away
  *
  * Return 0 on success and -errno on error.  In the error case, the inode will
index 43d79da5c57e48b5a6694ae27afb3fe84823135e..37ba29ff3158aca16ff0febd65fdb3cce24152d6 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -906,17 +906,6 @@ void free_pipe_info(struct inode *inode)
 }
 
 static struct vfsmount *pipe_mnt __read_mostly;
-static int pipefs_delete_dentry(struct dentry *dentry)
-{
-       /*
-        * At creation time, we pretended this dentry was hashed
-        * (by clearing DCACHE_UNHASHED bit in d_flags)
-        * At delete time, we restore the truth : not hashed.
-        * (so that dput() can proceed correctly)
-        */
-       dentry->d_flags |= DCACHE_UNHASHED;
-       return 0;
-}
 
 /*
  * pipefs_dname() is called from d_path().
@@ -928,7 +917,6 @@ static char *pipefs_dname(struct dentry *dentry, char *buffer, int buflen)
 }
 
 static const struct dentry_operations pipefs_dentry_operations = {
-       .d_delete       = pipefs_delete_dentry,
        .d_dname        = pipefs_dname,
 };
 
@@ -989,12 +977,6 @@ struct file *create_write_pipe(int flags)
        path.mnt = mntget(pipe_mnt);
 
        path.dentry->d_op = &pipefs_dentry_operations;
-       /*
-        * We dont want to publish this dentry into global dentry hash table.
-        * We pretend dentry is already hashed, by unsetting DCACHE_UNHASHED
-        * This permits a working /proc/$pid/fd/XXX on pipes
-        */
-       path.dentry->d_flags &= ~DCACHE_UNHASHED;
        d_instantiate(path.dentry, inode);
 
        err = -ENFILE;
index 32fae4040ebf46a94bc84cf1260c2edebce0c330..2efc57173fd703b74bfc1adaad5289df1ff1f179 100644 (file)
@@ -60,7 +60,7 @@ const struct inode_operations ramfs_file_inode_operations = {
  */
 int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize)
 {
-       unsigned long npages, xpages, loop, limit;
+       unsigned long npages, xpages, loop;
        struct page *pages;
        unsigned order;
        void *data;
index ac7cd75c86f8d351e4240bac5d1b12b1c317a4bb..513f431038f9a749960b6c9b328ece5799684330 100644 (file)
@@ -1,7 +1,6 @@
 config REISERFS_FS
        tristate "Reiserfs support"
        select CRC32
-       select FS_JOURNAL_INFO
        help
          Stores not just filenames but the files themselves in a balanced
          tree.  Uses journalling.
index 3a28e7751b3c714da6e3b2c0b7fe9ad89e82a87b..290ae38fca8ae915c749c287ce3e4a19307d3d89 100644 (file)
@@ -2538,6 +2538,12 @@ static int reiserfs_writepage(struct page *page, struct writeback_control *wbc)
        return reiserfs_write_full_page(page, wbc);
 }
 
+static void reiserfs_truncate_failed_write(struct inode *inode)
+{
+       truncate_inode_pages(inode->i_mapping, inode->i_size);
+       reiserfs_truncate_file(inode, 0);
+}
+
 static int reiserfs_write_begin(struct file *file,
                                struct address_space *mapping,
                                loff_t pos, unsigned len, unsigned flags,
@@ -2604,6 +2610,8 @@ static int reiserfs_write_begin(struct file *file,
        if (ret) {
                unlock_page(page);
                page_cache_release(page);
+               /* Truncate allocated blocks */
+               reiserfs_truncate_failed_write(inode);
        }
        return ret;
 }
@@ -2701,9 +2709,7 @@ static int reiserfs_write_end(struct file *file, struct address_space *mapping,
         ** transaction tracking stuff when the size changes.  So, we have
         ** to do the i_size updates here.
         */
-       pos += copied;
-
-       if (pos > inode->i_size) {
+       if (pos + copied > inode->i_size) {
                struct reiserfs_transaction_handle myth;
                lock_depth = reiserfs_write_lock_once(inode->i_sb);
                locked = true;
@@ -2721,7 +2727,7 @@ static int reiserfs_write_end(struct file *file, struct address_space *mapping,
                        goto journal_error;
 
                reiserfs_update_inode_transaction(inode);
-               inode->i_size = pos;
+               inode->i_size = pos + copied;
                /*
                 * this will just nest into our transaction.  It's important
                 * to use mark_inode_dirty so the inode gets pushed around on the
@@ -2751,6 +2757,10 @@ static int reiserfs_write_end(struct file *file, struct address_space *mapping,
                reiserfs_write_unlock_once(inode->i_sb, lock_depth);
        unlock_page(page);
        page_cache_release(page);
+
+       if (pos + len > inode->i_size)
+               reiserfs_truncate_failed_write(inode);
+
        return ret == 0 ? copied : ret;
 
       journal_error:
index 67716f6a1a4a29ddb5e59dda194f837cedbfe210..4a6f7f440658d4461a1f441a78516efe13a2c855 100644 (file)
@@ -7,18 +7,63 @@
  * This function cannot be inlined since i_size_{read,write} is rather
  * heavy-weight on 32-bit systems
  */
-void fsstack_copy_inode_size(struct inode *dst, const struct inode *src)
+void fsstack_copy_inode_size(struct inode *dst, struct inode *src)
 {
-       i_size_write(dst, i_size_read((struct inode *)src));
-       dst->i_blocks = src->i_blocks;
+       loff_t i_size;
+       blkcnt_t i_blocks;
+
+       /*
+        * i_size_read() includes its own seqlocking and protection from
+        * preemption (see include/linux/fs.h): we need nothing extra for
+        * that here, and prefer to avoid nesting locks than attempt to keep
+        * i_size and i_blocks in sync together.
+        */
+       i_size = i_size_read(src);
+
+       /*
+        * But if CONFIG_LBDAF (on 32-bit), we ought to make an effort to
+        * keep the two halves of i_blocks in sync despite SMP or PREEMPT -
+        * though stat's generic_fillattr() doesn't bother, and we won't be
+        * applying quotas (where i_blocks does become important) at the
+        * upper level.
+        *
+        * We don't actually know what locking is used at the lower level;
+        * but if it's a filesystem that supports quotas, it will be using
+        * i_lock as in inode_add_bytes().  tmpfs uses other locking, and
+        * its 32-bit is (just) able to exceed 2TB i_size with the aid of
+        * holes; but its i_blocks cannot carry into the upper long without
+        * almost 2TB swap - let's ignore that case.
+        */
+       if (sizeof(i_blocks) > sizeof(long))
+               spin_lock(&src->i_lock);
+       i_blocks = src->i_blocks;
+       if (sizeof(i_blocks) > sizeof(long))
+               spin_unlock(&src->i_lock);
+
+       /*
+        * If CONFIG_SMP or CONFIG_PREEMPT on 32-bit, it's vital for
+        * fsstack_copy_inode_size() to hold some lock around
+        * i_size_write(), otherwise i_size_read() may spin forever (see
+        * include/linux/fs.h).  We don't necessarily hold i_mutex when this
+        * is called, so take i_lock for that case.
+        *
+        * And if CONFIG_LBADF (on 32-bit), continue our effort to keep the
+        * two halves of i_blocks in sync despite SMP or PREEMPT: use i_lock
+        * for that case too, and do both at once by combining the tests.
+        *
+        * There is none of this locking overhead in the 64-bit case.
+        */
+       if (sizeof(i_size) > sizeof(long) || sizeof(i_blocks) > sizeof(long))
+               spin_lock(&dst->i_lock);
+       i_size_write(dst, i_size);
+       dst->i_blocks = i_blocks;
+       if (sizeof(i_size) > sizeof(long) || sizeof(i_blocks) > sizeof(long))
+               spin_unlock(&dst->i_lock);
 }
 EXPORT_SYMBOL_GPL(fsstack_copy_inode_size);
 
-/* copy all attributes; get_nlinks is optional way to override the i_nlink
- * copying
- */
-void fsstack_copy_attr_all(struct inode *dest, const struct inode *src,
-                               int (*get_nlinks)(struct inode *))
+/* copy all attributes */
+void fsstack_copy_attr_all(struct inode *dest, const struct inode *src)
 {
        dest->i_mode = src->i_mode;
        dest->i_uid = src->i_uid;
@@ -29,14 +74,6 @@ void fsstack_copy_attr_all(struct inode *dest, const struct inode *src,
        dest->i_ctime = src->i_ctime;
        dest->i_blkbits = src->i_blkbits;
        dest->i_flags = src->i_flags;
-
-       /*
-        * Update the nlinks AFTER updating the above fields, because the
-        * get_links callback may depend on them.
-        */
-       if (!get_nlinks)
-               dest->i_nlink = src->i_nlink;
-       else
-               dest->i_nlink = (*get_nlinks)(dest);
+       dest->i_nlink = src->i_nlink;
 }
 EXPORT_SYMBOL_GPL(fsstack_copy_attr_all);
index 36752a683481533566fda6910e11d4c8a0d66a41..418727a2a2390f435d68b1fad91dede88dc4c17f 100644 (file)
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -355,6 +355,7 @@ SYSCALL_DEFINE(sync_file_range)(int fd, loff_t offset, loff_t nbytes,
 {
        int ret;
        struct file *file;
+       struct address_space *mapping;
        loff_t endbyte;                 /* inclusive */
        int fput_needed;
        umode_t i_mode;
@@ -405,7 +406,28 @@ SYSCALL_DEFINE(sync_file_range)(int fd, loff_t offset, loff_t nbytes,
                        !S_ISLNK(i_mode))
                goto out_put;
 
-       ret = do_sync_mapping_range(file->f_mapping, offset, endbyte, flags);
+       mapping = file->f_mapping;
+       if (!mapping) {
+               ret = -EINVAL;
+               goto out_put;
+       }
+
+       ret = 0;
+       if (flags & SYNC_FILE_RANGE_WAIT_BEFORE) {
+               ret = filemap_fdatawait_range(mapping, offset, endbyte);
+               if (ret < 0)
+                       goto out_put;
+       }
+
+       if (flags & SYNC_FILE_RANGE_WRITE) {
+               ret = filemap_fdatawrite_range(mapping, offset, endbyte);
+               if (ret < 0)
+                       goto out_put;
+       }
+
+       if (flags & SYNC_FILE_RANGE_WAIT_AFTER)
+               ret = filemap_fdatawait_range(mapping, offset, endbyte);
+
 out_put:
        fput_light(file, fput_needed);
 out:
@@ -437,38 +459,3 @@ asmlinkage long SyS_sync_file_range2(long fd, long flags,
 }
 SYSCALL_ALIAS(sys_sync_file_range2, SyS_sync_file_range2);
 #endif
-
-/*
- * `endbyte' is inclusive
- */
-int do_sync_mapping_range(struct address_space *mapping, loff_t offset,
-                         loff_t endbyte, unsigned int flags)
-{
-       int ret;
-
-       if (!mapping) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       ret = 0;
-       if (flags & SYNC_FILE_RANGE_WAIT_BEFORE) {
-               ret = filemap_fdatawait_range(mapping, offset, endbyte);
-               if (ret < 0)
-                       goto out;
-       }
-
-       if (flags & SYNC_FILE_RANGE_WRITE) {
-               ret = __filemap_fdatawrite_range(mapping, offset, endbyte,
-                                               WB_SYNC_ALL);
-               if (ret < 0)
-                       goto out;
-       }
-
-       if (flags & SYNC_FILE_RANGE_WAIT_AFTER) {
-               ret = filemap_fdatawait_range(mapping, offset, endbyte);
-       }
-out:
-       return ret;
-}
-EXPORT_SYMBOL_GPL(do_sync_mapping_range);
index 39849f887e724602fa54d1feedf0d63090fe3d6e..16a6444330ec65b79488ceea7bd82295c4fde5b0 100644 (file)
@@ -45,7 +45,7 @@
  *
  * Similarly, @i_mutex is not always locked in 'ubifs_readpage()', e.g., the
  * read-ahead path does not lock it ("sys_read -> generic_file_aio_read ->
- * ondemand_readahead -> readpage"). In case of readahead, @I_LOCK flag is not
+ * ondemand_readahead -> readpage"). In case of readahead, @I_SYNC flag is not
  * set as well. However, UBIFS disables readahead.
  */
 
index 1d5b298ba8b21d5ab86b22e131336f366101e4a0..225946012d0b3d2015e72a81d62a751ac0a1df84 100644 (file)
@@ -794,7 +794,7 @@ xfs_setup_inode(
        struct inode            *inode = &ip->i_vnode;
 
        inode->i_ino = ip->i_ino;
-       inode->i_state = I_NEW|I_LOCK;
+       inode->i_state = I_NEW;
        inode_add_to_lists(ip->i_mount->m_super, inode);
 
        inode->i_mode   = ip->i_d.di_mode;
index 0de36c2a46f1e7798a8ac7080051f2611aaa0064..fa402a6bbbcf3272ee002700aa85ca118cbbc86e 100644 (file)
@@ -91,7 +91,7 @@ xfs_inode_alloc(
        ip->i_new_size = 0;
 
        /* prevent anyone from using this yet */
-       VFS_I(ip)->i_state = I_NEW|I_LOCK;
+       VFS_I(ip)->i_state = I_NEW;
 
        return ip;
 }
@@ -217,7 +217,7 @@ xfs_iget_cache_hit(
                        trace_xfs_iget_reclaim(ip);
                        goto out_error;
                }
-               inode->i_state = I_LOCK|I_NEW;
+               inode->i_state = I_NEW;
        } else {
                /* If the VFS inode is being torn down, pause and try again. */
                if (!igrab(inode)) {
index 681ddf3e844c1fde1c1db04dbfe1629daaaf9108..fcd268ce06744ab616aeb6a5e429c723426906f6 100644 (file)
@@ -51,7 +51,7 @@
 #endif
 
 /*
- * Before Linux 2.6.32 only O_DSYNC semantics were implemented, but using
+ * Before Linux 2.6.33 only O_DSYNC semantics were implemented, but using
  * the O_SYNC flag.  We continue to use the existing numerical value
  * for O_DSYNC semantics now, but using the correct symbolic name for it.
  * This new value is used to request true Posix O_SYNC semantics.  It is
index f72914db2a115f0fb7ad2b074300272f699c696b..756f831cbdd557236057ede228bfdb9481559c97 100644 (file)
@@ -118,6 +118,7 @@ header-y += mtio.h
 header-y += ncp_no.h
 header-y += neighbour.h
 header-y += net_dropmon.h
+header-y += net_tstamp.h
 header-y += netfilter_arp.h
 header-y += netrom.h
 header-y += nfs2.h
index 0f5f57858a237bb16335b90bafbe9ece0cf9d8f8..8c4f884db6b40044a5934985656551b1dee22d8d 100644 (file)
@@ -36,18 +36,18 @@ struct backlight_device;
 struct fb_info;
 
 struct backlight_ops {
-       unsigned int options;
+       const unsigned int options;
 
 #define BL_CORE_SUSPENDRESUME  (1 << 0)
 
        /* Notify the backlight driver some property has changed */
-       int (*update_status)(struct backlight_device *);
+       int (* const update_status)(struct backlight_device *);
        /* Return the current backlight brightness (accounting for power,
           fb_blank etc.) */
-       int (*get_brightness)(struct backlight_device *);
+       int (* const get_brightness)(struct backlight_device *);
        /* Check if given framebuffer device is the one bound to this backlight;
           return 0 if not, !=0 if it is. If NULL, backlight always matches the fb. */
-       int (*check_fb)(struct fb_info *);
+       int (* const check_fb)(struct fb_info *);
 };
 
 /* This structure defines all the properties of a backlight */
@@ -86,7 +86,7 @@ struct backlight_device {
           registered this device has been unloaded, and if class_get_devdata()
           points to something in the body of that driver, it is also invalid. */
        struct mutex ops_lock;
-       struct backlight_ops *ops;
+       const struct backlight_ops *ops;
 
        /* The framebuffer notifier block */
        struct notifier_block fb_notif;
@@ -103,7 +103,7 @@ static inline void backlight_update_status(struct backlight_device *bd)
 }
 
 extern struct backlight_device *backlight_device_register(const char *name,
-       struct device *dev, void *devdata, struct backlight_ops *ops);
+       struct device *dev, void *devdata, const struct backlight_ops *ops);
 extern void backlight_device_unregister(struct backlight_device *bd);
 extern void backlight_force_update(struct backlight_device *bd,
                                   enum backlight_update_reason reason);
index aece486ac7349b8463ace95585b2fa9379a04ab3..cd4349bdc34efd2b5044eb8f83e0e4f98e211817 100644 (file)
@@ -68,6 +68,14 @@ struct linux_binprm{
 
 #define BINPRM_MAX_RECURSION 4
 
+/* Function parameter for binfmt->coredump */
+struct coredump_params {
+       long signr;
+       struct pt_regs *regs;
+       struct file *file;
+       unsigned long limit;
+};
+
 /*
  * This structure defines the functions that are used to load the binary formats that
  * linux accepts.
@@ -77,7 +85,7 @@ struct linux_binfmt {
        struct module *module;
        int (*load_binary)(struct linux_binprm *, struct  pt_regs * regs);
        int (*load_shlib)(struct file *);
-       int (*core_dump)(long signr, struct pt_regs *regs, struct file *file, unsigned long limit);
+       int (*core_dump)(struct coredump_params *cprm);
        unsigned long min_coredump;     /* minimal dump size */
        int hasvdso;
 };
index 66bc0a54b284b635044276a85f6aeaec28acce09..cca191933ff6ec929d2784fc438049d1c60e0c7f 100644 (file)
@@ -1095,10 +1095,6 @@ struct file_lock {
 
 extern void send_sigio(struct fown_struct *fown, int fd, int band);
 
-/* fs/sync.c */
-extern int do_sync_mapping_range(struct address_space *mapping, loff_t offset,
-                       loff_t endbyte, unsigned int flags);
-
 #ifdef CONFIG_FILE_LOCKING
 extern int fcntl_getlk(struct file *, struct flock __user *);
 extern int fcntl_setlk(unsigned int, struct file *, unsigned int,
@@ -1591,7 +1587,7 @@ struct super_operations {
  * until that flag is cleared.  I_WILL_FREE, I_FREEING and I_CLEAR are set at
  * various stages of removing an inode.
  *
- * Two bits are used for locking and completion notification, I_LOCK and I_SYNC.
+ * Two bits are used for locking and completion notification, I_NEW and I_SYNC.
  *
  * I_DIRTY_SYNC                Inode is dirty, but doesn't have to be written on
  *                     fdatasync().  i_atime is the usual cause.
@@ -1600,8 +1596,14 @@ struct super_operations {
  *                     don't have to write inode on fdatasync() when only
  *                     mtime has changed in it.
  * I_DIRTY_PAGES       Inode has dirty pages.  Inode itself may be clean.
- * I_NEW               get_new_inode() sets i_state to I_LOCK|I_NEW.  Both
- *                     are cleared by unlock_new_inode(), called from iget().
+ * I_NEW               Serves as both a mutex and completion notification.
+ *                     New inodes set I_NEW.  If two processes both create
+ *                     the same inode, one of them will release its inode and
+ *                     wait for I_NEW to be released before returning.
+ *                     Inodes in I_WILL_FREE, I_FREEING or I_CLEAR state can
+ *                     also cause waiting on I_NEW, without I_NEW actually
+ *                     being set.  find_inode() uses this to prevent returning
+ *                     nearly-dead inodes.
  * I_WILL_FREE         Must be set when calling write_inode_now() if i_count
  *                     is zero.  I_FREEING must be set when I_WILL_FREE is
  *                     cleared.
@@ -1615,20 +1617,11 @@ struct super_operations {
  *                     prohibited for many purposes.  iget() must wait for
  *                     the inode to be completely released, then create it
  *                     anew.  Other functions will just ignore such inodes,
- *                     if appropriate.  I_LOCK is used for waiting.
+ *                     if appropriate.  I_NEW is used for waiting.
  *
- * I_LOCK              Serves as both a mutex and completion notification.
- *                     New inodes set I_LOCK.  If two processes both create
- *                     the same inode, one of them will release its inode and
- *                     wait for I_LOCK to be released before returning.
- *                     Inodes in I_WILL_FREE, I_FREEING or I_CLEAR state can
- *                     also cause waiting on I_LOCK, without I_LOCK actually
- *                     being set.  find_inode() uses this to prevent returning
- *                     nearly-dead inodes.
- * I_SYNC              Similar to I_LOCK, but limited in scope to writeback
- *                     of inode dirty data.  Having a separate lock for this
- *                     purpose reduces latency and prevents some filesystem-
- *                     specific deadlocks.
+ * I_SYNC              Synchonized write of dirty inode data.  The bits is
+ *                     set during data writeback, and cleared with a wakeup
+ *                     on the bit address once it is done.
  *
  * Q: What is the difference between I_WILL_FREE and I_FREEING?
  * Q: igrab() only checks on (I_FREEING|I_WILL_FREE).  Should it also check on
@@ -1637,13 +1630,12 @@ struct super_operations {
 #define I_DIRTY_SYNC           1
 #define I_DIRTY_DATASYNC       2
 #define I_DIRTY_PAGES          4
-#define I_NEW                  8
+#define __I_NEW                        3
+#define I_NEW                  (1 << __I_NEW)
 #define I_WILL_FREE            16
 #define I_FREEING              32
 #define I_CLEAR                        64
-#define __I_LOCK               7
-#define I_LOCK                 (1 << __I_LOCK)
-#define __I_SYNC               8
+#define __I_SYNC               7
 #define I_SYNC                 (1 << __I_SYNC)
 
 #define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES)
index bb516ceeefc91835d083c2184eec9761ebdd7c87..da317c7163ab55c4ff6e3552c58ecb7db916ce7e 100644 (file)
@@ -8,10 +8,8 @@
 #include <linux/fs.h>
 
 /* externs for fs/stack.c */
-extern void fsstack_copy_attr_all(struct inode *dest, const struct inode *src,
-                               int (*get_nlinks)(struct inode *));
-
-extern void fsstack_copy_inode_size(struct inode *dst, const struct inode *src);
+extern void fsstack_copy_attr_all(struct inode *dest, const struct inode *src);
+extern void fsstack_copy_inode_size(struct inode *dst, struct inode *src);
 
 /* inlines */
 static inline void fsstack_copy_attr_atime(struct inode *dest,
index 5ed8b9c50355185439736b3cb4d850d3b07cb646..abec69b63d7e3a5d65f2bc430a0cd389138367b0 100644 (file)
@@ -111,12 +111,6 @@ extern struct cred init_cred;
 # define INIT_PERF_EVENTS(tsk)
 #endif
 
-#ifdef CONFIG_FS_JOURNAL_INFO
-#define INIT_JOURNAL_INFO      .journal_info = NULL,
-#else
-#define INIT_JOURNAL_INFO
-#endif
-
 /*
  *  INIT_TASK is used to set up the first task table, touch at
  * your own risk!. Base=0, limit=0x1fffff (=2MB)
@@ -168,6 +162,7 @@ extern struct cred init_cred;
                .signal = {{0}}},                                       \
        .blocked        = {{0}},                                        \
        .alloc_lock     = __SPIN_LOCK_UNLOCKED(tsk.alloc_lock),         \
+       .journal_info   = NULL,                                         \
        .cpu_timers     = INIT_CPU_TIMERS(tsk.cpu_timers),              \
        .fs_excl        = ATOMIC_INIT(0),                               \
        .pi_lock        = __RAW_SPIN_LOCK_UNLOCKED(tsk.pi_lock),        \
@@ -178,7 +173,6 @@ extern struct cred init_cred;
                [PIDTYPE_SID]  = INIT_PID_LINK(PIDTYPE_SID),            \
        },                                                              \
        .dirties = INIT_PROP_LOCAL_SINGLE(dirties),                     \
-       INIT_JOURNAL_INFO                                               \
        INIT_IDS                                                        \
        INIT_PERF_EVENTS(tsk)                                           \
        INIT_TRACE_IRQFLAGS                                             \
index 3c7497d46ee9655fa86f7bb42f1637a023d6fd25..99d9a6766f7ec055feca4a25d7d5e4c89fd9b058 100644 (file)
@@ -32,8 +32,7 @@ extern void kmemleak_padding(const void *ptr, unsigned long offset,
                             size_t size) __ref;
 extern void kmemleak_not_leak(const void *ptr) __ref;
 extern void kmemleak_ignore(const void *ptr) __ref;
-extern void kmemleak_scan_area(const void *ptr, unsigned long offset,
-                              size_t length, gfp_t gfp) __ref;
+extern void kmemleak_scan_area(const void *ptr, size_t size, gfp_t gfp) __ref;
 extern void kmemleak_no_scan(const void *ptr) __ref;
 
 static inline void kmemleak_alloc_recursive(const void *ptr, size_t size,
@@ -84,8 +83,7 @@ static inline void kmemleak_not_leak(const void *ptr)
 static inline void kmemleak_ignore(const void *ptr)
 {
 }
-static inline void kmemleak_scan_area(const void *ptr, unsigned long offset,
-                                     size_t length, gfp_t gfp)
+static inline void kmemleak_scan_area(const void *ptr, size_t size, gfp_t gfp)
 {
 }
 static inline void kmemleak_erase(void **ptr)
index afc9f9fd70f516a47bfceb4a49cc1e5d3b9bb492..2618aa9063bcc6f1a0fdf83727f234ad83448920 100644 (file)
@@ -12,9 +12,6 @@
 #ifndef __LINUX_LEDS_LP3944_H
 #define __LINUX_LEDS_LP3944_H
 
-#include <linux/leds.h>
-#include <linux/workqueue.h>
-
 #define LP3944_LED0 0
 #define LP3944_LED1 1
 #define LP3944_LED2 2
index 96eea90f01a87711440b6fd3162e2d40d38269b4..f158eb1149aa8b6cd0029ca92ac2645a672a3928 100644 (file)
@@ -32,7 +32,7 @@ struct pca9532_led {
        struct i2c_client *client;
        char *name;
        struct led_classdev ldev;
-       struct work_struct work;
+       struct work_struct work;
        enum pca9532_type type;
        enum pca9532_state state;
 };
diff --git a/include/linux/leds-regulator.h b/include/linux/leds-regulator.h
new file mode 100644 (file)
index 0000000..5a8eb38
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * leds-regulator.h - platform data structure for regulator driven LEDs.
+ *
+ * Copyright (C) 2009 Antonio Ospite <ospite@studenti.unina.it>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __LINUX_LEDS_REGULATOR_H
+#define __LINUX_LEDS_REGULATOR_H
+
+/*
+ * Use "vled" as supply id when declaring the regulator consumer:
+ *
+ * static struct regulator_consumer_supply pcap_regulator_VVIB_consumers [] = {
+ *     { .dev_name = "leds-regulator.0", supply = "vled" },
+ * };
+ *
+ * If you have several regulator driven LEDs, you can append a numerical id to
+ * .dev_name as done above, and use the same id when declaring the platform
+ * device:
+ *
+ * static struct led_regulator_platform_data a780_vibrator_data = {
+ *     .name   = "a780::vibrator",
+ * };
+ *
+ * static struct platform_device a780_vibrator = {
+ *     .name = "leds-regulator",
+ *     .id   = 0,
+ *     .dev  = {
+ *             .platform_data = &a780_vibrator_data,
+ *     },
+ * };
+ */
+
+#include <linux/leds.h>
+
+struct led_regulator_platform_data {
+       char *name;                     /* LED name as expected by LED class */
+       enum led_brightness brightness; /* initial brightness value */
+};
+
+#endif /* __LINUX_LEDS_REGULATOR_H */
index 415c228743d562f3e93bc2c67a49b8dfbbe58a5b..fd322aca33ba89a9cec62eb7f3909f813b2267a5 100644 (file)
@@ -41,6 +41,23 @@ struct wm831x_battery_pdata {
        int timeout;        /** Charge cycle timeout, in minutes */
 };
 
+/**
+ * Configuration for the WM831x DC-DC BuckWise convertors.  This
+ * should be passed as driver_data in the regulator_init_data.
+ *
+ * Currently all the configuration is for the fast DVS switching
+ * support of the devices.  This allows MFPs on the device to be
+ * configured as an input to switch between two output voltages,
+ * allowing voltage transitions without the expense of an access over
+ * I2C or SPI buses.
+ */
+struct wm831x_buckv_pdata {
+       int dvs_gpio;        /** CPU GPIO to use for DVS switching */
+       int dvs_control_src; /** Hardware DVS source to use (1 or 2) */
+       int dvs_init_state;  /** DVS state to expect on startup */
+       int dvs_state_gpio;  /** CPU GPIO to use for monitoring status */
+};
+
 /* Sources for status LED configuration.  Values are register values
  * plus 1 to allow for a zero default for preserve.
  */
index 8a5509877192b903390b7851ae77df96c9e7fad1..ee24ef8ab616e6b48f6ac6cd0d9ff0c038c19bc1 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef LINUX_MM_DEBUG_H
 #define LINUX_MM_DEBUG_H 1
 
-#include <linux/autoconf.h>
-
 #ifdef CONFIG_DEBUG_VM
 #define VM_BUG_ON(cond) BUG_ON(cond)
 #else
index 6f7561730d88c3b8c816e34e76b140cb9612ce8c..30fe668c25425eaf1e1464c6a49d8b170ccc60ca 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/seqlock.h>
 #include <linux/nodemask.h>
 #include <linux/pageblock-flags.h>
-#include <linux/bounds.h>
+#include <generated/bounds.h>
 #include <asm/atomic.h>
 #include <asm/page.h>
 
index d9ebf1037dfa01699f67722b361f003ed5697abe..d74785c2393ad03976925e8ea6b63e3716718b79 100644 (file)
@@ -23,6 +23,7 @@ struct proc_mounts {
 
 struct fs_struct;
 
+extern struct mnt_namespace *create_mnt_ns(struct vfsmount *mnt);
 extern struct mnt_namespace *copy_mnt_ns(unsigned long, struct mnt_namespace *,
                struct fs_struct *);
 extern void put_mnt_ns(struct mnt_namespace *ns);
index feee2ba8d06a39e90e841289e8e83b9750ee871e..5b59f35dcb8fdd3ef12c4bc4f2cd5f439e63053b 100644 (file)
@@ -8,7 +8,7 @@
 #include <linux/types.h>
 #ifndef __GENERATING_BOUNDS_H
 #include <linux/mm_types.h>
-#include <linux/bounds.h>
+#include <generated/bounds.h>
 #endif /* !__GENERATING_BOUNDS_H */
 
 /*
index 7a9754c96775091d1ac9ef9c002682e29c38ca88..01b3d759f1fccec7f88e1b276973aa6f70e5bae5 100644 (file)
@@ -10,7 +10,7 @@ struct platform_pwm_backlight_data {
        unsigned int dft_brightness;
        unsigned int pwm_period_ns;
        int (*init)(struct device *dev);
-       int (*notify)(int brightness);
+       int (*notify)(struct device *dev, int brightness);
        void (*exit)(struct device *dev);
 };
 
index 490c5b37b6d7f02f2f25003b4e7f4d4356a4bed9..030d92255c7a09b8fd6175f93e0a1862b96c21a5 100644 (file)
@@ -35,6 +35,8 @@
 #ifndef __LINUX_REGULATOR_CONSUMER_H_
 #define __LINUX_REGULATOR_CONSUMER_H_
 
+#include <linux/device.h>
+
 /*
  * Regulator operating modes.
  *
index 87f5f176d4ef31c521e133a9b24c92471d5d5eeb..234a8476cba8a5acadb627236819e89333838eec 100644 (file)
@@ -43,16 +43,20 @@ struct regulator;
 /**
  * struct regulator_state - regulator state during low power system states
  *
- * This describes a regulators state during a system wide low power state.
+ * This describes a regulators state during a system wide low power
+ * state.  One of enabled or disabled must be set for the
+ * configuration to be applied.
  *
  * @uV: Operating voltage during suspend.
  * @mode: Operating mode during suspend.
  * @enabled: Enabled during suspend.
+ * @disabled: Disabled during suspend.
  */
 struct regulator_state {
        int uV; /* suspend voltage */
        unsigned int mode; /* suspend regulator operating mode */
        int enabled; /* is regulator enabled in this suspend state */
+       int disabled; /* is the regulator disbled in this suspend state */
 };
 
 /**
diff --git a/include/linux/regulator/max8660.h b/include/linux/regulator/max8660.h
new file mode 100644 (file)
index 0000000..9936763
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * max8660.h  --  Voltage regulation for the Maxim 8660/8661
+ *
+ * Copyright (C) 2009 Wolfram Sang, Pengutronix e.K.
+ *
+ * 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; 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
+ */
+
+#ifndef __LINUX_REGULATOR_MAX8660_H
+#define __LINUX_REGULATOR_MAX8660_H
+
+#include <linux/regulator/machine.h>
+
+enum {
+       MAX8660_V3,
+       MAX8660_V4,
+       MAX8660_V5,
+       MAX8660_V6,
+       MAX8660_V7,
+       MAX8660_V_END,
+};
+
+/**
+ * max8660_subdev_data - regulator subdev data
+ * @id: regulator id
+ * @name: regulator name
+ * @platform_data: regulator init data
+ */
+struct max8660_subdev_data {
+       int                             id;
+       char                            *name;
+       struct regulator_init_data      *platform_data;
+};
+
+/**
+ * max8660_platform_data - platform data for max8660
+ * @num_subdevs: number of regulators used
+ * @subdevs: pointer to regulators used
+ * @en34_is_high: if EN34 is driven high, regulators cannot be en-/disabled.
+ */
+struct max8660_platform_data {
+       int num_subdevs;
+       struct max8660_subdev_data *subdevs;
+       unsigned en34_is_high:1;
+};
+#endif
index 244c287a5ac12f4b0c10068322b3daac493ba29e..211ed32befbd8cfec7065a236924987210877d42 100644 (file)
@@ -1446,10 +1446,8 @@ struct task_struct {
        gfp_t lockdep_reclaim_gfp;
 #endif
 
-#ifdef CONFIG_FS_JOURNAL_INFO
 /* journalling filesystem info */
        void *journal_info;
-#endif
 
 /* stacked block device info */
        struct bio *bio_list, **bio_tail;
diff --git a/include/linux/spi/dw_spi.h b/include/linux/spi/dw_spi.h
new file mode 100644 (file)
index 0000000..51b3e77
--- /dev/null
@@ -0,0 +1,212 @@
+#ifndef DW_SPI_HEADER_H
+#define DW_SPI_HEADER_H
+#include <linux/io.h>
+
+/* Bit fields in CTRLR0 */
+#define SPI_DFS_OFFSET                 0
+
+#define SPI_FRF_OFFSET                 4
+#define SPI_FRF_SPI                    0x0
+#define SPI_FRF_SSP                    0x1
+#define SPI_FRF_MICROWIRE              0x2
+#define SPI_FRF_RESV                   0x3
+
+#define SPI_MODE_OFFSET                        6
+#define SPI_SCPH_OFFSET                        6
+#define SPI_SCOL_OFFSET                        7
+#define SPI_TMOD_OFFSET                        8
+#define        SPI_TMOD_TR                     0x0             /* xmit & recv */
+#define SPI_TMOD_TO                    0x1             /* xmit only */
+#define SPI_TMOD_RO                    0x2             /* recv only */
+#define SPI_TMOD_EPROMREAD             0x3             /* eeprom read mode */
+
+#define SPI_SLVOE_OFFSET               10
+#define SPI_SRL_OFFSET                 11
+#define SPI_CFS_OFFSET                 12
+
+/* Bit fields in SR, 7 bits */
+#define SR_MASK                                0x7f            /* cover 7 bits */
+#define SR_BUSY                                (1 << 0)
+#define SR_TF_NOT_FULL                 (1 << 1)
+#define SR_TF_EMPT                     (1 << 2)
+#define SR_RF_NOT_EMPT                 (1 << 3)
+#define SR_RF_FULL                     (1 << 4)
+#define SR_TX_ERR                      (1 << 5)
+#define SR_DCOL                                (1 << 6)
+
+/* Bit fields in ISR, IMR, RISR, 7 bits */
+#define SPI_INT_TXEI                   (1 << 0)
+#define SPI_INT_TXOI                   (1 << 1)
+#define SPI_INT_RXUI                   (1 << 2)
+#define SPI_INT_RXOI                   (1 << 3)
+#define SPI_INT_RXFI                   (1 << 4)
+#define SPI_INT_MSTI                   (1 << 5)
+
+/* TX RX interrupt level threshhold, max can be 256 */
+#define SPI_INT_THRESHOLD              32
+
+enum dw_ssi_type {
+       SSI_MOTO_SPI = 0,
+       SSI_TI_SSP,
+       SSI_NS_MICROWIRE,
+};
+
+struct dw_spi_reg {
+       u32     ctrl0;
+       u32     ctrl1;
+       u32     ssienr;
+       u32     mwcr;
+       u32     ser;
+       u32     baudr;
+       u32     txfltr;
+       u32     rxfltr;
+       u32     txflr;
+       u32     rxflr;
+       u32     sr;
+       u32     imr;
+       u32     isr;
+       u32     risr;
+       u32     txoicr;
+       u32     rxoicr;
+       u32     rxuicr;
+       u32     msticr;
+       u32     icr;
+       u32     dmacr;
+       u32     dmatdlr;
+       u32     dmardlr;
+       u32     idr;
+       u32     version;
+       u32     dr;             /* Currently oper as 32 bits,
+                               though only low 16 bits matters */
+} __packed;
+
+struct dw_spi {
+       struct spi_master       *master;
+       struct spi_device       *cur_dev;
+       struct device           *parent_dev;
+       enum dw_ssi_type        type;
+
+       void __iomem            *regs;
+       unsigned long           paddr;
+       u32                     iolen;
+       int                     irq;
+       u32                     max_freq;       /* max bus freq supported */
+
+       u16                     bus_num;
+       u16                     num_cs;         /* supported slave numbers */
+
+       /* Driver message queue */
+       struct workqueue_struct *workqueue;
+       struct work_struct      pump_messages;
+       spinlock_t              lock;
+       struct list_head        queue;
+       int                     busy;
+       int                     run;
+
+       /* Message Transfer pump */
+       struct tasklet_struct   pump_transfers;
+
+       /* Current message transfer state info */
+       struct spi_message      *cur_msg;
+       struct spi_transfer     *cur_transfer;
+       struct chip_data        *cur_chip;
+       struct chip_data        *prev_chip;
+       size_t                  len;
+       void                    *tx;
+       void                    *tx_end;
+       void                    *rx;
+       void                    *rx_end;
+       int                     dma_mapped;
+       dma_addr_t              rx_dma;
+       dma_addr_t              tx_dma;
+       size_t                  rx_map_len;
+       size_t                  tx_map_len;
+       u8                      n_bytes;        /* current is a 1/2 bytes op */
+       u8                      max_bits_per_word;      /* maxim is 16b */
+       u32                     dma_width;
+       int                     cs_change;
+       int                     (*write)(struct dw_spi *dws);
+       int                     (*read)(struct dw_spi *dws);
+       irqreturn_t             (*transfer_handler)(struct dw_spi *dws);
+       void                    (*cs_control)(u32 command);
+
+       /* Dma info */
+       int                     dma_inited;
+       struct dma_chan         *txchan;
+       struct dma_chan         *rxchan;
+       int                     txdma_done;
+       int                     rxdma_done;
+       u64                     tx_param;
+       u64                     rx_param;
+       struct device           *dma_dev;
+       dma_addr_t              dma_addr;
+
+       /* Bus interface info */
+       void                    *priv;
+#ifdef CONFIG_DEBUG_FS
+       struct dentry *debugfs;
+#endif
+};
+
+#define dw_readl(dw, name) \
+       __raw_readl(&(((struct dw_spi_reg *)dw->regs)->name))
+#define dw_writel(dw, name, val) \
+       __raw_writel((val), &(((struct dw_spi_reg *)dw->regs)->name))
+#define dw_readw(dw, name) \
+       __raw_readw(&(((struct dw_spi_reg *)dw->regs)->name))
+#define dw_writew(dw, name, val) \
+       __raw_writew((val), &(((struct dw_spi_reg *)dw->regs)->name))
+
+static inline void spi_enable_chip(struct dw_spi *dws, int enable)
+{
+       dw_writel(dws, ssienr, (enable ? 1 : 0));
+}
+
+static inline void spi_set_clk(struct dw_spi *dws, u16 div)
+{
+       dw_writel(dws, baudr, div);
+}
+
+static inline void spi_chip_sel(struct dw_spi *dws, u16 cs)
+{
+       if (cs > dws->num_cs)
+               return;
+       dw_writel(dws, ser, 1 << cs);
+}
+
+/* Disable IRQ bits */
+static inline void spi_mask_intr(struct dw_spi *dws, u32 mask)
+{
+       u32 new_mask;
+
+       new_mask = dw_readl(dws, imr) & ~mask;
+       dw_writel(dws, imr, new_mask);
+}
+
+/* Enable IRQ bits */
+static inline void spi_umask_intr(struct dw_spi *dws, u32 mask)
+{
+       u32 new_mask;
+
+       new_mask = dw_readl(dws, imr) | mask;
+       dw_writel(dws, imr, new_mask);
+}
+
+/*
+ * Each SPI slave device to work with dw_api controller should
+ * has such a structure claiming its working mode (PIO/DMA etc),
+ * which can be save in the "controller_data" member of the
+ * struct spi_device
+ */
+struct dw_spi_chip {
+       u8 poll_mode;   /* 0 for contoller polling mode */
+       u8 type;        /* SPI/SSP/Micrwire */
+       u8 enable_dma;
+       void (*cs_control)(u32 command);
+};
+
+extern int dw_spi_add_host(struct dw_spi *dws);
+extern void dw_spi_remove_host(struct dw_spi *dws);
+extern int dw_spi_suspend_host(struct dw_spi *dws);
+extern int dw_spi_resume_host(struct dw_spi *dws);
+#endif /* DW_SPI_HEADER_H */
index 79b9837d9ca079b809405ae7d0a6ed93d5cf273c..cf97b5b9d1fe8928bca85db1e5ae888681a39519 100644 (file)
@@ -1,4 +1,4 @@
-#include <linux/utsrelease.h>
+#include <generated/utsrelease.h>
 #include <linux/module.h>
 
 /* Simply sanity version stamp for modules. */
index 3fb9944e50a650f35075fd37ecb02cdf04d8e8aa..d5dd0bc408fd4e7b1e79ea8326841a8a187f2738 100644 (file)
@@ -84,6 +84,8 @@ struct vt_setactivate {
 
 #define VT_SETACTIVATE 0x560F  /* Activate and set the mode of a console */
 
+#ifdef __KERNEL__
+
 #ifdef CONFIG_VT_CONSOLE
 
 extern int vt_kmsg_redirect(int new);
@@ -97,6 +99,8 @@ static inline int vt_kmsg_redirect(int new)
 
 #endif
 
+#endif /* __KERNEL__ */
+
 #define vt_get_kmsg_redirect() vt_kmsg_redirect(-1)
 
 #endif /* _LINUX_VT_H */
index 705f01fe413a5f982538bf58fe6c524f4828635a..c18c008f4bbfffb3a59df701c2e366d35325e2df 100644 (file)
@@ -79,8 +79,7 @@ void wakeup_flusher_threads(long nr_pages);
 static inline void wait_on_inode(struct inode *inode)
 {
        might_sleep();
-       wait_on_bit(&inode->i_state, __I_LOCK, inode_wait,
-                                                       TASK_UNINTERRUPTIBLE);
+       wait_on_bit(&inode->i_state, __I_NEW, inode_wait, TASK_UNINTERRUPTIBLE);
 }
 static inline void inode_sync_wait(struct inode *inode)
 {
index 4a243df426f70b9f3fbe366f1b94dbb8f4cdd1cf..0bf677aa0872f8c9f61c411b5adb6f1c395a8910 100644 (file)
@@ -15,12 +15,8 @@ mounts-$(CONFIG_BLK_DEV_RAM) += do_mounts_rd.o
 mounts-$(CONFIG_BLK_DEV_INITRD)        += do_mounts_initrd.o
 mounts-$(CONFIG_BLK_DEV_MD)    += do_mounts_md.o
 
-# files to be removed upon make clean
-clean-files := ../include/linux/compile.h
-
 # dependencies on generated files need to be listed explicitly
-
-$(obj)/version.o: include/linux/compile.h
+$(obj)/version.o: include/generated/compile.h
 
 # compile.h changes depending on hostname, generation number, etc,
 # so we regenerate it always.
@@ -30,7 +26,7 @@ $(obj)/version.o: include/linux/compile.h
        chk_compile.h = :
  quiet_chk_compile.h = echo '  CHK     $@'
 silent_chk_compile.h = :
-include/linux/compile.h: FORCE
+include/generated/compile.h: FORCE
        @$($(quiet)chk_compile.h)
        $(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkcompile_h $@ \
        "$(UTS_MACHINE)" "$(CONFIG_SMP)" "$(CONFIG_PREEMPT)" "$(CC) $(KBUILD_CFLAGS)"
index 52a8b98642b8fb78343dfd63e20d1f448acb5866..adff586401a50c2e6de2ee145ae6a047fd03c6ba 100644 (file)
@@ -6,11 +6,11 @@
  *  May be freely distributed as part of Linux.
  */
 
-#include <linux/compile.h>
+#include <generated/compile.h>
 #include <linux/module.h>
 #include <linux/uts.h>
 #include <linux/utsname.h>
-#include <linux/utsrelease.h>
+#include <generated/utsrelease.h>
 #include <linux/version.h>
 
 #ifndef CONFIG_KALLSYMS
index 3c5301381837407d986f06cddaf665eca71fb412..98a51f26c13691b9f6f5955cdc83840f8932c2be 100644 (file)
@@ -12,7 +12,7 @@
 
 void foo(void)
 {
-       /* The enum constants to put into include/linux/bounds.h */
+       /* The enum constants to put into include/generated/bounds.h */
        DEFINE(NR_PAGEFLAGS, __NR_PAGEFLAGS);
        DEFINE(MAX_NR_ZONES, __MAX_NR_ZONES);
        /* End of constants */
index 5962d7ccf24371ed7aedf4832cac0cbd5e9c3820..546774a31a66752a698faa02c4e54f7c39fbef9e 100644 (file)
@@ -68,10 +68,10 @@ static void __unhash_process(struct task_struct *p)
                detach_pid(p, PIDTYPE_SID);
 
                list_del_rcu(&p->tasks);
+               list_del_init(&p->sibling);
                __get_cpu_var(process_counts)--;
        }
        list_del_rcu(&p->thread_group);
-       list_del_init(&p->sibling);
 }
 
 /*
@@ -736,12 +736,9 @@ static struct task_struct *find_new_reaper(struct task_struct *father)
 /*
 * Any that need to be release_task'd are put on the @dead list.
  */
-static void reparent_thread(struct task_struct *father, struct task_struct *p,
+static void reparent_leader(struct task_struct *father, struct task_struct *p,
                                struct list_head *dead)
 {
-       if (p->pdeath_signal)
-               group_send_sig_info(p->pdeath_signal, SEND_SIG_NOINFO, p);
-
        list_move_tail(&p->sibling, &p->real_parent->children);
 
        if (task_detached(p))
@@ -780,12 +777,18 @@ static void forget_original_parent(struct task_struct *father)
        reaper = find_new_reaper(father);
 
        list_for_each_entry_safe(p, n, &father->children, sibling) {
-               p->real_parent = reaper;
-               if (p->parent == father) {
-                       BUG_ON(task_ptrace(p));
-                       p->parent = p->real_parent;
-               }
-               reparent_thread(father, p, &dead_children);
+               struct task_struct *t = p;
+               do {
+                       t->real_parent = reaper;
+                       if (t->parent == father) {
+                               BUG_ON(task_ptrace(t));
+                               t->parent = t->real_parent;
+                       }
+                       if (t->pdeath_signal)
+                               group_send_sig_info(t->pdeath_signal,
+                                                   SEND_SIG_NOINFO, t);
+               } while_each_thread(p, t);
+               reparent_leader(father, p, &dead_children);
        }
        write_unlock_irq(&tasklist_lock);
 
@@ -1551,14 +1554,9 @@ static int do_wait_thread(struct wait_opts *wo, struct task_struct *tsk)
        struct task_struct *p;
 
        list_for_each_entry(p, &tsk->children, sibling) {
-               /*
-                * Do not consider detached threads.
-                */
-               if (!task_detached(p)) {
-                       int ret = wait_consider_task(wo, 0, p);
-                       if (ret)
-                               return ret;
-               }
+               int ret = wait_consider_task(wo, 0, p);
+               if (ret)
+                       return ret;
        }
 
        return 0;
index 202a0ba63d3c198a2c891536fc93b749abb955b2..5b2959b3ffc2c239244c25548f3d5c5506baf674 100644 (file)
@@ -1291,7 +1291,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        }
 
        if (likely(p->pid)) {
-               list_add_tail(&p->sibling, &p->real_parent->children);
                tracehook_finish_clone(p, clone_flags, trace);
 
                if (thread_group_leader(p)) {
@@ -1303,6 +1302,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
                        p->signal->tty = tty_kref_get(current->signal->tty);
                        attach_pid(p, PIDTYPE_PGID, task_pgrp(current));
                        attach_pid(p, PIDTYPE_SID, task_session(current));
+                       list_add_tail(&p->sibling, &p->real_parent->children);
                        list_add_tail_rcu(&p->tasks, &init_task.tasks);
                        __get_cpu_var(process_counts)++;
                }
index 433e9fcc1fc5197433a3b5f4efa0c08a467119d4..a9a93d9ee7a78e70068bca678826873376afd8a7 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/hardirq.h>
 #include <linux/elf.h>
 #include <linux/elfcore.h>
-#include <linux/utsrelease.h>
+#include <generated/utsrelease.h>
 #include <linux/utsname.h>
 #include <linux/numa.h>
 #include <linux/suspend.h>
index a65dc787a27bf6f28e4df980523820dacd1d14b3..e96b8ed1cb6aff09033114dd219157b84e8b23a3 100644 (file)
@@ -1910,9 +1910,7 @@ static void kmemleak_load_module(struct module *mod, Elf_Ehdr *hdr,
        unsigned int i;
 
        /* only scan the sections containing data */
-       kmemleak_scan_area(mod->module_core, (unsigned long)mod -
-                          (unsigned long)mod->module_core,
-                          sizeof(struct module), GFP_KERNEL);
+       kmemleak_scan_area(mod, sizeof(struct module), GFP_KERNEL);
 
        for (i = 1; i < hdr->e_shnum; i++) {
                if (!(sechdrs[i].sh_flags & SHF_ALLOC))
@@ -1921,8 +1919,7 @@ static void kmemleak_load_module(struct module *mod, Elf_Ehdr *hdr,
                    && strncmp(secstrings + sechdrs[i].sh_name, ".bss", 4) != 0)
                        continue;
 
-               kmemleak_scan_area(mod->module_core, sechdrs[i].sh_addr -
-                                  (unsigned long)mod->module_core,
+               kmemleak_scan_area((void *)sechdrs[i].sh_addr,
                                   sechdrs[i].sh_size, GFP_KERNEL);
        }
 }
@@ -2250,6 +2247,12 @@ static noinline struct module *load_module(void __user *umod,
                                         "_ftrace_events",
                                         sizeof(*mod->trace_events),
                                         &mod->num_trace_events);
+       /*
+        * This section contains pointers to allocated objects in the trace
+        * code and not scanning it leads to false positives.
+        */
+       kmemleak_scan_area(mod->trace_events, sizeof(*mod->trace_events) *
+                          mod->num_trace_events, GFP_KERNEL);
 #endif
 #ifdef CONFIG_FTRACE_MCOUNT_RECORD
        /* sechdrs[0].sh_size is always zero */
index 1ded8e7dd19b5fde61542b950ba3bb2d41f0690b..17463ca2e2292038027318222177979f83ee6bdb 100644 (file)
@@ -1412,7 +1412,7 @@ static LIST_HEAD(dump_list);
 
 /**
  * kmsg_dump_register - register a kernel log dumper.
- * @dump: pointer to the kmsg_dumper structure
+ * @dumper: pointer to the kmsg_dumper structure
  *
  * Adds a kernel log dumper to the system. The dump callback in the
  * structure will be called when the kernel oopses or panics and must be
@@ -1442,7 +1442,7 @@ EXPORT_SYMBOL_GPL(kmsg_dump_register);
 
 /**
  * kmsg_dump_unregister - unregister a kmsg dumper.
- * @dump: pointer to the kmsg_dumper structure
+ * @dumper: pointer to the kmsg_dumper structure
  *
  * Removes a dump device from the system. Returns zero on success and
  * %-EINVAL otherwise.
index 45e4bef0012a6747d6608cbb78ba0f700a29d7cb..6665761c006d0a67a5600cebb38d6856906ef9c5 100644 (file)
@@ -1131,7 +1131,7 @@ static struct ctl_table vm_table[] = {
                .data           = &sysctl_max_map_count,
                .maxlen         = sizeof(sysctl_max_map_count),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &zero,
        },
 #else
index 06ba26747d7e223b44ee67935b9ea33ff25752f8..8b9f20ab8eed9acc1b3d2529e377668951125723 100644 (file)
@@ -12,7 +12,7 @@
  *  Copyright (C) 2004 William Lee Irwin III
  */
 #include <linux/ring_buffer.h>
-#include <linux/utsrelease.h>
+#include <generated/utsrelease.h>
 #include <linux/stacktrace.h>
 #include <linux/writeback.h>
 #include <linux/kallsyms.h>
index 8cf9938dd147840d1dbc67166fa30fc22208bf78..25c3ed594c547966c1c291750d8adeb3b9e5674b 100644 (file)
@@ -360,6 +360,7 @@ config DEBUG_KMEMLEAK
        select DEBUG_FS if SYSFS
        select STACKTRACE if STACKTRACE_SUPPORT
        select KALLSYMS
+       select CRC32
        help
          Say Y here if you want to enable the memory leak
          detector. The memory allocation/freeing is traced in a way
index 735343fc857a7b3a6803a59e1ae3f33a7b5090e2..d4996cf46eb6ac0b2227a28ff26c734568b86f99 100644 (file)
@@ -1179,7 +1179,18 @@ qualifier:
  * %ps output the name of a text symbol without offset
  * %pF output the name of a function pointer with its offset
  * %pf output the name of a function pointer without its offset
- * %pR output the address range in a struct resource
+ * %pR output the address range in a struct resource with decoded flags
+ * %pr output the address range in a struct resource with raw flags
+ * %pM output a 6-byte MAC address with colons
+ * %pm output a 6-byte MAC address without colons
+ * %pI4 print an IPv4 address without leading zeros
+ * %pi4 print an IPv4 address with leading zeros
+ * %pI6 print an IPv6 address with colons
+ * %pi6 print an IPv6 address without colons
+ * %pI6c print an IPv6 address as specified by
+ *   http://www.ietf.org/id/draft-kawamura-ipv6-text-representation-03.txt
+ * %pU[bBlL] print a UUID/GUID in big or little endian using lower or upper
+ *   case.
  * %n is ignored
  *
  * The return value is the number of characters which would
index 13f33b3081ec2794afdae74d9071a88ec6aa9df3..5b069e4f5e485ac8f5906c4a0cad7dbdeef75f7e 100644 (file)
@@ -93,6 +93,7 @@
 #include <linux/nodemask.h>
 #include <linux/mm.h>
 #include <linux/workqueue.h>
+#include <linux/crc32.h>
 
 #include <asm/sections.h>
 #include <asm/processor.h>
 #define MSECS_MIN_AGE          5000    /* minimum object age for reporting */
 #define SECS_FIRST_SCAN                60      /* delay before the first scan */
 #define SECS_SCAN_WAIT         600     /* subsequent auto scanning delay */
-#define GRAY_LIST_PASSES       25      /* maximum number of gray list scans */
 #define MAX_SCAN_SIZE          4096    /* maximum size of a scanned block */
 
 #define BYTES_PER_POINTER      sizeof(void *)
 /* scanning area inside a memory block */
 struct kmemleak_scan_area {
        struct hlist_node node;
-       unsigned long offset;
-       size_t length;
+       unsigned long start;
+       size_t size;
 };
 
 #define KMEMLEAK_GREY  0
@@ -149,6 +149,8 @@ struct kmemleak_object {
        int min_count;
        /* the total number of pointers found pointing to this object */
        int count;
+       /* checksum for detecting modified objects */
+       u32 checksum;
        /* memory ranges to be scanned inside an object (empty for all) */
        struct hlist_head area_list;
        unsigned long trace[MAX_TRACE];
@@ -164,8 +166,6 @@ struct kmemleak_object {
 #define OBJECT_REPORTED                (1 << 1)
 /* flag set to not scan the object */
 #define OBJECT_NO_SCAN         (1 << 2)
-/* flag set on newly allocated objects */
-#define OBJECT_NEW             (1 << 3)
 
 /* number of bytes to print per line; must be 16 or 32 */
 #define HEX_ROW_SIZE           16
@@ -241,8 +241,6 @@ struct early_log {
        const void *ptr;                /* allocated/freed memory block */
        size_t size;                    /* memory block size */
        int min_count;                  /* minimum reference count */
-       unsigned long offset;           /* scan area offset */
-       size_t length;                  /* scan area length */
        unsigned long trace[MAX_TRACE]; /* stack trace */
        unsigned int trace_len;         /* stack trace length */
 };
@@ -323,11 +321,6 @@ static bool color_gray(const struct kmemleak_object *object)
                object->count >= object->min_count;
 }
 
-static bool color_black(const struct kmemleak_object *object)
-{
-       return object->min_count == KMEMLEAK_BLACK;
-}
-
 /*
  * Objects are considered unreferenced only if their color is white, they have
  * not be deleted and have a minimum age to avoid false positives caused by
@@ -335,7 +328,7 @@ static bool color_black(const struct kmemleak_object *object)
  */
 static bool unreferenced_object(struct kmemleak_object *object)
 {
-       return (object->flags & OBJECT_ALLOCATED) && color_white(object) &&
+       return (color_white(object) && object->flags & OBJECT_ALLOCATED) &&
                time_before_eq(object->jiffies + jiffies_min_age,
                               jiffies_last_scan);
 }
@@ -348,11 +341,13 @@ static void print_unreferenced(struct seq_file *seq,
                               struct kmemleak_object *object)
 {
        int i;
+       unsigned int msecs_age = jiffies_to_msecs(jiffies - object->jiffies);
 
        seq_printf(seq, "unreferenced object 0x%08lx (size %zu):\n",
                   object->pointer, object->size);
-       seq_printf(seq, "  comm \"%s\", pid %d, jiffies %lu\n",
-                  object->comm, object->pid, object->jiffies);
+       seq_printf(seq, "  comm \"%s\", pid %d, jiffies %lu (age %d.%03ds)\n",
+                  object->comm, object->pid, object->jiffies,
+                  msecs_age / 1000, msecs_age % 1000);
        hex_dump_object(seq, object);
        seq_printf(seq, "  backtrace:\n");
 
@@ -381,6 +376,7 @@ static void dump_object_info(struct kmemleak_object *object)
        pr_notice("  min_count = %d\n", object->min_count);
        pr_notice("  count = %d\n", object->count);
        pr_notice("  flags = 0x%lx\n", object->flags);
+       pr_notice("  checksum = %d\n", object->checksum);
        pr_notice("  backtrace:\n");
        print_stack_trace(&trace, 4);
 }
@@ -522,12 +518,13 @@ static struct kmemleak_object *create_object(unsigned long ptr, size_t size,
        INIT_HLIST_HEAD(&object->area_list);
        spin_lock_init(&object->lock);
        atomic_set(&object->use_count, 1);
-       object->flags = OBJECT_ALLOCATED | OBJECT_NEW;
+       object->flags = OBJECT_ALLOCATED;
        object->pointer = ptr;
        object->size = size;
        object->min_count = min_count;
-       object->count = -1;                     /* no color initially */
+       object->count = 0;                      /* white color initially */
        object->jiffies = jiffies;
+       object->checksum = 0;
 
        /* task information */
        if (in_irq()) {
@@ -720,14 +717,13 @@ static void make_black_object(unsigned long ptr)
  * Add a scanning area to the object. If at least one such area is added,
  * kmemleak will only scan these ranges rather than the whole memory block.
  */
-static void add_scan_area(unsigned long ptr, unsigned long offset,
-                         size_t length, gfp_t gfp)
+static void add_scan_area(unsigned long ptr, size_t size, gfp_t gfp)
 {
        unsigned long flags;
        struct kmemleak_object *object;
        struct kmemleak_scan_area *area;
 
-       object = find_and_get_object(ptr, 0);
+       object = find_and_get_object(ptr, 1);
        if (!object) {
                kmemleak_warn("Adding scan area to unknown object at 0x%08lx\n",
                              ptr);
@@ -741,7 +737,7 @@ static void add_scan_area(unsigned long ptr, unsigned long offset,
        }
 
        spin_lock_irqsave(&object->lock, flags);
-       if (offset + length > object->size) {
+       if (ptr + size > object->pointer + object->size) {
                kmemleak_warn("Scan area larger than object 0x%08lx\n", ptr);
                dump_object_info(object);
                kmem_cache_free(scan_area_cache, area);
@@ -749,8 +745,8 @@ static void add_scan_area(unsigned long ptr, unsigned long offset,
        }
 
        INIT_HLIST_NODE(&area->node);
-       area->offset = offset;
-       area->length = length;
+       area->start = ptr;
+       area->size = size;
 
        hlist_add_head(&area->node, &object->area_list);
 out_unlock:
@@ -786,7 +782,7 @@ static void object_no_scan(unsigned long ptr)
  * processed later once kmemleak is fully initialized.
  */
 static void __init log_early(int op_type, const void *ptr, size_t size,
-                            int min_count, unsigned long offset, size_t length)
+                            int min_count)
 {
        unsigned long flags;
        struct early_log *log;
@@ -808,8 +804,6 @@ static void __init log_early(int op_type, const void *ptr, size_t size,
        log->ptr = ptr;
        log->size = size;
        log->min_count = min_count;
-       log->offset = offset;
-       log->length = length;
        if (op_type == KMEMLEAK_ALLOC)
                log->trace_len = __save_stack_trace(log->trace);
        crt_early_log++;
@@ -858,7 +852,7 @@ void __ref kmemleak_alloc(const void *ptr, size_t size, int min_count,
        if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr))
                create_object((unsigned long)ptr, size, min_count, gfp);
        else if (atomic_read(&kmemleak_early_log))
-               log_early(KMEMLEAK_ALLOC, ptr, size, min_count, 0, 0);
+               log_early(KMEMLEAK_ALLOC, ptr, size, min_count);
 }
 EXPORT_SYMBOL_GPL(kmemleak_alloc);
 
@@ -873,7 +867,7 @@ void __ref kmemleak_free(const void *ptr)
        if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr))
                delete_object_full((unsigned long)ptr);
        else if (atomic_read(&kmemleak_early_log))
-               log_early(KMEMLEAK_FREE, ptr, 0, 0, 0, 0);
+               log_early(KMEMLEAK_FREE, ptr, 0, 0);
 }
 EXPORT_SYMBOL_GPL(kmemleak_free);
 
@@ -888,7 +882,7 @@ void __ref kmemleak_free_part(const void *ptr, size_t size)
        if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr))
                delete_object_part((unsigned long)ptr, size);
        else if (atomic_read(&kmemleak_early_log))
-               log_early(KMEMLEAK_FREE_PART, ptr, size, 0, 0, 0);
+               log_early(KMEMLEAK_FREE_PART, ptr, size, 0);
 }
 EXPORT_SYMBOL_GPL(kmemleak_free_part);
 
@@ -903,7 +897,7 @@ void __ref kmemleak_not_leak(const void *ptr)
        if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr))
                make_gray_object((unsigned long)ptr);
        else if (atomic_read(&kmemleak_early_log))
-               log_early(KMEMLEAK_NOT_LEAK, ptr, 0, 0, 0, 0);
+               log_early(KMEMLEAK_NOT_LEAK, ptr, 0, 0);
 }
 EXPORT_SYMBOL(kmemleak_not_leak);
 
@@ -919,22 +913,21 @@ void __ref kmemleak_ignore(const void *ptr)
        if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr))
                make_black_object((unsigned long)ptr);
        else if (atomic_read(&kmemleak_early_log))
-               log_early(KMEMLEAK_IGNORE, ptr, 0, 0, 0, 0);
+               log_early(KMEMLEAK_IGNORE, ptr, 0, 0);
 }
 EXPORT_SYMBOL(kmemleak_ignore);
 
 /*
  * Limit the range to be scanned in an allocated memory block.
  */
-void __ref kmemleak_scan_area(const void *ptr, unsigned long offset,
-                             size_t length, gfp_t gfp)
+void __ref kmemleak_scan_area(const void *ptr, size_t size, gfp_t gfp)
 {
        pr_debug("%s(0x%p)\n", __func__, ptr);
 
        if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr))
-               add_scan_area((unsigned long)ptr, offset, length, gfp);
+               add_scan_area((unsigned long)ptr, size, gfp);
        else if (atomic_read(&kmemleak_early_log))
-               log_early(KMEMLEAK_SCAN_AREA, ptr, 0, 0, offset, length);
+               log_early(KMEMLEAK_SCAN_AREA, ptr, size, 0);
 }
 EXPORT_SYMBOL(kmemleak_scan_area);
 
@@ -948,10 +941,24 @@ void __ref kmemleak_no_scan(const void *ptr)
        if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr))
                object_no_scan((unsigned long)ptr);
        else if (atomic_read(&kmemleak_early_log))
-               log_early(KMEMLEAK_NO_SCAN, ptr, 0, 0, 0, 0);
+               log_early(KMEMLEAK_NO_SCAN, ptr, 0, 0);
 }
 EXPORT_SYMBOL(kmemleak_no_scan);
 
+/*
+ * Update an object's checksum and return true if it was modified.
+ */
+static bool update_checksum(struct kmemleak_object *object)
+{
+       u32 old_csum = object->checksum;
+
+       if (!kmemcheck_is_obj_initialized(object->pointer, object->size))
+               return false;
+
+       object->checksum = crc32(0, (void *)object->pointer, object->size);
+       return object->checksum != old_csum;
+}
+
 /*
  * Memory scanning is a long process and it needs to be interruptable. This
  * function checks whether such interrupt condition occured.
@@ -1031,11 +1038,14 @@ static void scan_block(void *_start, void *_end,
                 * added to the gray_list.
                 */
                object->count++;
-               if (color_gray(object))
+               if (color_gray(object)) {
                        list_add_tail(&object->gray_list, &gray_list);
-               else
-                       put_object(object);
+                       spin_unlock_irqrestore(&object->lock, flags);
+                       continue;
+               }
+
                spin_unlock_irqrestore(&object->lock, flags);
+               put_object(object);
        }
 }
 
@@ -1075,13 +1085,46 @@ static void scan_object(struct kmemleak_object *object)
                }
        } else
                hlist_for_each_entry(area, elem, &object->area_list, node)
-                       scan_block((void *)(object->pointer + area->offset),
-                                  (void *)(object->pointer + area->offset
-                                           + area->length), object, 0);
+                       scan_block((void *)area->start,
+                                  (void *)(area->start + area->size),
+                                  object, 0);
 out:
        spin_unlock_irqrestore(&object->lock, flags);
 }
 
+/*
+ * Scan the objects already referenced (gray objects). More objects will be
+ * referenced and, if there are no memory leaks, all the objects are scanned.
+ */
+static void scan_gray_list(void)
+{
+       struct kmemleak_object *object, *tmp;
+
+       /*
+        * The list traversal is safe for both tail additions and removals
+        * from inside the loop. The kmemleak objects cannot be freed from
+        * outside the loop because their use_count was incremented.
+        */
+       object = list_entry(gray_list.next, typeof(*object), gray_list);
+       while (&object->gray_list != &gray_list) {
+               cond_resched();
+
+               /* may add new objects to the list */
+               if (!scan_should_stop())
+                       scan_object(object);
+
+               tmp = list_entry(object->gray_list.next, typeof(*object),
+                                gray_list);
+
+               /* remove the object from the list and release it */
+               list_del(&object->gray_list);
+               put_object(object);
+
+               object = tmp;
+       }
+       WARN_ON(!list_empty(&gray_list));
+}
+
 /*
  * Scan data sections and all the referenced memory blocks allocated via the
  * kernel's standard allocators. This function must be called with the
@@ -1090,10 +1133,9 @@ out:
 static void kmemleak_scan(void)
 {
        unsigned long flags;
-       struct kmemleak_object *object, *tmp;
+       struct kmemleak_object *object;
        int i;
        int new_leaks = 0;
-       int gray_list_pass = 0;
 
        jiffies_last_scan = jiffies;
 
@@ -1114,7 +1156,6 @@ static void kmemleak_scan(void)
 #endif
                /* reset the reference count (whiten the object) */
                object->count = 0;
-               object->flags &= ~OBJECT_NEW;
                if (color_gray(object) && get_object(object))
                        list_add_tail(&object->gray_list, &gray_list);
 
@@ -1172,62 +1213,36 @@ static void kmemleak_scan(void)
 
        /*
         * Scan the objects already referenced from the sections scanned
-        * above. More objects will be referenced and, if there are no memory
-        * leaks, all the objects will be scanned. The list traversal is safe
-        * for both tail additions and removals from inside the loop. The
-        * kmemleak objects cannot be freed from outside the loop because their
-        * use_count was increased.
+        * above.
         */
-repeat:
-       object = list_entry(gray_list.next, typeof(*object), gray_list);
-       while (&object->gray_list != &gray_list) {
-               cond_resched();
-
-               /* may add new objects to the list */
-               if (!scan_should_stop())
-                       scan_object(object);
-
-               tmp = list_entry(object->gray_list.next, typeof(*object),
-                                gray_list);
-
-               /* remove the object from the list and release it */
-               list_del(&object->gray_list);
-               put_object(object);
-
-               object = tmp;
-       }
-
-       if (scan_should_stop() || ++gray_list_pass >= GRAY_LIST_PASSES)
-               goto scan_end;
+       scan_gray_list();
 
        /*
-        * Check for new objects allocated during this scanning and add them
-        * to the gray list.
+        * Check for new or unreferenced objects modified since the previous
+        * scan and color them gray until the next scan.
         */
        rcu_read_lock();
        list_for_each_entry_rcu(object, &object_list, object_list) {
                spin_lock_irqsave(&object->lock, flags);
-               if ((object->flags & OBJECT_NEW) && !color_black(object) &&
-                   get_object(object)) {
-                       object->flags &= ~OBJECT_NEW;
+               if (color_white(object) && (object->flags & OBJECT_ALLOCATED)
+                   && update_checksum(object) && get_object(object)) {
+                       /* color it gray temporarily */
+                       object->count = object->min_count;
                        list_add_tail(&object->gray_list, &gray_list);
                }
                spin_unlock_irqrestore(&object->lock, flags);
        }
        rcu_read_unlock();
 
-       if (!list_empty(&gray_list))
-               goto repeat;
-
-scan_end:
-       WARN_ON(!list_empty(&gray_list));
+       /*
+        * Re-scan the gray list for modified unreferenced objects.
+        */
+       scan_gray_list();
 
        /*
-        * If scanning was stopped or new objects were being allocated at a
-        * higher rate than gray list scanning, do not report any new
-        * unreferenced objects.
+        * If scanning was stopped do not report any new unreferenced objects.
         */
-       if (scan_should_stop() || gray_list_pass >= GRAY_LIST_PASSES)
+       if (scan_should_stop())
                return;
 
        /*
@@ -1642,8 +1657,7 @@ void __init kmemleak_init(void)
                        kmemleak_ignore(log->ptr);
                        break;
                case KMEMLEAK_SCAN_AREA:
-                       kmemleak_scan_area(log->ptr, log->offset, log->length,
-                                          GFP_KERNEL);
+                       kmemleak_scan_area(log->ptr, log->size, GFP_KERNEL);
                        break;
                case KMEMLEAK_NO_SCAN:
                        kmemleak_no_scan(log->ptr);
index aa1aa23452355067af9d62179cd41d62c64e68fc..033bc135a41f3885cae863ca0c9f5185d6c5d665 100644 (file)
@@ -547,5 +547,17 @@ page_cache_async_readahead(struct address_space *mapping,
 
        /* do read-ahead */
        ondemand_readahead(mapping, ra, filp, true, offset, req_size);
+
+#ifdef CONFIG_BLOCK
+       /*
+        * Normally the current page is !uptodate and lock_page() will be
+        * immediately called to implicitly unplug the device. However this
+        * is not always true for RAID conifgurations, where data arrives
+        * not strictly in their submission order. In this case we need to
+        * explicitly kick off the IO.
+        */
+       if (PageUptodate(page))
+               blk_run_backing_dev(mapping->backing_dev_info, NULL);
+#endif
 }
 EXPORT_SYMBOL_GPL(page_cache_async_readahead);
index f8485062f3badd858fce717f2a0178512504ef05..eef4ebea51581f9aa8a6d2244f8ce5fa57f99c22 100644 (file)
@@ -1830,6 +1830,8 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
                        iput(inode);
                        return error;
                }
+#else
+               error = 0;
 #endif
                if (dir->i_mode & S_ISGID) {
                        inode->i_gid = dir->i_gid;
index 3f4822938f4605f4e6e1cf55f996f812332cd4a6..e17cc2c337b8b6d2794a1a92e0117a8dec16bf0a 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -2275,9 +2275,11 @@ kmem_cache_create (const char *name, size_t size, size_t align,
        /*
         * Determine if the slab management is 'on' or 'off' slab.
         * (bootstrapping cannot cope with offslab caches so don't do
-        * it too early on.)
+        * it too early on. Always use on-slab management when
+        * SLAB_NOLEAKTRACE to avoid recursive calls into kmemleak)
         */
-       if ((size >= (PAGE_SIZE >> 3)) && !slab_early_init)
+       if ((size >= (PAGE_SIZE >> 3)) && !slab_early_init &&
+           !(flags & SLAB_NOLEAKTRACE))
                /*
                 * Size is large, assume best to place the slab management obj
                 * off-slab (should allow better packing of objs).
@@ -2596,8 +2598,8 @@ static struct slab *alloc_slabmgmt(struct kmem_cache *cachep, void *objp,
                 * kmemleak does not treat the ->s_mem pointer as a reference
                 * to the object. Otherwise we will not report the leak.
                 */
-               kmemleak_scan_area(slabp, offsetof(struct slab, list),
-                                  sizeof(struct list_head), local_flags);
+               kmemleak_scan_area(&slabp->list, sizeof(struct list_head),
+                                  local_flags);
                if (!slabp)
                        return NULL;
        } else {
index dbfdfa96d29b850c2f9a198cd494069772dbafc6..769c386bd4288758635acde6ca77c401a49c61a8 100644 (file)
@@ -312,18 +312,6 @@ static struct file_system_type sock_fs_type = {
        .kill_sb =      kill_anon_super,
 };
 
-static int sockfs_delete_dentry(struct dentry *dentry)
-{
-       /*
-        * At creation time, we pretended this dentry was hashed
-        * (by clearing DCACHE_UNHASHED bit in d_flags)
-        * At delete time, we restore the truth : not hashed.
-        * (so that dput() can proceed correctly)
-        */
-       dentry->d_flags |= DCACHE_UNHASHED;
-       return 0;
-}
-
 /*
  * sockfs_dname() is called from d_path().
  */
@@ -334,7 +322,6 @@ static char *sockfs_dname(struct dentry *dentry, char *buffer, int buflen)
 }
 
 static const struct dentry_operations sockfs_dentry_operations = {
-       .d_delete = sockfs_delete_dentry,
        .d_dname  = sockfs_dname,
 };
 
@@ -374,12 +361,6 @@ static int sock_alloc_file(struct socket *sock, struct file **f, int flags)
        path.mnt = mntget(sock_mnt);
 
        path.dentry->d_op = &sockfs_dentry_operations;
-       /*
-        * We dont want to push this dentry into global dentry hash table.
-        * We pretend dentry is already hashed, by unsetting DCACHE_UNHASHED
-        * This permits a working /proc/$pid/fd/XXX on sockets
-        */
-       path.dentry->d_flags &= ~DCACHE_UNHASHED;
        d_instantiate(path.dentry, SOCK_INODE(sock));
        SOCK_INODE(sock)->i_fop = &socket_file_ops;
 
index c67e73ecd5beac46e7212922737479568a95f919..ed2773edfe71bae99adc0a7b64a454912dfd4477 100644 (file)
@@ -149,6 +149,12 @@ ld-option = $(call try-run,\
 # $(Q)$(MAKE) $(build)=dir
 build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj
 
+###
+# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.modbuiltin obj=
+# Usage:
+# $(Q)$(MAKE) $(modbuiltin)=dir
+modbuiltin := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.modbuiltin obj
+
 # Prefix -I with $(srctree) if it is not an absolute path.
 # skip if -I has no parameter
 addtree = $(if $(patsubst -I%,%,$(1)), \
index 224d85e72ef13a93458895cffdbdf32f22747705..cd815ac2a50b41da74f32d950b7e759e60f28605 100644 (file)
@@ -213,7 +213,7 @@ cmd_gzip = (cat $(filter-out FORCE,$^) | gzip -f -9 > $@) || \
 
 # Bzip2 and LZMA do not include size in file... so we have to fake that;
 # append the size as a 32-bit littleendian number as gzip does.
-size_append = /bin/echo -ne $(shell                                    \
+size_append = printf $(shell                                           \
 dec_size=0;                                                            \
 for F in $1; do                                                                \
        fsize=$$(stat -c "%s" $$F);                                     \
diff --git a/scripts/Makefile.modbuiltin b/scripts/Makefile.modbuiltin
new file mode 100644 (file)
index 0000000..102a276
--- /dev/null
@@ -0,0 +1,55 @@
+# ==========================================================================
+# Generating modules.builtin
+# ==========================================================================
+
+src := $(obj)
+
+PHONY := __modbuiltin
+__modbuiltin:
+
+-include include/config/auto.conf
+# tristate.conf sets tristate variables to uppercase 'Y' or 'M'
+# That way, we get the list of built-in modules in obj-Y
+-include include/config/tristate.conf
+
+include scripts/Kbuild.include
+
+# The filename Kbuild has precedence over Makefile
+kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
+kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
+include $(kbuild-file)
+
+include scripts/Makefile.lib
+__subdir-Y     := $(patsubst %/,%,$(filter %/, $(obj-Y)))
+subdir-Y       += $(__subdir-Y)
+subdir-ym      := $(sort $(subdir-y) $(subdir-Y) $(subdir-m))
+subdir-ym      := $(addprefix $(obj)/,$(subdir-ym))
+obj-Y          := $(addprefix $(obj)/,$(obj-Y))
+
+modbuiltin-subdirs := $(patsubst %,%/modules.builtin, $(subdir-ym))
+modbuiltin-mods    := $(filter %.ko, $(obj-Y:.o=.ko))
+modbuiltin-target  := $(obj)/modules.builtin
+
+__modbuiltin: $(modbuiltin-target) $(subdir-ym)
+       @:
+
+$(modbuiltin-target): $(subdir-ym) FORCE
+       $(Q)(for m in $(modbuiltin-mods); do echo kernel/$$m; done;     \
+       cat /dev/null $(modbuiltin-subdirs)) > $@
+
+PHONY += FORCE
+
+FORCE:
+
+# Descending
+# ---------------------------------------------------------------------------
+
+PHONY += $(subdir-ym)
+$(subdir-ym):
+       $(Q)$(MAKE) $(modbuiltin)=$@
+
+
+# Declare the contents of the .PHONY variable as phony.  We keep that
+# information in a variable se we can use it in if_changed and friends.
+
+.PHONY: $(PHONY)
index 6bf21f83837dff5a42893d57dde41e8d225948e4..ea26b23de082b03cfa99483c52118f962a019a0e 100644 (file)
  * tells make when to remake a file.
  *
  * To use this list as-is however has the drawback that virtually
- * every file in the kernel includes <linux/autoconf.h>.
+ * every file in the kernel includes autoconf.h.
  *
- * If the user re-runs make *config, linux/autoconf.h will be
+ * If the user re-runs make *config, autoconf.h will be
  * regenerated.  make notices that and will rebuild every file which
  * includes autoconf.h, i.e. basically all files. This is extremely
  * annoying if the user just changed CONFIG_HIS_DRIVER from n to m.
  *
  * So we play the same trick that "mkdep" played before. We replace
- * the dependency on linux/autoconf.h by a dependency on every config
+ * the dependency on autoconf.h by a dependency on every config
  * option which is mentioned in any of the listed prequisites.
  *
  * kconfig populates a tree in include/config/ with an empty file
@@ -73,7 +73,7 @@
  *   cmd_<target> = <cmdline>
  *
  * and then basically copies the .<target>.d file to stdout, in the
- * process filtering out the dependency on linux/autoconf.h and adding
+ * process filtering out the dependency on autoconf.h and adding
  * dependencies on include/config/my/option.h for every
  * CONFIG_MY_OPTION encountered in any of the prequisites.
  *
@@ -324,7 +324,7 @@ static void parse_dep_file(void *map, size_t len)
                        p++;
                }
                memcpy(s, m, p-m); s[p-m] = 0;
-               if (strrcmp(s, "include/linux/autoconf.h") &&
+               if (strrcmp(s, "include/generated/autoconf.h") &&
                    strrcmp(s, "arch/um/include/uml-config.h") &&
                    strrcmp(s, ".ver")) {
                        printf("  %s \\\n", s);
index 287467a2e8c7afe3334105e6adf61afbe75a87cb..8060e06798b32990c58bba036161f01a74f3b789 100644 (file)
@@ -1,4 +1,4 @@
-/* ANSI-C code produced by gperf version 3.0.3 */
+/* ANSI-C code produced by gperf version 3.0.4 */
 /* Command-line: gperf -L ANSI-C -a -C -E -g -H is_reserved_hash -k '1,3,$' -N is_reserved_word -p -t scripts/genksyms/keywords.gperf  */
 
 #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
@@ -34,7 +34,7 @@ struct resword;
 static const struct resword *is_reserved_word(register const char *str, register unsigned int len);
 #line 5 "scripts/genksyms/keywords.gperf"
 struct resword { const char *name; int token; };
-/* maximum key range = 62, duplicates = 0 */
+/* maximum key range = 64, duplicates = 0 */
 
 #ifdef __GNUC__
 __inline
@@ -48,39 +48,39 @@ is_reserved_hash (register const char *str, register unsigned int len)
 {
   static const unsigned char asso_values[] =
     {
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65,  5,
-      65, 65, 65, 65, 65, 65, 35, 65, 65, 65,
-       0, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65,  0, 65,  0, 65,  5,
-      20, 15, 10, 30, 65, 15, 65, 65, 20,  0,
-      10, 35, 20, 65, 10,  5,  0, 10,  5, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67,  0,
+      67, 67, 67, 67, 67, 67, 15, 67, 67, 67,
+       0, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67,  0, 67,  0, 67,  5,
+      25, 20, 15, 30, 67, 15, 67, 67, 10,  0,
+      10, 40, 20, 67, 10,  5,  0, 10, 15, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67
     };
   return len + asso_values[(unsigned char)str[2]] + asso_values[(unsigned char)str[0]] + asso_values[(unsigned char)str[len - 1]];
 }
 
 #ifdef __GNUC__
 __inline
-#ifdef __GNUC_STDC_INLINE__
+#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
 __attribute__ ((__gnu_inline__))
 #endif
 #endif
@@ -89,116 +89,119 @@ is_reserved_word (register const char *str, register unsigned int len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 43,
+      TOTAL_KEYWORDS = 45,
       MIN_WORD_LENGTH = 3,
       MAX_WORD_LENGTH = 24,
       MIN_HASH_VALUE = 3,
-      MAX_HASH_VALUE = 64
+      MAX_HASH_VALUE = 66
     };
 
   static const struct resword wordlist[] =
     {
       {""}, {""}, {""},
-#line 28 "scripts/genksyms/keywords.gperf"
+#line 30 "scripts/genksyms/keywords.gperf"
       {"asm", ASM_KEYW},
       {""},
-#line 10 "scripts/genksyms/keywords.gperf"
+#line 12 "scripts/genksyms/keywords.gperf"
       {"__asm", ASM_KEYW},
       {""},
-#line 11 "scripts/genksyms/keywords.gperf"
+#line 13 "scripts/genksyms/keywords.gperf"
       {"__asm__", ASM_KEYW},
       {""}, {""},
-#line 54 "scripts/genksyms/keywords.gperf"
+#line 56 "scripts/genksyms/keywords.gperf"
       {"__typeof__", TYPEOF_KEYW},
       {""},
-#line 14 "scripts/genksyms/keywords.gperf"
+#line 16 "scripts/genksyms/keywords.gperf"
       {"__const", CONST_KEYW},
-#line 13 "scripts/genksyms/keywords.gperf"
-      {"__attribute__", ATTRIBUTE_KEYW},
 #line 15 "scripts/genksyms/keywords.gperf"
+      {"__attribute__", ATTRIBUTE_KEYW},
+#line 17 "scripts/genksyms/keywords.gperf"
       {"__const__", CONST_KEYW},
-#line 20 "scripts/genksyms/keywords.gperf"
+#line 22 "scripts/genksyms/keywords.gperf"
       {"__signed__", SIGNED_KEYW},
-#line 46 "scripts/genksyms/keywords.gperf"
+#line 48 "scripts/genksyms/keywords.gperf"
       {"static", STATIC_KEYW},
-#line 22 "scripts/genksyms/keywords.gperf"
-      {"__volatile__", VOLATILE_KEYW},
-#line 41 "scripts/genksyms/keywords.gperf"
+      {""},
+#line 43 "scripts/genksyms/keywords.gperf"
       {"int", INT_KEYW},
-#line 34 "scripts/genksyms/keywords.gperf"
+#line 36 "scripts/genksyms/keywords.gperf"
       {"char", CHAR_KEYW},
-#line 35 "scripts/genksyms/keywords.gperf"
+#line 37 "scripts/genksyms/keywords.gperf"
       {"const", CONST_KEYW},
-#line 47 "scripts/genksyms/keywords.gperf"
+#line 49 "scripts/genksyms/keywords.gperf"
       {"struct", STRUCT_KEYW},
-#line 26 "scripts/genksyms/keywords.gperf"
+#line 28 "scripts/genksyms/keywords.gperf"
       {"__restrict__", RESTRICT_KEYW},
-#line 27 "scripts/genksyms/keywords.gperf"
+#line 29 "scripts/genksyms/keywords.gperf"
       {"restrict", RESTRICT_KEYW},
-#line 25 "scripts/genksyms/keywords.gperf"
-      {"_restrict", RESTRICT_KEYW},
-#line 18 "scripts/genksyms/keywords.gperf"
+#line 9 "scripts/genksyms/keywords.gperf"
+      {"EXPORT_SYMBOL_GPL_FUTURE", EXPORT_SYMBOL_KEYW},
+#line 20 "scripts/genksyms/keywords.gperf"
       {"__inline__", INLINE_KEYW},
-#line 12 "scripts/genksyms/keywords.gperf"
-      {"__attribute", ATTRIBUTE_KEYW},
       {""},
-#line 16 "scripts/genksyms/keywords.gperf"
+#line 24 "scripts/genksyms/keywords.gperf"
+      {"__volatile__", VOLATILE_KEYW},
+#line 7 "scripts/genksyms/keywords.gperf"
+      {"EXPORT_SYMBOL", EXPORT_SYMBOL_KEYW},
+#line 27 "scripts/genksyms/keywords.gperf"
+      {"_restrict", RESTRICT_KEYW},
+      {""},
+#line 14 "scripts/genksyms/keywords.gperf"
+      {"__attribute", ATTRIBUTE_KEYW},
+#line 8 "scripts/genksyms/keywords.gperf"
+      {"EXPORT_SYMBOL_GPL", EXPORT_SYMBOL_KEYW},
+#line 18 "scripts/genksyms/keywords.gperf"
       {"__extension__", EXTENSION_KEYW},
-#line 37 "scripts/genksyms/keywords.gperf"
+#line 39 "scripts/genksyms/keywords.gperf"
       {"enum", ENUM_KEYW},
-#line 21 "scripts/genksyms/keywords.gperf"
-      {"__volatile", VOLATILE_KEYW},
-#line 38 "scripts/genksyms/keywords.gperf"
+#line 10 "scripts/genksyms/keywords.gperf"
+      {"EXPORT_UNUSED_SYMBOL", EXPORT_SYMBOL_KEYW},
+#line 40 "scripts/genksyms/keywords.gperf"
       {"extern", EXTERN_KEYW},
       {""},
-#line 19 "scripts/genksyms/keywords.gperf"
+#line 21 "scripts/genksyms/keywords.gperf"
       {"__signed", SIGNED_KEYW},
-#line 9 "scripts/genksyms/keywords.gperf"
-      {"EXPORT_SYMBOL_GPL_FUTURE", EXPORT_SYMBOL_KEYW},
-      {""},
-#line 53 "scripts/genksyms/keywords.gperf"
+#line 11 "scripts/genksyms/keywords.gperf"
+      {"EXPORT_UNUSED_SYMBOL_GPL", EXPORT_SYMBOL_KEYW},
+#line 51 "scripts/genksyms/keywords.gperf"
+      {"union", UNION_KEYW},
+#line 55 "scripts/genksyms/keywords.gperf"
       {"typeof", TYPEOF_KEYW},
-#line 48 "scripts/genksyms/keywords.gperf"
+#line 50 "scripts/genksyms/keywords.gperf"
       {"typedef", TYPEDEF_KEYW},
-#line 17 "scripts/genksyms/keywords.gperf"
+#line 19 "scripts/genksyms/keywords.gperf"
       {"__inline", INLINE_KEYW},
-#line 33 "scripts/genksyms/keywords.gperf"
+#line 35 "scripts/genksyms/keywords.gperf"
       {"auto", AUTO_KEYW},
-#line 49 "scripts/genksyms/keywords.gperf"
-      {"union", UNION_KEYW},
-      {""}, {""},
-#line 50 "scripts/genksyms/keywords.gperf"
-      {"unsigned", UNSIGNED_KEYW},
-#line 51 "scripts/genksyms/keywords.gperf"
-      {"void", VOID_KEYW},
-#line 44 "scripts/genksyms/keywords.gperf"
-      {"short", SHORT_KEYW},
+#line 23 "scripts/genksyms/keywords.gperf"
+      {"__volatile", VOLATILE_KEYW},
       {""}, {""},
 #line 52 "scripts/genksyms/keywords.gperf"
-      {"volatile", VOLATILE_KEYW},
-      {""},
-#line 39 "scripts/genksyms/keywords.gperf"
-      {"float", FLOAT_KEYW},
-#line 36 "scripts/genksyms/keywords.gperf"
-      {"double", DOUBLE_KEYW},
+      {"unsigned", UNSIGNED_KEYW},
       {""},
-#line 7 "scripts/genksyms/keywords.gperf"
-      {"EXPORT_SYMBOL", EXPORT_SYMBOL_KEYW},
-      {""}, {""},
-#line 40 "scripts/genksyms/keywords.gperf"
+#line 46 "scripts/genksyms/keywords.gperf"
+      {"short", SHORT_KEYW},
+#line 42 "scripts/genksyms/keywords.gperf"
       {"inline", INLINE_KEYW},
-#line 8 "scripts/genksyms/keywords.gperf"
-      {"EXPORT_SYMBOL_GPL", EXPORT_SYMBOL_KEYW},
-#line 43 "scripts/genksyms/keywords.gperf"
-      {"register", REGISTER_KEYW},
       {""},
-#line 24 "scripts/genksyms/keywords.gperf"
+#line 54 "scripts/genksyms/keywords.gperf"
+      {"volatile", VOLATILE_KEYW},
+#line 44 "scripts/genksyms/keywords.gperf"
+      {"long", LONG_KEYW},
+#line 26 "scripts/genksyms/keywords.gperf"
       {"_Bool", BOOL_KEYW},
-#line 45 "scripts/genksyms/keywords.gperf"
-      {"signed", SIGNED_KEYW},
       {""}, {""},
-#line 42 "scripts/genksyms/keywords.gperf"
-      {"long", LONG_KEYW}
+#line 45 "scripts/genksyms/keywords.gperf"
+      {"register", REGISTER_KEYW},
+#line 53 "scripts/genksyms/keywords.gperf"
+      {"void", VOID_KEYW},
+#line 41 "scripts/genksyms/keywords.gperf"
+      {"float", FLOAT_KEYW},
+#line 38 "scripts/genksyms/keywords.gperf"
+      {"double", DOUBLE_KEYW},
+      {""}, {""}, {""}, {""},
+#line 47 "scripts/genksyms/keywords.gperf"
+      {"signed", SIGNED_KEYW}
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
index 8fe977a4d57b7ada0480074e91ed01b298c61dc2..e6349acb6f2f36994071acd1c30889f1e4a2d583 100644 (file)
@@ -7,6 +7,8 @@ struct resword { const char *name; int token; }
 EXPORT_SYMBOL, EXPORT_SYMBOL_KEYW
 EXPORT_SYMBOL_GPL, EXPORT_SYMBOL_KEYW
 EXPORT_SYMBOL_GPL_FUTURE, EXPORT_SYMBOL_KEYW
+EXPORT_UNUSED_SYMBOL, EXPORT_SYMBOL_KEYW
+EXPORT_UNUSED_SYMBOL_GPL, EXPORT_SYMBOL_KEYW
 __asm, ASM_KEYW
 __asm__, ASM_KEYW
 __attribute, ATTRIBUTE_KEYW
index 0308ecc10d5b133858a15bf9f46b3cb2f424d4d6..1ddcdd38d97ffb7c599c9ec940202ee18de55e64 100755 (executable)
@@ -8,8 +8,6 @@ do_command()
 {
        if [ -f ${srctree}/arch/$2/include/asm/Kbuild ]; then
                make ARCH=$2 KBUILD_HEADERS=$1 headers_$1
-       elif [ -f ${srctree}/include/asm-$2/Kbuild ]; then
-               make ARCH=$2 KBUILD_HEADERS=$1 headers_$1
        else
                printf "Ignoring arch: %s\n" ${arch}
        fi
index 80599e3a7994107cfa06f04e6a70c2d3ff2acbda..999e8a7d5bf7e1be6aa473bc865c4a4d2df36d75 100644 (file)
@@ -27,6 +27,7 @@ oldconfig: $(obj)/conf
        $< -o $(Kconfig)
 
 silentoldconfig: $(obj)/conf
+       $(Q)mkdir -p include/generated
        $< -s $(Kconfig)
 
 localmodconfig: $(obj)/streamline_config.pl $(obj)/conf
index b55e72ff2fc676d4ae36ebe9028c6dee5b44d715..c4dec80cfd8e14a94792af807da0e9705256257d 100644 (file)
@@ -677,7 +677,7 @@ int conf_write_autoconf(void)
        struct symbol *sym;
        const char *str;
        const char *name;
-       FILE *out, *out_h;
+       FILE *out, *tristate, *out_h;
        time_t now;
        int i, l;
 
@@ -692,9 +692,16 @@ int conf_write_autoconf(void)
        if (!out)
                return 1;
 
+       tristate = fopen(".tmpconfig_tristate", "w");
+       if (!tristate) {
+               fclose(out);
+               return 1;
+       }
+
        out_h = fopen(".tmpconfig.h", "w");
        if (!out_h) {
                fclose(out);
+               fclose(tristate);
                return 1;
        }
 
@@ -707,6 +714,9 @@ int conf_write_autoconf(void)
                     "# %s"
                     "#\n",
                     sym_get_string_value(sym), ctime(&now));
+       fprintf(tristate, "#\n"
+                         "# Automatically generated - do not edit\n"
+                         "\n");
        fprintf(out_h, "/*\n"
                       " * Automatically generated C config: don't edit\n"
                       " * Linux kernel version: %s\n"
@@ -727,10 +737,14 @@ int conf_write_autoconf(void)
                                break;
                        case mod:
                                fprintf(out, "CONFIG_%s=m\n", sym->name);
+                               fprintf(tristate, "CONFIG_%s=M\n", sym->name);
                                fprintf(out_h, "#define CONFIG_%s_MODULE 1\n", sym->name);
                                break;
                        case yes:
                                fprintf(out, "CONFIG_%s=y\n", sym->name);
+                               if (sym->type == S_TRISTATE)
+                                       fprintf(tristate, "CONFIG_%s=Y\n",
+                                                       sym->name);
                                fprintf(out_h, "#define CONFIG_%s 1\n", sym->name);
                                break;
                        }
@@ -772,13 +786,19 @@ int conf_write_autoconf(void)
                }
        }
        fclose(out);
+       fclose(tristate);
        fclose(out_h);
 
        name = getenv("KCONFIG_AUTOHEADER");
        if (!name)
-               name = "include/linux/autoconf.h";
+               name = "include/generated/autoconf.h";
        if (rename(".tmpconfig.h", name))
                return 1;
+       name = getenv("KCONFIG_TRISTATE");
+       if (!name)
+               name = "include/config/tristate.conf";
+       if (rename(".tmpconfig_tristate", name))
+               return 1;
        name = conf_get_autoconfig_name();
        /*
         * This must be the last step, kbuild has a dependency on auto.conf
index bce3d0fe6fbd8d3f51918098b16c2da45456987e..23dbad80cce9e16ce885d61163a5f79c1ca2b981 100755 (executable)
@@ -14,7 +14,7 @@ vecho() { [ "${quiet}" = "silent_" ] || echo "$@" ; }
 # So "sudo make install" won't change the "compiled by <user>"
 # do "compiled by root"
 
-if [ -r $TARGET -a ! -O include/linux/autoconf.h ]; then
+if [ -r $TARGET -a ! -O include/generated/autoconf.h ]; then
   vecho "  SKIPPED $TARGET"
   exit 0
 fi
index 6c4ffc767b91a16bfdc1e1aef9885bee66be3736..20923613467cf376db195e17a9df754e934ab470 100644 (file)
@@ -15,7 +15,7 @@
 #include <stdio.h>
 #include <ctype.h>
 #include "modpost.h"
-#include "../../include/linux/autoconf.h"
+#include "../../include/generated/autoconf.h"
 #include "../../include/linux/license.h"
 
 /* Some toolchains use a `_' prefix for all user symbols. */
index f67cc885c807f0649b508a534d19566dd4de9abe..62fcc3a7f4d35f4ae29c959baac684f154c9aafd 100644 (file)
@@ -77,9 +77,27 @@ clean-files += $(objtree)/binkernel.spec
 
 # Deb target
 # ---------------------------------------------------------------------------
+quiet_cmd_builddeb = BUILDDEB
+      cmd_builddeb = set -e; \
+       test `id -u` = 0 || \
+       test -n "$(KBUILD_PKG_ROOTCMD)" || { \
+               which fakeroot >/dev/null 2>&1 && \
+               KBUILD_PKG_ROOTCMD="fakeroot -u"; \
+       } || { \
+               echo; \
+               echo "builddeb must be run as root (or using fakeroot)."; \
+               echo "KBUILD_PKG_ROOTCMD is unset and fakeroot not found."; \
+               echo "Try setting KBUILD_PKG_ROOTCMD to a command to acquire"; \
+               echo "root privileges (e.g., 'fakeroot -u' or 'sudo')."; \
+               false; \
+       } && \
+       \
+       $$KBUILD_PKG_ROOTCMD $(CONFIG_SHELL) \
+               $(srctree)/scripts/package/builddeb
+
 deb-pkg: FORCE
        $(MAKE) KBUILD_SRC=
-       $(CONFIG_SHELL) $(srctree)/scripts/package/builddeb
+       $(call cmd,builddeb)
 
 clean-dirs += $(objtree)/debian/
 
index b1fd48db1640d50320de63ede7e3a7e699794408..51b2aa0acb82db959b67ca1170439c436ae0ab3b 100644 (file)
@@ -101,7 +101,11 @@ esac
 #
 (
        cd "${tmpdir}"
-       tar cf - . | ${compress} > "${tarball}${file_ext}"
+       opts=
+       if tar --owner=root --group=root --help >/dev/null 2>&1; then
+               opts="--owner=root --group=root"
+       fi
+       tar cf - . $opts | ${compress} > "${tarball}${file_ext}"
 )
 
 echo "Tarball successfully created in ${tarball}${file_ext}"
index d52f7a01557c1b28cf3155a640c175ce613558aa..1a0c44d7c4a75308ca6addf915a6951cf30a603d 100755 (executable)
@@ -89,7 +89,13 @@ all_defconfigs()
 
 docscope()
 {
-       (echo \-k; echo \-q; all_sources) > cscope.files
+       # always use absolute paths for cscope, as recommended by cscope
+       # upstream
+       case "$tree" in
+               /*) ;;
+               *) tree=$PWD/$tree ;;
+       esac
+       (cd /; echo \-k; echo \-q; all_sources) > cscope.files
        cscope -b -f cscope.out
 }
 
index 30d459fb0709a70a97d6ddd5f8d635e8bb467490..44d39785e50da4a67bdde65a86e55b6a795e55b3 100644 (file)
@@ -1,13 +1,5 @@
 /*
- * Copyright (c) 2002 - 2005 Tony Finch <dot@dotat.at>.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by Dave Yost.
- * It was rewritten to support ANSI C by Tony Finch. The original version of
- * unifdef carried the following copyright notice. None of its code remains
- * in this version (though some of the names remain).
- *
- * Copyright (c) 1985, 1993
- *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 2002 - 2009 Tony Finch <dot@dotat.at>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * SUCH DAMAGE.
  */
 
-#include <sys/cdefs.h>
+/*
+ * This code was derived from software contributed to Berkeley by Dave Yost.
+ * It was rewritten to support ANSI C by Tony Finch. The original version
+ * of unifdef carried the 4-clause BSD copyright licence. None of its code
+ * remains in this version (though some of the names remain) so it now
+ * carries a more liberal licence.
+ *
+ * The latest version is available from http://dotat.at/prog/unifdef
+ */
 
-#ifndef lint
-#if 0
-static const char copyright[] =
-"@(#) Copyright (c) 1985, 1993\n\
-       The Regents of the University of California.  All rights reserved.\n";
-#endif
-#ifdef __IDSTRING
-__IDSTRING(Berkeley, "@(#)unifdef.c    8.1 (Berkeley) 6/6/93");
-__IDSTRING(NetBSD, "$NetBSD: unifdef.c,v 1.8 2000/07/03 02:51:36 matt Exp $");
-__IDSTRING(dotat, "$dotat: things/unifdef.c,v 1.171 2005/03/08 12:38:48 fanf2 Exp $");
-#endif
-#endif /* not lint */
-#ifdef __FBSDID
-__FBSDID("$FreeBSD: /repoman/r/ncvs/src/usr.bin/unifdef/unifdef.c,v 1.20 2005/05/21 09:55:09 ru Exp $");
-#endif
+static const char * const copyright[] = {
+    "@(#) Copyright (c) 2002 - 2009 Tony Finch <dot@dotat.at>\n",
+    "$dotat: unifdef/unifdef.c,v 1.190 2009/11/27 17:21:26 fanf2 Exp $",
+};
 
 /*
  * unifdef - remove ifdef'ed lines
@@ -72,8 +61,6 @@ __FBSDID("$FreeBSD: /repoman/r/ncvs/src/usr.bin/unifdef/unifdef.c,v 1.20 2005/05
 #include <string.h>
 #include <unistd.h>
 
-size_t strlcpy(char *dst, const char *src, size_t siz);
-
 /* types of input lines: */
 typedef enum {
        LT_TRUEI,               /* a true #if with ignore flag */
@@ -90,6 +77,7 @@ typedef enum {
        LT_DODGY_LAST = LT_DODGY + LT_ENDIF,
        LT_PLAIN,               /* ordinary line */
        LT_EOF,                 /* end of file */
+       LT_ERROR,               /* unevaluable #if */
        LT_COUNT
 } Linetype;
 
@@ -100,7 +88,7 @@ static char const * const linetype_name[] = {
        "DODGY IF", "DODGY TRUE", "DODGY FALSE",
        "DODGY ELIF", "DODGY ELTRUE", "DODGY ELFALSE",
        "DODGY ELSE", "DODGY ENDIF",
-       "PLAIN", "EOF"
+       "PLAIN", "EOF", "ERROR"
 };
 
 /* state of #if processing */
@@ -168,11 +156,13 @@ static char const * const linestate_name[] = {
  * Globals.
  */
 
+static bool             compblank;             /* -B: compress blank lines */
+static bool             lnblank;               /* -b: blank deleted lines */
 static bool             complement;            /* -c: do the complement */
 static bool             debugging;             /* -d: debugging reports */
 static bool             iocccok;               /* -e: fewer IOCCC errors */
+static bool             strictlogic;           /* -K: keep ambiguous #ifs */
 static bool             killconsts;            /* -k: eval constant #ifs */
-static bool             lnblank;               /* -l: blank deleted lines */
 static bool             lnnum;                 /* -n: add #line directives */
 static bool             symlist;               /* -s: output symbol list */
 static bool             text;                  /* -t: this is a text file */
@@ -196,7 +186,9 @@ static bool             ignoring[MAXDEPTH]; /* ignore comments state */
 static int              stifline[MAXDEPTH];    /* start of current #if */
 static int              depth;                 /* current #if nesting */
 static int              delcount;              /* count of deleted lines */
-static bool             keepthis;              /* don't delete constant #if */
+static unsigned         blankcount;            /* count of blank lines */
+static unsigned         blankmax;              /* maximum recent blankcount */
+static bool             constexpr;             /* constant #if expression */
 
 static int              exitstat;              /* program exit status */
 
@@ -206,13 +198,14 @@ static void             done(void);
 static void             error(const char *);
 static int              findsym(const char *);
 static void             flushline(bool);
-static Linetype         get_line(void);
+static Linetype         parseline(void);
 static Linetype         ifeval(const char **);
 static void             ignoreoff(void);
 static void             ignoreon(void);
 static void             keywordedit(const char *);
 static void             nest(void);
 static void             process(void);
+static const char      *skipargs(const char *);
 static const char      *skipcomment(const char *);
 static const char      *skipsym(const char *);
 static void             state(Ifstate);
@@ -220,7 +213,7 @@ static int              strlcmp(const char *, const char *, size_t);
 static void             unnest(void);
 static void             usage(void);
 
-#define endsym(c) (!isalpha((unsigned char)c) && !isdigit((unsigned char)c) && c != '_')
+#define endsym(c) (!isalnum((unsigned char)c) && c != '_')
 
 /*
  * The main program.
@@ -230,7 +223,7 @@ main(int argc, char *argv[])
 {
        int opt;
 
-       while ((opt = getopt(argc, argv, "i:D:U:I:cdeklnst")) != -1)
+       while ((opt = getopt(argc, argv, "i:D:U:I:BbcdeKklnst")) != -1)
                switch (opt) {
                case 'i': /* treat stuff controlled by these symbols as text */
                        /*
@@ -255,6 +248,13 @@ main(int argc, char *argv[])
                case 'I':
                        /* no-op for compatibility with cpp */
                        break;
+               case 'B': /* compress blank lines around removed section */
+                       compblank = true;
+                       break;
+               case 'b': /* blank deleted lines instead of omitting them */
+               case 'l': /* backwards compatibility */
+                       lnblank = true;
+                       break;
                case 'c': /* treat -D as -U and vice versa */
                        complement = true;
                        break;
@@ -264,12 +264,12 @@ main(int argc, char *argv[])
                case 'e': /* fewer errors from dodgy lines */
                        iocccok = true;
                        break;
+               case 'K': /* keep ambiguous #ifs */
+                       strictlogic = true;
+                       break;
                case 'k': /* process constant #ifs */
                        killconsts = true;
                        break;
-               case 'l': /* blank deleted lines instead of omitting them */
-                       lnblank = true;
-                       break;
                case 'n': /* add #line directive after deleted lines */
                        lnnum = true;
                        break;
@@ -284,6 +284,8 @@ main(int argc, char *argv[])
                }
        argc -= optind;
        argv += optind;
+       if (compblank && lnblank)
+               errx(2, "-B and -b are mutually exclusive");
        if (argc > 1) {
                errx(2, "can only do one file");
        } else if (argc == 1 && strcmp(*argv, "-") != 0) {
@@ -302,7 +304,7 @@ main(int argc, char *argv[])
 static void
 usage(void)
 {
-       fprintf(stderr, "usage: unifdef [-cdeklnst] [-Ipath]"
+       fprintf(stderr, "usage: unifdef [-BbcdeKknst] [-Ipath]"
            " [-Dsym[=val]] [-Usym] [-iDsym[=val]] [-iUsym] ... [file]\n");
        exit(2);
 }
@@ -383,46 +385,46 @@ static state_fn * const trans_table[IS_COUNT][LT_COUNT] = {
 /* IS_OUTSIDE */
 { Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Eendif,
   Oiffy, Oiffy, Fpass, Oif,   Oif,   Eelif, Eelif, Eelif, Eelse, Eendif,
-  print, done },
+  print, done,  abort },
 /* IS_FALSE_PREFIX */
 { Idrop, Idrop, Fdrop, Fdrop, Fdrop, Mpass, Strue, Sfalse,Selse, Dendif,
   Idrop, Idrop, Fdrop, Fdrop, Fdrop, Mpass, Eioccc,Eioccc,Eioccc,Eioccc,
-  drop,  Eeof },
+  drop,  Eeof,  abort },
 /* IS_TRUE_PREFIX */
 { Itrue, Ifalse,Fpass, Ftrue, Ffalse,Dfalse,Dfalse,Dfalse,Delse, Dendif,
   Oiffy, Oiffy, Fpass, Oif,   Oif,   Eioccc,Eioccc,Eioccc,Eioccc,Eioccc,
-  print, Eeof },
+  print, Eeof,  abort },
 /* IS_PASS_MIDDLE */
 { Itrue, Ifalse,Fpass, Ftrue, Ffalse,Pelif, Mtrue, Delif, Pelse, Pendif,
   Oiffy, Oiffy, Fpass, Oif,   Oif,   Pelif, Oelif, Oelif, Pelse, Pendif,
-  print, Eeof },
+  print, Eeof,  abort },
 /* IS_FALSE_MIDDLE */
 { Idrop, Idrop, Fdrop, Fdrop, Fdrop, Pelif, Mtrue, Delif, Pelse, Pendif,
   Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eioccc,Eioccc,Eioccc,Eioccc,Eioccc,
-  drop,  Eeof },
+  drop,  Eeof,  abort },
 /* IS_TRUE_MIDDLE */
 { Itrue, Ifalse,Fpass, Ftrue, Ffalse,Melif, Melif, Melif, Melse, Pendif,
   Oiffy, Oiffy, Fpass, Oif,   Oif,   Eioccc,Eioccc,Eioccc,Eioccc,Pendif,
-  print, Eeof },
+  print, Eeof,  abort },
 /* IS_PASS_ELSE */
 { Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Pendif,
   Oiffy, Oiffy, Fpass, Oif,   Oif,   Eelif, Eelif, Eelif, Eelse, Pendif,
-  print, Eeof },
+  print, Eeof,  abort },
 /* IS_FALSE_ELSE */
 { Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eelif, Eelif, Eelif, Eelse, Dendif,
   Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eelif, Eelif, Eelif, Eelse, Eioccc,
-  drop,  Eeof },
+  drop,  Eeof,  abort },
 /* IS_TRUE_ELSE */
 { Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Dendif,
   Oiffy, Oiffy, Fpass, Oif,   Oif,   Eelif, Eelif, Eelif, Eelse, Eioccc,
-  print, Eeof },
+  print, Eeof,  abort },
 /* IS_FALSE_TRAILER */
 { Idrop, Idrop, Fdrop, Fdrop, Fdrop, Dfalse,Dfalse,Dfalse,Delse, Dendif,
   Idrop, Idrop, Fdrop, Fdrop, Fdrop, Dfalse,Dfalse,Dfalse,Delse, Eioccc,
-  drop,  Eeof }
+  drop,  Eeof,  abort }
 /*TRUEI  FALSEI IF     TRUE   FALSE  ELIF   ELTRUE ELFALSE ELSE  ENDIF
   TRUEI  FALSEI IF     TRUE   FALSE  ELIF   ELTRUE ELFALSE ELSE  ENDIF (DODGY)
-  PLAIN  EOF */
+  PLAIN  EOF    ERROR */
 };
 
 /*
@@ -463,9 +465,11 @@ keywordedit(const char *replacement)
 static void
 nest(void)
 {
-       depth += 1;
-       if (depth >= MAXDEPTH)
+       if (depth > MAXDEPTH-1)
+               abort(); /* bug */
+       if (depth == MAXDEPTH-1)
                error("Too many levels of nesting");
+       depth += 1;
        stifline[depth] = linenum;
 }
 static void
@@ -490,15 +494,23 @@ flushline(bool keep)
        if (symlist)
                return;
        if (keep ^ complement) {
-               if (lnnum && delcount > 0)
-                       printf("#line %d\n", linenum);
-               fputs(tline, stdout);
-               delcount = 0;
+               bool blankline = tline[strspn(tline, " \t\n")] == '\0';
+               if (blankline && compblank && blankcount != blankmax) {
+                       delcount += 1;
+                       blankcount += 1;
+               } else {
+                       if (lnnum && delcount > 0)
+                               printf("#line %d\n", linenum);
+                       fputs(tline, stdout);
+                       delcount = 0;
+                       blankmax = blankcount = blankline ? blankcount + 1 : 0;
+               }
        } else {
                if (lnblank)
                        putc('\n', stdout);
                exitstat = 1;
                delcount += 1;
+               blankcount = 0;
        }
 }
 
@@ -510,9 +522,12 @@ process(void)
 {
        Linetype lineval;
 
+       /* When compressing blank lines, act as if the file
+          is preceded by a large number of blank lines. */
+       blankmax = blankcount = 1000;
        for (;;) {
                linenum++;
-               lineval = get_line();
+               lineval = parseline();
                trans_table[ifstate[depth]][lineval]();
                debug("process %s -> %s depth %d",
                    linetype_name[lineval],
@@ -526,7 +541,7 @@ process(void)
  * help from skipcomment().
  */
 static Linetype
-get_line(void)
+parseline(void)
 {
        const char *cp;
        int cursym;
@@ -595,9 +610,21 @@ get_line(void)
                        if (incomment)
                                linestate = LS_DIRTY;
                }
-               /* skipcomment should have changed the state */
-               if (linestate == LS_HASH)
-                       abort(); /* bug */
+               /* skipcomment normally changes the state, except
+                  if the last line of the file lacks a newline, or
+                  if there is too much whitespace in a directive */
+               if (linestate == LS_HASH) {
+                       size_t len = cp - tline;
+                       if (fgets(tline + len, MAXLINE - len, input) == NULL) {
+                               /* append the missing newline */
+                               tline[len+0] = '\n';
+                               tline[len+1] = '\0';
+                               cp++;
+                               linestate = LS_START;
+                       } else {
+                               linestate = LS_DIRTY;
+                       }
+               }
        }
        if (linestate == LS_DIRTY) {
                while (*cp != '\0')
@@ -610,17 +637,40 @@ get_line(void)
 
 /*
  * These are the binary operators that are supported by the expression
- * evaluator. Note that if support for division is added then we also
- * need short-circuiting booleans because of divide-by-zero.
+ * evaluator.
  */
-static int op_lt(int a, int b) { return (a < b); }
-static int op_gt(int a, int b) { return (a > b); }
-static int op_le(int a, int b) { return (a <= b); }
-static int op_ge(int a, int b) { return (a >= b); }
-static int op_eq(int a, int b) { return (a == b); }
-static int op_ne(int a, int b) { return (a != b); }
-static int op_or(int a, int b) { return (a || b); }
-static int op_and(int a, int b) { return (a && b); }
+static Linetype op_strict(int *p, int v, Linetype at, Linetype bt) {
+       if(at == LT_IF || bt == LT_IF) return (LT_IF);
+       return (*p = v, v ? LT_TRUE : LT_FALSE);
+}
+static Linetype op_lt(int *p, Linetype at, int a, Linetype bt, int b) {
+       return op_strict(p, a < b, at, bt);
+}
+static Linetype op_gt(int *p, Linetype at, int a, Linetype bt, int b) {
+       return op_strict(p, a > b, at, bt);
+}
+static Linetype op_le(int *p, Linetype at, int a, Linetype bt, int b) {
+       return op_strict(p, a <= b, at, bt);
+}
+static Linetype op_ge(int *p, Linetype at, int a, Linetype bt, int b) {
+       return op_strict(p, a >= b, at, bt);
+}
+static Linetype op_eq(int *p, Linetype at, int a, Linetype bt, int b) {
+       return op_strict(p, a == b, at, bt);
+}
+static Linetype op_ne(int *p, Linetype at, int a, Linetype bt, int b) {
+       return op_strict(p, a != b, at, bt);
+}
+static Linetype op_or(int *p, Linetype at, int a, Linetype bt, int b) {
+       if (!strictlogic && (at == LT_TRUE || bt == LT_TRUE))
+               return (*p = 1, LT_TRUE);
+       return op_strict(p, a || b, at, bt);
+}
+static Linetype op_and(int *p, Linetype at, int a, Linetype bt, int b) {
+       if (!strictlogic && (at == LT_FALSE || bt == LT_FALSE))
+               return (*p = 0, LT_FALSE);
+       return op_strict(p, a && b, at, bt);
+}
 
 /*
  * An evaluation function takes three arguments, as follows: (1) a pointer to
@@ -629,8 +679,8 @@ static int op_and(int a, int b) { return (a && b); }
  * value of the expression; and (3) a pointer to a char* that points to the
  * expression to be evaluated and that is updated to the end of the expression
  * when evaluation is complete. The function returns LT_FALSE if the value of
- * the expression is zero, LT_TRUE if it is non-zero, or LT_IF if the
- * expression could not be evaluated.
+ * the expression is zero, LT_TRUE if it is non-zero, LT_IF if the expression
+ * depends on an unknown symbol, or LT_ERROR if there is a parse failure.
  */
 struct ops;
 
@@ -649,7 +699,7 @@ static const struct ops {
        eval_fn *inner;
        struct op {
                const char *str;
-               int (*fn)(int, int);
+               Linetype (*fn)(int *, Linetype, int, Linetype, int);
        } op[5];
 } eval_ops[] = {
        { eval_table, { { "||", op_or } } },
@@ -664,8 +714,8 @@ static const struct ops {
 
 /*
  * Function for evaluating the innermost parts of expressions,
- * viz. !expr (expr) defined(symbol) symbol number
- * We reset the keepthis flag when we find a non-constant subexpression.
+ * viz. !expr (expr) number defined(symbol) symbol
+ * We reset the constexpr flag in the last two cases.
  */
 static Linetype
 eval_unary(const struct ops *ops, int *valp, const char **cpp)
@@ -673,68 +723,83 @@ eval_unary(const struct ops *ops, int *valp, const char **cpp)
        const char *cp;
        char *ep;
        int sym;
+       bool defparen;
+       Linetype lt;
 
        cp = skipcomment(*cpp);
        if (*cp == '!') {
                debug("eval%d !", ops - eval_ops);
                cp++;
-               if (eval_unary(ops, valp, &cp) == LT_IF) {
-                       *cpp = cp;
-                       return (LT_IF);
+               lt = eval_unary(ops, valp, &cp);
+               if (lt == LT_ERROR)
+                       return (LT_ERROR);
+               if (lt != LT_IF) {
+                       *valp = !*valp;
+                       lt = *valp ? LT_TRUE : LT_FALSE;
                }
-               *valp = !*valp;
        } else if (*cp == '(') {
                cp++;
                debug("eval%d (", ops - eval_ops);
-               if (eval_table(eval_ops, valp, &cp) == LT_IF)
-                       return (LT_IF);
+               lt = eval_table(eval_ops, valp, &cp);
+               if (lt == LT_ERROR)
+                       return (LT_ERROR);
                cp = skipcomment(cp);
                if (*cp++ != ')')
-                       return (LT_IF);
+                       return (LT_ERROR);
        } else if (isdigit((unsigned char)*cp)) {
                debug("eval%d number", ops - eval_ops);
                *valp = strtol(cp, &ep, 0);
+               if (ep == cp)
+                       return (LT_ERROR);
+               lt = *valp ? LT_TRUE : LT_FALSE;
                cp = skipsym(cp);
        } else if (strncmp(cp, "defined", 7) == 0 && endsym(cp[7])) {
                cp = skipcomment(cp+7);
                debug("eval%d defined", ops - eval_ops);
-               if (*cp++ != '(')
-                       return (LT_IF);
-               cp = skipcomment(cp);
+               if (*cp == '(') {
+                       cp = skipcomment(cp+1);
+                       defparen = true;
+               } else {
+                       defparen = false;
+               }
                sym = findsym(cp);
-               cp = skipsym(cp);
-               cp = skipcomment(cp);
-               if (*cp++ != ')')
-                       return (LT_IF);
-               if (sym >= 0)
+               if (sym < 0) {
+                       lt = LT_IF;
+               } else {
                        *valp = (value[sym] != NULL);
-               else {
-                       *cpp = cp;
-                       return (LT_IF);
+                       lt = *valp ? LT_TRUE : LT_FALSE;
                }
-               keepthis = false;
+               cp = skipsym(cp);
+               cp = skipcomment(cp);
+               if (defparen && *cp++ != ')')
+                       return (LT_ERROR);
+               constexpr = false;
        } else if (!endsym(*cp)) {
                debug("eval%d symbol", ops - eval_ops);
                sym = findsym(cp);
-               if (sym < 0)
-                       return (LT_IF);
-               if (value[sym] == NULL)
+               cp = skipsym(cp);
+               if (sym < 0) {
+                       lt = LT_IF;
+                       cp = skipargs(cp);
+               } else if (value[sym] == NULL) {
                        *valp = 0;
-               else {
+                       lt = LT_FALSE;
+               } else {
                        *valp = strtol(value[sym], &ep, 0);
                        if (*ep != '\0' || ep == value[sym])
-                               return (LT_IF);
+                               return (LT_ERROR);
+                       lt = *valp ? LT_TRUE : LT_FALSE;
+                       cp = skipargs(cp);
                }
-               cp = skipsym(cp);
-               keepthis = false;
+               constexpr = false;
        } else {
                debug("eval%d bad expr", ops - eval_ops);
-               return (LT_IF);
+               return (LT_ERROR);
        }
 
        *cpp = cp;
        debug("eval%d = %d", ops - eval_ops, *valp);
-       return (*valp ? LT_TRUE : LT_FALSE);
+       return (lt);
 }
 
 /*
@@ -746,11 +811,13 @@ eval_table(const struct ops *ops, int *valp, const char **cpp)
        const struct op *op;
        const char *cp;
        int val;
-       Linetype lhs, rhs;
+       Linetype lt, rt;
 
        debug("eval%d", ops - eval_ops);
        cp = *cpp;
-       lhs = ops->inner(ops+1, valp, &cp);
+       lt = ops->inner(ops+1, valp, &cp);
+       if (lt == LT_ERROR)
+               return (LT_ERROR);
        for (;;) {
                cp = skipcomment(cp);
                for (op = ops->op; op->str != NULL; op++)
@@ -760,32 +827,16 @@ eval_table(const struct ops *ops, int *valp, const char **cpp)
                        break;
                cp += strlen(op->str);
                debug("eval%d %s", ops - eval_ops, op->str);
-               rhs = ops->inner(ops+1, &val, &cp);
-               if (op->fn == op_and && (lhs == LT_FALSE || rhs == LT_FALSE)) {
-                       debug("eval%d: and always false", ops - eval_ops);
-                       if (lhs == LT_IF)
-                               *valp = val;
-                       lhs = LT_FALSE;
-                       continue;
-               }
-               if (op->fn == op_or && (lhs == LT_TRUE || rhs == LT_TRUE)) {
-                       debug("eval%d: or always true", ops - eval_ops);
-                       if (lhs == LT_IF)
-                               *valp = val;
-                       lhs = LT_TRUE;
-                       continue;
-               }
-               if (rhs == LT_IF)
-                       lhs = LT_IF;
-               if (lhs != LT_IF)
-                       *valp = op->fn(*valp, val);
+               rt = ops->inner(ops+1, &val, &cp);
+               if (rt == LT_ERROR)
+                       return (LT_ERROR);
+               lt = op->fn(valp, lt, *valp, rt, val);
        }
 
        *cpp = cp;
        debug("eval%d = %d", ops - eval_ops, *valp);
-       if (lhs != LT_IF)
-               lhs = (*valp ? LT_TRUE : LT_FALSE);
-       return lhs;
+       debug("eval%d lt = %s", ops - eval_ops, linetype_name[lt]);
+       return (lt);
 }
 
 /*
@@ -796,17 +847,14 @@ eval_table(const struct ops *ops, int *valp, const char **cpp)
 static Linetype
 ifeval(const char **cpp)
 {
-       const char *cp = *cpp;
        int ret;
-       int val;
+       int val = 0;
 
        debug("eval %s", *cpp);
-       keepthis = killconsts ? false : true;
-       ret = eval_table(eval_ops, &val, &cp);
-       if (ret != LT_IF)
-               *cpp = cp;
+       constexpr = killconsts ? false : true;
+       ret = eval_table(eval_ops, &val, cpp);
        debug("eval = %d", val);
-       return (keepthis ? LT_IF : ret);
+       return (constexpr ? LT_IF : ret == LT_ERROR ? LT_IF : ret);
 }
 
 /*
@@ -917,6 +965,31 @@ skipcomment(const char *cp)
        return (cp);
 }
 
+/*
+ * Skip macro arguments.
+ */
+static const char *
+skipargs(const char *cp)
+{
+       const char *ocp = cp;
+       int level = 0;
+       cp = skipcomment(cp);
+       if (*cp != '(')
+               return (cp);
+       do {
+               if (*cp == '(')
+                       level++;
+               if (*cp == ')')
+                       level--;
+               cp = skipcomment(cp+1);
+       } while (level != 0 && *cp != '\0');
+       if (level == 0)
+               return (cp);
+       else
+       /* Rewind and re-detect the syntax error later. */
+               return (ocp);
+}
+
 /*
  * Skip over an identifier.
  */
@@ -929,7 +1002,7 @@ skipsym(const char *cp)
 }
 
 /*
- * Look for the symbol in the symbol table. If is is found, we return
+ * Look for the symbol in the symbol table. If it is found, we return
  * the symbol table index, else we return -1.
  */
 static int
index 83b3dde1a83b74a5f1e75cb2d98a44787e33bca2..b2b3c2d1cf8bd37849d92b9a1d06131f1cf14f96 100644 (file)
@@ -354,7 +354,10 @@ static int cpio_mkfile(const char *name, const char *location,
                push_pad();
 
                if (size) {
-                       fwrite(filebuf, size, 1, stdout);
+                       if (fwrite(filebuf, size, 1, stdout) != 1) {
+                               fprintf(stderr, "writing filebuf failed\n");
+                               goto error;
+                       }
                        offset += size;
                        push_pad();
                }