Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 14 Dec 2009 20:50:25 +0000 (12:50 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 14 Dec 2009 20:50:25 +0000 (12:50 -0800)
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-udf-2.6:
  udf: Avoid IO in udf_clear_inode
  udf: Try harder when looking for VAT inode
  udf: Fix compilation with UDFFS_DEBUG enabled

383 files changed:
Documentation/feature-removal-schedule.txt
Documentation/md.txt
Documentation/spinlocks.txt
Documentation/sysctl/kernel.txt
MAINTAINERS
arch/arm/Kconfig
arch/arm/Kconfig.debug
arch/arm/configs/zeus_defconfig [new file with mode: 0644]
arch/arm/kernel/Makefile
arch/arm/kernel/early_printk.c [new file with mode: 0644]
arch/arm/kernel/smp_twd.c
arch/arm/mach-clps711x/include/mach/memory.h
arch/arm/mach-footbridge/common.c
arch/arm/mach-footbridge/include/mach/memory.h
arch/arm/mach-integrator/include/mach/memory.h
arch/arm/mach-ixp2000/include/mach/memory.h
arch/arm/mach-ixp23xx/include/mach/memory.h
arch/arm/mach-lh7a40x/clocks.c
arch/arm/mach-omap2/board-2430sdp.c
arch/arm/mach-omap2/board-3430sdp.c
arch/arm/mach-omap2/board-ldp.c
arch/arm/mach-omap2/board-omap3beagle.c
arch/arm/mach-omap2/board-omap3pandora.c
arch/arm/mach-omap2/board-overo.c
arch/arm/mach-omap2/board-rx51-peripherals.c
arch/arm/mach-pxa/Kconfig
arch/arm/mach-pxa/Makefile
arch/arm/mach-pxa/em-x270.c
arch/arm/mach-pxa/include/mach/arcom-pcmcia.h [new file with mode: 0644]
arch/arm/mach-pxa/include/mach/viper.h
arch/arm/mach-pxa/include/mach/zeus.h [new file with mode: 0644]
arch/arm/mach-pxa/viper.c
arch/arm/mach-pxa/zeus.c [new file with mode: 0644]
arch/arm/mach-realview/Kconfig
arch/arm/mach-s3c24a0/include/mach/memory.h
arch/arm/mach-sa1100/Kconfig
arch/arm/mach-sa1100/generic.c
arch/arm/mach-w90x900/include/mach/nuc900_spi.h [new file with mode: 0644]
arch/arm/plat-omap/include/plat/irqs.h
arch/arm/vfp/vfpmodule.c
arch/ia64/Kconfig
arch/ia64/include/asm/meminit.h
arch/ia64/include/asm/pgtable.h
arch/ia64/include/asm/processor.h
arch/ia64/kernel/acpi.c
arch/ia64/kernel/head.S
arch/ia64/kernel/ia64_ksyms.c
arch/ia64/kernel/mca_asm.S
arch/ia64/kernel/relocate_kernel.S
arch/ia64/kernel/setup.c
arch/ia64/kernel/vmlinux.lds.S
arch/ia64/mm/contig.c
arch/ia64/mm/discontig.c
arch/ia64/mm/init.c
arch/ia64/sn/kernel/sn2/sn2_smp.c
arch/ia64/xen/irq_xen.c
arch/ia64/xen/time.c
arch/m68k/include/asm/pgtable_mm.h
arch/m68k/sun3/mmu_emu.c
arch/microblaze/Kconfig
arch/microblaze/Kconfig.debug
arch/microblaze/Makefile
arch/microblaze/boot/Makefile
arch/microblaze/include/asm/cache.h
arch/microblaze/include/asm/cacheflush.h
arch/microblaze/include/asm/cpuinfo.h
arch/microblaze/include/asm/device.h
arch/microblaze/include/asm/ftrace.h
arch/microblaze/include/asm/futex.h
arch/microblaze/include/asm/irqflags.h
arch/microblaze/include/asm/page.h
arch/microblaze/include/asm/pgalloc.h
arch/microblaze/include/asm/pvr.h
arch/microblaze/include/asm/setup.h
arch/microblaze/include/asm/system.h
arch/microblaze/include/asm/uaccess.h
arch/microblaze/kernel/Makefile
arch/microblaze/kernel/cpu/Makefile
arch/microblaze/kernel/cpu/cache.c
arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c
arch/microblaze/kernel/cpu/cpuinfo-static.c
arch/microblaze/kernel/cpu/cpuinfo.c
arch/microblaze/kernel/cpu/mb.c
arch/microblaze/kernel/cpu/pvr.c
arch/microblaze/kernel/entry-nommu.S
arch/microblaze/kernel/entry.S
arch/microblaze/kernel/ftrace.c [new file with mode: 0644]
arch/microblaze/kernel/heartbeat.c
arch/microblaze/kernel/intc.c
arch/microblaze/kernel/mcount.S [new file with mode: 0644]
arch/microblaze/kernel/microblaze_ksyms.c
arch/microblaze/kernel/process.c
arch/microblaze/kernel/reset.c [new file with mode: 0644]
arch/microblaze/kernel/setup.c
arch/microblaze/kernel/signal.c
arch/microblaze/kernel/stacktrace.c [new file with mode: 0644]
arch/microblaze/kernel/syscall_table.S
arch/microblaze/kernel/timer.c
arch/microblaze/kernel/vmlinux.lds.S
arch/microblaze/lib/uaccess.c
arch/microblaze/mm/init.c
arch/microblaze/mm/pgtable.c
arch/microblaze/oprofile/Makefile [new file with mode: 0644]
arch/microblaze/oprofile/microblaze_oprofile.c [new file with mode: 0644]
arch/microblaze/platform/Kconfig.platform
arch/microblaze/platform/generic/Kconfig.auto
arch/microblaze/platform/generic/system.dts
arch/microblaze/platform/platform.c
arch/mn10300/kernel/kprobes.c
arch/powerpc/include/asm/smp.h
arch/powerpc/kernel/perf_callchain.c
arch/powerpc/kernel/setup-common.c
arch/powerpc/kernel/smp.c
arch/powerpc/platforms/cell/interrupt.c
arch/powerpc/platforms/pseries/dtl.c
arch/sparc/kernel/nmi.c
arch/x86/include/asm/irq_vectors.h
arch/x86/include/asm/msr.h
arch/x86/include/asm/percpu.h
arch/x86/include/asm/trampoline.h
arch/x86/kernel/aperture_64.c
arch/x86/kernel/apic/apic.c
arch/x86/kernel/apic/nmi.c
arch/x86/kernel/cpu/addon_cpuid_features.c
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/cpu_debug.c
arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
arch/x86/kernel/cpu/intel.c
arch/x86/kernel/cpu/intel_cacheinfo.c
arch/x86/kernel/cpu/mcheck/therm_throt.c
arch/x86/kernel/ds.c
arch/x86/kernel/e820.c
arch/x86/kernel/head32.c
arch/x86/kernel/head64.c
arch/x86/kernel/mpparse.c
arch/x86/kernel/pci-dma.c
arch/x86/kernel/pci-gart_64.c
arch/x86/kernel/setup.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/trampoline.c
arch/x86/kvm/svm.c
arch/x86/lib/msr.c
arch/x86/mm/mmio-mod.c
arch/x86/xen/smp.c
arch/x86/xen/time.c
crypto/cryptd.c
drivers/base/cpu.c
drivers/char/nvram.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/freq_table.c
drivers/crypto/padlock-aes.c
drivers/dma/dmaengine.c
drivers/edac/amd64_edac.c
drivers/gpio/adp5520-gpio.c
drivers/gpio/twl4030-gpio.c
drivers/gpio/wm831x-gpio.c
drivers/infiniband/hw/ehca/ehca_irq.c
drivers/input/keyboard/Kconfig
drivers/input/keyboard/Makefile
drivers/input/keyboard/adp5520-keys.c [new file with mode: 0644]
drivers/input/keyboard/twl4030_keypad.c
drivers/input/misc/pcf50633-input.c
drivers/input/misc/twl4030-pwrbutton.c
drivers/isdn/hardware/avm/avm_cs.c
drivers/isdn/hisax/avma1_cs.c
drivers/isdn/hisax/elsa_cs.c
drivers/isdn/hisax/sedlbauer_cs.c
drivers/isdn/hisax/teles_cs.c
drivers/lguest/x86/core.c
drivers/md/Kconfig
drivers/md/bitmap.c
drivers/md/bitmap.h
drivers/md/faulty.c
drivers/md/linear.c
drivers/md/md.c
drivers/md/md.h
drivers/md/multipath.c
drivers/md/raid0.c
drivers/md/raid1.c
drivers/md/raid1.h
drivers/md/raid10.c
drivers/md/raid5.c
drivers/md/raid6algos.c
drivers/mfd/88pm8607.c [new file with mode: 0644]
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/ab3100-core.c
drivers/mfd/ab4500-core.c [new file with mode: 0644]
drivers/mfd/adp5520.c [new file with mode: 0644]
drivers/mfd/asic3.c
drivers/mfd/ezx-pcap.c
drivers/mfd/mc13783-core.c
drivers/mfd/pcf50633-adc.c
drivers/mfd/pcf50633-core.c
drivers/mfd/tps65010.c
drivers/mfd/twl-core.c [new file with mode: 0644]
drivers/mfd/twl4030-core.c [deleted file]
drivers/mfd/twl4030-irq.c
drivers/mfd/twl4030-power.c
drivers/mfd/twl6030-irq.c [new file with mode: 0644]
drivers/mfd/wm831x-core.c
drivers/mfd/wm831x-irq.c
drivers/mfd/wm8350-core.c
drivers/mfd/wm8350-irq.c [new file with mode: 0644]
drivers/mfd/wm8350-regmap.c
drivers/net/chelsio/sge.c
drivers/net/loopback.c
drivers/net/pcmcia/axnet_cs.c
drivers/net/pcmcia/fmvj18x_cs.c
drivers/net/pcmcia/pcnet_cs.c
drivers/net/pcmcia/smc91c92_cs.c
drivers/net/pcmcia/xirc2ps_cs.c
drivers/net/veth.c
drivers/oprofile/cpu_buffer.c
drivers/oprofile/cpu_buffer.h
drivers/oprofile/oprofile_stats.c
drivers/pcmcia/Kconfig
drivers/pcmcia/Makefile
drivers/pcmcia/cardbus.c
drivers/pcmcia/cistpl.c
drivers/pcmcia/cs.c
drivers/pcmcia/ds.c
drivers/pcmcia/pcmcia_ioctl.c
drivers/pcmcia/pcmcia_resource.c
drivers/pcmcia/pxa2xx_base.c
drivers/pcmcia/pxa2xx_base.h
drivers/pcmcia/pxa2xx_palmtc.c
drivers/pcmcia/pxa2xx_stargate2.c
drivers/pcmcia/pxa2xx_viper.c
drivers/pcmcia/rsrc_mgr.c
drivers/pcmcia/rsrc_nonstatic.c
drivers/pcmcia/socket_sysfs.c
drivers/pcmcia/yenta_socket.c
drivers/power/pcf50633-charger.c
drivers/power/wm8350_power.c
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/pcf50633-regulator.c
drivers/regulator/twl-regulator.c [new file with mode: 0644]
drivers/regulator/twl4030-regulator.c [deleted file]
drivers/regulator/wm8350-regulator.c
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-pcf50633.c
drivers/rtc/rtc-twl.c [new file with mode: 0644]
drivers/rtc/rtc-twl4030.c [deleted file]
drivers/rtc/rtc-wm8350.c
drivers/s390/net/netiucv.c
drivers/spi/Kconfig
drivers/spi/Makefile
drivers/spi/au1550_spi.c
drivers/spi/mpc52xx_spi.c
drivers/spi/omap_spi_100k.c [new file with mode: 0644]
drivers/spi/spi_imx.c
drivers/spi/spi_mpc8xxx.c
drivers/spi/spi_nuc900.c [new file with mode: 0644]
drivers/spi/spi_sh_msiof.c [new file with mode: 0644]
drivers/spi/spidev.c
drivers/spi/xilinx_spi.c
drivers/spi/xilinx_spi.h [new file with mode: 0644]
drivers/spi/xilinx_spi_of.c [new file with mode: 0644]
drivers/spi/xilinx_spi_pltfm.c [new file with mode: 0644]
drivers/usb/otg/twl4030-usb.c
drivers/video/backlight/adp5520_bl.c
drivers/video/omap/lcd_2430sdp.c
drivers/watchdog/twl4030_wdt.c
fs/compat_ioctl.c
fs/ext4/mballoc.c
fs/nfs/callback.c
fs/nfs/callback.h
fs/nfs/callback_proc.c
fs/nfs/callback_xdr.c
fs/nfs/client.c
fs/nfs/delegation.c
fs/nfs/delegation.h
fs/nfs/dir.c
fs/nfs/dns_resolve.c
fs/nfs/internal.h
fs/nfs/iostat.h
fs/nfs/nfs4_fs.h
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/nfs4xdr.c
fs/nfs/read.c
fs/nfs/super.c
fs/nfs/unlink.c
fs/nfs/write.c
fs/xfs/xfs_mount.c
include/asm-generic/percpu.h
include/linux/hw_breakpoint.h
include/linux/i2c/tps65010.h
include/linux/i2c/twl.h [new file with mode: 0644]
include/linux/i2c/twl4030.h [deleted file]
include/linux/mfd/88pm8607.h [new file with mode: 0644]
include/linux/mfd/ab4500.h [new file with mode: 0644]
include/linux/mfd/adp5520.h [new file with mode: 0644]
include/linux/mfd/ezx-pcap.h
include/linux/mfd/mc13783-private.h
include/linux/mfd/mc13783.h
include/linux/mfd/pcf50633/core.h
include/linux/mfd/wm831x/core.h
include/linux/mfd/wm831x/pdata.h
include/linux/mfd/wm8350/core.h
include/linux/mfd/wm8350/gpio.h
include/linux/nfs4.h
include/linux/nfs_fs_sb.h
include/linux/nfs_xdr.h
include/linux/pci.h
include/linux/percpu-defs.h
include/linux/percpu.h
include/linux/raid/pq.h
include/linux/slab_def.h
include/linux/slub_def.h
include/linux/spi/mpc52xx_spi.h [deleted file]
include/linux/spi/sh_msiof.h [new file with mode: 0644]
include/linux/spi/xilinx_spi.h [new file with mode: 0644]
include/linux/sunrpc/sched.h
include/linux/vmstat.h
include/net/neighbour.h
include/net/netfilter/nf_conntrack.h
include/net/snmp.h
include/pcmcia/cs.h
include/pcmcia/ds.h
include/pcmcia/mem_op.h
include/pcmcia/ss.h
kernel/lockdep.c
kernel/module.c
kernel/rcutorture.c
kernel/sched.c
kernel/softirq.c
kernel/softlockup.c
kernel/time/timer_stats.c
kernel/trace/trace.c
kernel/trace/trace.h
kernel/trace/trace_functions_graph.c
kernel/trace/trace_hw_branches.c
mm/Makefile
mm/allocpercpu.c [deleted file]
mm/migrate.c
mm/percpu.c
mm/slab.c
mm/slub.c
mm/vmalloc.c
mm/vmstat.c
net/sunrpc/addr.c
net/sunrpc/auth.c
net/sunrpc/auth_gss/auth_gss.c
net/sunrpc/clnt.c
net/sunrpc/rpcb_clnt.c
net/sunrpc/sunrpc_syms.c
net/sunrpc/xprt.c
net/sunrpc/xprtsock.c
scripts/recordmcount.pl
sound/pcmcia/pdaudiocf/pdaudiocf.c
sound/soc/codecs/twl4030.c
sound/soc/codecs/wm8350.c
tools/perf/Makefile
tools/perf/bench/sched-messaging.c
tools/perf/bench/sched-pipe.c
tools/perf/builtin-annotate.c
tools/perf/builtin-bench.c
tools/perf/builtin-buildid-list.c
tools/perf/builtin-kmem.c
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-sched.c
tools/perf/builtin-timechart.c
tools/perf/builtin-trace.c
tools/perf/perf.h
tools/perf/util/data_map.c
tools/perf/util/data_map.h
tools/perf/util/event.c
tools/perf/util/event.h
tools/perf/util/header.c
tools/perf/util/header.h
tools/perf/util/map.c
tools/perf/util/session.c [new file with mode: 0644]
tools/perf/util/session.h [new file with mode: 0644]
tools/perf/util/symbol.c
tools/perf/util/symbol.h
tools/perf/util/thread.c
tools/perf/util/thread.h

index 2a4d77946c7dc075df1a6678a54204ea8e618502..eb2c138c277c45ec66b25116cbd744d42c41878f 100644 (file)
@@ -291,13 +291,6 @@ Who:       Michael Buesch <mb@bu3sch.de>
 
 ---------------------------
 
-What:  usedac i386 kernel parameter
-When:  2.6.27
-Why:   replaced by allowdac and no dac combination
-Who:   Glauber Costa <gcosta@redhat.com>
-
----------------------------
-
 What: print_fn_descriptor_symbol()
 When: October 2009
 Why:  The %pF vsprintf format provides the same functionality in a
index 4edd39ec7db91abcbcbac352fc3c5e6d3e3c3eca..188f4768f1d58c013d962f993ae36483195fd288 100644 (file)
@@ -233,9 +233,9 @@ All md devices contain:
 
   resync_start
      The point at which resync should start.  If no resync is needed,
-     this will be a very large number.  At array creation it will
-     default to 0, though starting the array as 'clean' will
-     set it much larger.
+     this will be a very large number (or 'none' since 2.6.30-rc1).  At
+     array creation it will default to 0, though starting the array as
+     'clean' will set it much larger.
 
    new_dev
      This file can be written but not read.  The value written should
@@ -296,6 +296,51 @@ All md devices contain:
      active-idle
          like active, but no writes have been seen for a while (safe_mode_delay).
 
+  bitmap/location
+     This indicates where the write-intent bitmap for the array is
+     stored.
+     It can be one of "none", "file" or "[+-]N".
+     "file" may later be extended to "file:/file/name"
+     "[+-]N" means that many sectors from the start of the metadata.
+       This is replicated on all devices.  For arrays with externally
+       managed metadata, the offset is from the beginning of the
+       device.
+  bitmap/chunksize
+     The size, in bytes, of the chunk which will be represented by a
+     single bit.  For RAID456, it is a portion of an individual
+     device. For RAID10, it is a portion of the array.  For RAID1, it
+     is both (they come to the same thing).
+  bitmap/time_base
+     The time, in seconds, between looking for bits in the bitmap to
+     be cleared. In the current implementation, a bit will be cleared
+     between 2 and 3 times "time_base" after all the covered blocks
+     are known to be in-sync.
+  bitmap/backlog
+     When write-mostly devices are active in a RAID1, write requests
+     to those devices proceed in the background - the filesystem (or
+     other user of the device) does not have to wait for them.
+     'backlog' sets a limit on the number of concurrent background
+     writes.  If there are more than this, new writes will by
+     synchronous.
+  bitmap/metadata
+     This can be either 'internal' or 'external'.
+     'internal' is the default and means the metadata for the bitmap
+     is stored in the first 256 bytes of the allocated space and is
+     managed by the md module.
+     'external' means that bitmap metadata is managed externally to
+     the kernel (i.e. by some userspace program)
+  bitmap/can_clear
+     This is either 'true' or 'false'.  If 'true', then bits in the
+     bitmap will be cleared when the corresponding blocks are thought
+     to be in-sync.  If 'false', bits will never be cleared.
+     This is automatically set to 'false' if a write happens on a
+     degraded array, or if the array becomes degraded during a write.
+     When metadata is managed externally, it should be set to true
+     once the array becomes non-degraded, and this fact has been
+     recorded in the metadata.
+     
+     
+     
 
 As component devices are added to an md array, they appear in the 'md'
 directory as new directories named
@@ -334,8 +379,9 @@ Each directory contains:
        Writing "writemostly" sets the writemostly flag.
        Writing "-writemostly" clears the writemostly flag.
        Writing "blocked" sets the "blocked" flag.
-       Writing "-blocked" clear the "blocked" flag and allows writes
+       Writing "-blocked" clears the "blocked" flag and allows writes
                to complete.
+       Writing "in_sync" sets the in_sync flag.
 
        This file responds to select/poll. Any change to 'faulty'
        or 'blocked' causes an event.
@@ -372,6 +418,24 @@ Each directory contains:
         array.  If a value less than the current component_size is
         written, it will be rejected.
 
+      recovery_start
+
+        When the device is not 'in_sync', this records the number of
+       sectors from the start of the device which are known to be
+       correct.  This is normally zero, but during a recovery
+       operation is will steadily increase, and if the recovery is
+       interrupted, restoring this value can cause recovery to
+       avoid repeating the earlier blocks.  With v1.x metadata, this
+       value is saved and restored automatically.
+
+       This can be set whenever the device is not an active member of
+       the array, either before the array is activated, or before
+       the 'slot' is set.
+
+       Setting this to 'none' is equivalent to setting 'in_sync'.
+       Setting to any other value also clears the 'in_sync' flag.
+       
+
 
 An active md device will also contain and entry for each active device
 in the array.  These are named
index 619699dde5938b64c6d63e1059cf0ed702c128af..178c831b907d08c8096b72c307508d0b272fccbe 100644 (file)
@@ -1,73 +1,8 @@
-SPIN_LOCK_UNLOCKED and RW_LOCK_UNLOCKED defeat lockdep state tracking and
-are hence deprecated.
+Lesson 1: Spin locks
 
-Please use DEFINE_SPINLOCK()/DEFINE_RWLOCK() or
-__SPIN_LOCK_UNLOCKED()/__RW_LOCK_UNLOCKED() as appropriate for static
-initialization.
-
-Most of the time, you can simply turn:
-
-       static spinlock_t xxx_lock = SPIN_LOCK_UNLOCKED;
-
-into:
-
-       static DEFINE_SPINLOCK(xxx_lock);
-
-Static structure member variables go from:
-
-       struct foo bar {
-               .lock   =       SPIN_LOCK_UNLOCKED;
-       };
-
-to:
-
-       struct foo bar {
-               .lock   =       __SPIN_LOCK_UNLOCKED(bar.lock);
-       };
-
-Declaration of static rw_locks undergo a similar transformation.
-
-Dynamic initialization, when necessary, may be performed as
-demonstrated below.
-
-   spinlock_t xxx_lock;
-   rwlock_t xxx_rw_lock;
-
-   static int __init xxx_init(void)
-   {
-       spin_lock_init(&xxx_lock);
-       rwlock_init(&xxx_rw_lock);
-       ...
-   }
-
-   module_init(xxx_init);
-
-The following discussion is still valid, however, with the dynamic
-initialization of spinlocks or with DEFINE_SPINLOCK, etc., used
-instead of SPIN_LOCK_UNLOCKED.
-
------------------------
-
-On Fri, 2 Jan 1998, Doug Ledford wrote:
-> 
-> I'm working on making the aic7xxx driver more SMP friendly (as well as
-> importing the latest FreeBSD sequencer code to have 7895 support) and wanted
-> to get some info from you.  The goal here is to make the various routines
-> SMP safe as well as UP safe during interrupts and other manipulating
-> routines.  So far, I've added a spin_lock variable to things like my queue
-> structs.  Now, from what I recall, there are some spin lock functions I can
-> use to lock these spin locks from other use as opposed to a (nasty)
-> save_flags(); cli(); stuff; restore_flags(); construct.  Where do I find
-> these routines and go about making use of them?  Do they only lock on a
-> per-processor basis or can they also lock say an interrupt routine from
-> mucking with a queue if the queue routine was manipulating it when the
-> interrupt occurred, or should I still use a cli(); based construct on that
-> one?
-
-See <asm/spinlock.h>. The basic version is:
-
-   spinlock_t xxx_lock = SPIN_LOCK_UNLOCKED;
+The most basic primitive for locking is spinlock.
 
+static DEFINE_SPINLOCK(xxx_lock);
 
        unsigned long flags;
 
@@ -75,13 +10,11 @@ See <asm/spinlock.h>. The basic version is:
        ... critical section here ..
        spin_unlock_irqrestore(&xxx_lock, flags);
 
-and the above is always safe. It will disable interrupts _locally_, but the
+The above is always safe. It will disable interrupts _locally_, but the
 spinlock itself will guarantee the global lock, so it will guarantee that
 there is only one thread-of-control within the region(s) protected by that
-lock. 
-
-Note that it works well even under UP - the above sequence under UP
-essentially is just the same as doing a
+lock. This works well even under UP. The above sequence under UP
+essentially is just the same as doing
 
        unsigned long flags;
 
@@ -91,15 +24,13 @@ essentially is just the same as doing a
 
 so the code does _not_ need to worry about UP vs SMP issues: the spinlocks
 work correctly under both (and spinlocks are actually more efficient on
-architectures that allow doing the "save_flags + cli" in one go because I
-don't export that interface normally).
+architectures that allow doing the "save_flags + cli" in one operation).
+
+   NOTE! Implications of spin_locks for memory are further described in:
 
-NOTE NOTE NOTE! The reason the spinlock is so much faster than a global
-interrupt lock under SMP is exactly because it disables interrupts only on
-the local CPU. The spin-lock is safe only when you _also_ use the lock
-itself to do locking across CPU's, which implies that EVERYTHING that
-touches a shared variable has to agree about the spinlock they want to
-use.
+     Documentation/memory-barriers.txt
+       (5) LOCK operations.
+       (6) UNLOCK operations.
 
 The above is usually pretty simple (you usually need and want only one
 spinlock for most things - using more than one spinlock can make things a
@@ -120,20 +51,24 @@ and another sequence that does
 then they are NOT mutually exclusive, and the critical regions can happen
 at the same time on two different CPU's. That's fine per se, but the
 critical regions had better be critical for different things (ie they
-can't stomp on each other). 
+can't stomp on each other).
 
 The above is a problem mainly if you end up mixing code - for example the
 routines in ll_rw_block() tend to use cli/sti to protect the atomicity of
 their actions, and if a driver uses spinlocks instead then you should
-think about issues like the above..
+think about issues like the above.
 
 This is really the only really hard part about spinlocks: once you start
 using spinlocks they tend to expand to areas you might not have noticed
 before, because you have to make sure the spinlocks correctly protect the
 shared data structures _everywhere_ they are used. The spinlocks are most
-easily added to places that are completely independent of other code (ie
-internal driver data structures that nobody else ever touches, for
-example). 
+easily added to places that are completely independent of other code (for
+example, internal driver data structures that nobody else ever touches).
+
+   NOTE! The spin-lock is safe only when you _also_ use the lock itself
+   to do locking across CPU's, which implies that EVERYTHING that
+   touches a shared variable has to agree about the spinlock they want
+   to use.
 
 ----
 
@@ -141,13 +76,17 @@ Lesson 2: reader-writer spinlocks.
 
 If your data accesses have a very natural pattern where you usually tend
 to mostly read from the shared variables, the reader-writer locks
-(rw_lock) versions of the spinlocks are often nicer. They allow multiple
+(rw_lock) versions of the spinlocks are sometimes useful. They allow multiple
 readers to be in the same critical region at once, but if somebody wants
-to change the variables it has to get an exclusive write lock. The
-routines look the same as above:
+to change the variables it has to get an exclusive write lock.
 
-   rwlock_t xxx_lock = RW_LOCK_UNLOCKED;
+   NOTE! reader-writer locks require more atomic memory operations than
+   simple spinlocks.  Unless the reader critical section is long, you
+   are better off just using spinlocks.
 
+The routines look the same as above:
+
+   rwlock_t xxx_lock = RW_LOCK_UNLOCKED;
 
        unsigned long flags;
 
@@ -159,18 +98,21 @@ routines look the same as above:
        .. read and write exclusive access to the info ...
        write_unlock_irqrestore(&xxx_lock, flags);
 
-The above kind of lock is useful for complex data structures like linked
-lists etc, especially when you know that most of the work is to just
-traverse the list searching for entries without changing the list itself,
-for example. Then you can use the read lock for that kind of list
-traversal, which allows many concurrent readers. Anything that _changes_
-the list will have to get the write lock. 
+The above kind of lock may be useful for complex data structures like
+linked lists, especially searching for entries without changing the list
+itself.  The read lock allows many concurrent readers.  Anything that
+_changes_ the list will have to get the write lock.
+
+   NOTE! RCU is better for list traversal, but requires careful
+   attention to design detail (see Documentation/RCU/listRCU.txt).
 
-Note: you cannot "upgrade" a read-lock to a write-lock, so if you at _any_
+Also, you cannot "upgrade" a read-lock to a write-lock, so if you at _any_
 time need to do any changes (even if you don't do it every time), you have
-to get the write-lock at the very beginning. I could fairly easily add a
-primitive to create a "upgradeable" read-lock, but it hasn't been an issue
-yet. Tell me if you'd want one. 
+to get the write-lock at the very beginning.
+
+   NOTE! We are working hard to remove reader-writer spinlocks in most
+   cases, so please don't add a new one without consensus.  (Instead, see
+   Documentation/RCU/rcu.txt for complete information.)
 
 ----
 
@@ -233,4 +175,46 @@ indeed), while write-locks need to protect themselves against interrupts.
 
                Linus
 
+----
+
+Reference information:
+
+For dynamic initialization, use spin_lock_init() or rwlock_init() as
+appropriate:
+
+   spinlock_t xxx_lock;
+   rwlock_t xxx_rw_lock;
+
+   static int __init xxx_init(void)
+   {
+       spin_lock_init(&xxx_lock);
+       rwlock_init(&xxx_rw_lock);
+       ...
+   }
+
+   module_init(xxx_init);
+
+For static initialization, use DEFINE_SPINLOCK() / DEFINE_RWLOCK() or
+__SPIN_LOCK_UNLOCKED() / __RW_LOCK_UNLOCKED() as appropriate.
+
+SPIN_LOCK_UNLOCKED and RW_LOCK_UNLOCKED are deprecated.  These interfere
+with lockdep state tracking.
+
+Most of the time, you can simply turn:
+       static spinlock_t xxx_lock = SPIN_LOCK_UNLOCKED;
+into:
+       static DEFINE_SPINLOCK(xxx_lock);
+
+Static structure member variables go from:
+
+       struct foo bar {
+               .lock   =       SPIN_LOCK_UNLOCKED;
+       };
+
+to:
 
+       struct foo bar {
+               .lock   =       __SPIN_LOCK_UNLOCKED(bar.lock);
+       };
+
+Declaration of static rw_locks undergo a similar transformation.
index 8f7a0e73ef44a2d48c6d0ae6755fde7d5479535e..3894eaa23486f951ace787893740ac2850f7d6d9 100644 (file)
@@ -19,6 +19,8 @@ Currently, these files might (depending on your configuration)
 show up in /proc/sys/kernel:
 - acpi_video_flags
 - acct
+- bootloader_type           [ X86 only ]
+- bootloader_version        [ X86 only ]
 - callhome                  [ S390 only ]
 - auto_msgmni
 - core_pattern
@@ -93,6 +95,35 @@ valid for 30 seconds.
 
 ==============================================================
 
+bootloader_type:
+
+x86 bootloader identification
+
+This gives the bootloader type number as indicated by the bootloader,
+shifted left by 4, and OR'd with the low four bits of the bootloader
+version.  The reason for this encoding is that this used to match the
+type_of_loader field in the kernel header; the encoding is kept for
+backwards compatibility.  That is, if the full bootloader type number
+is 0x15 and the full version number is 0x234, this file will contain
+the value 340 = 0x154.
+
+See the type_of_loader and ext_loader_type fields in
+Documentation/x86/boot.txt for additional information.
+
+==============================================================
+
+bootloader_version:
+
+x86 bootloader version
+
+The complete bootloader version number.  In the example above, this
+file will contain the value 564 = 0x234.
+
+See the type_of_loader and ext_loader_ver fields in
+Documentation/x86/boot.txt for additional information.
+
+==============================================================
+
 callhome:
 
 Controls the kernel's callhome behavior in case of a kernel panic.
index cff133be42c6d30abf25fefce7e1e748bb8b6e49..1f21c34124db44d77fabe9ed7f9b8b1decfb299b 100644 (file)
@@ -5080,6 +5080,7 @@ F:        drivers/char/specialix*
 
 SPI SUBSYSTEM
 M:     David Brownell <dbrownell@users.sourceforge.net>
+M:     Grant Likely <grant.likely@secretlab.ca>
 L:     spi-devel-general@lists.sourceforge.net
 S:     Maintained
 F:     Documentation/spi/
index cf8a99f19dc4dde348094e6817ade53391b7f4ab..233a222752c0c507a3879109b3c81d0793d3bf76 100644 (file)
@@ -603,6 +603,7 @@ config ARCH_SA1100
        select ARCH_SPARSEMEM_ENABLE
        select ARCH_MTD_XIP
        select ARCH_HAS_CPUFREQ
+       select CPU_FREQ
        select GENERIC_GPIO
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
@@ -1359,13 +1360,9 @@ source "drivers/cpufreq/Kconfig"
 
 config CPU_FREQ_SA1100
        bool
-       depends on CPU_FREQ && (SA1100_H3100 || SA1100_H3600 || SA1100_LART || SA1100_PLEB || SA1100_BADGE4 || SA1100_HACKKIT)
-       default y
 
 config CPU_FREQ_SA1110
        bool
-       depends on CPU_FREQ && (SA1100_ASSABET || SA1100_CERF || SA1100_PT_SYSTEM3)
-       default y
 
 config CPU_FREQ_INTEGRATOR
        tristate "CPUfreq driver for ARM Integrator CPUs"
index ff54c23d085e51844332615a98bd12259d1b7015..5cb9326df7a7ad2e75fe10205c3786c40432cfa9 100644 (file)
@@ -71,6 +71,14 @@ config DEBUG_LL
          in the kernel.  This is helpful if you are debugging code that
          executes before the console is initialized.
 
+config EARLY_PRINTK
+       bool "Early printk"
+       depends on DEBUG_LL
+       help
+         Say Y here if you want to have an early console using the
+         kernel low-level debugging functions. Add earlyprintk to your
+         kernel parameters to enable this console.
+
 config DEBUG_ICEDCC
        bool "Kernel low-level debugging via EmbeddedICE DCC channel"
        depends on DEBUG_LL
diff --git a/arch/arm/configs/zeus_defconfig b/arch/arm/configs/zeus_defconfig
new file mode 100644 (file)
index 0000000..823b11e
--- /dev/null
@@ -0,0 +1,2032 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.32
+# Tue Dec  8 20:27:05 2009
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_ARCH_HAS_CPUFREQ=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_MTD_XIP=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+# CONFIG_TREE_RCU is not set
+# CONFIG_TREE_PREEMPT_RCU is not set
+CONFIG_TINY_RCU=y
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=13
+# CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+# CONFIG_RELAY is not set
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+CONFIG_COMPAT_BRK=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_SLOW_WORK is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_DEFAULT_DEADLINE=y
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="deadline"
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+CONFIG_INLINE_SPIN_UNLOCK=y
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+CONFIG_INLINE_READ_UNLOCK=y
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+CONFIG_INLINE_WRITE_UNLOCK=y
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+# CONFIG_MUTEX_SPIN_ON_OWNER is not set
+CONFIG_FREEZER=y
+
+#
+# System Type
+#
+CONFIG_MMU=y
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_STMP3XXX is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_DOVE is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_PNX4008 is not set
+CONFIG_ARCH_PXA=y
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5PC1XX is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_BCMRING is not set
+# CONFIG_ARCH_U8500 is not set
+
+#
+# Intel PXA2xx/PXA3xx Implementations
+#
+
+#
+# Intel/Marvell Dev Platforms (sorted by hardware release time)
+#
+# CONFIG_ARCH_LUBBOCK is not set
+# CONFIG_MACH_MAINSTONE is not set
+# CONFIG_MACH_ZYLONITE300 is not set
+# CONFIG_MACH_ZYLONITE320 is not set
+# CONFIG_MACH_LITTLETON is not set
+# CONFIG_MACH_TAVOREVB is not set
+# CONFIG_MACH_SAAR is not set
+
+#
+# Third Party Dev Platforms (sorted by vendor name)
+#
+# CONFIG_ARCH_PXA_IDP is not set
+# CONFIG_ARCH_VIPER is not set
+CONFIG_MACH_ARCOM_ZEUS=y
+# CONFIG_MACH_BALLOON3 is not set
+# CONFIG_MACH_CSB726 is not set
+# CONFIG_MACH_ARMCORE is not set
+# CONFIG_MACH_EM_X270 is not set
+# CONFIG_MACH_EXEDA is not set
+# CONFIG_MACH_CM_X300 is not set
+# CONFIG_ARCH_GUMSTIX is not set
+# CONFIG_MACH_INTELMOTE2 is not set
+# CONFIG_MACH_STARGATE2 is not set
+# CONFIG_MACH_XCEP is not set
+# CONFIG_TRIZEPS_PXA is not set
+CONFIG_ARCOM_PCMCIA=y
+# CONFIG_MACH_LOGICPD_PXA270 is not set
+# CONFIG_MACH_PCM027 is not set
+# CONFIG_MACH_COLIBRI is not set
+# CONFIG_MACH_COLIBRI300 is not set
+# CONFIG_MACH_COLIBRI320 is not set
+
+#
+# End-user Products (sorted by vendor name)
+#
+# CONFIG_MACH_H4700 is not set
+# CONFIG_MACH_H5000 is not set
+# CONFIG_MACH_HIMALAYA is not set
+# CONFIG_MACH_MAGICIAN is not set
+# CONFIG_MACH_MIOA701 is not set
+# CONFIG_PXA_EZX is not set
+# CONFIG_MACH_MP900C is not set
+# CONFIG_ARCH_PXA_PALM is not set
+# CONFIG_PXA_SHARPSL is not set
+# CONFIG_ARCH_PXA_ESERIES is not set
+CONFIG_PXA27x=y
+CONFIG_PXA_SSP=y
+CONFIG_PXA_HAVE_BOARD_IRQS=y
+CONFIG_PXA_HAVE_ISA_IRQS=y
+CONFIG_PLAT_PXA=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_XSCALE=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_PABRT_LEGACY=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_DCACHE_DISABLE is not set
+CONFIG_ARM_L1_CACHE_SHIFT=5
+CONFIG_IWMMXT=y
+CONFIG_XSCALE_PMU=y
+CONFIG_COMMON_CLKDEV=y
+
+#
+# Bus support
+#
+CONFIG_ISA=y
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+CONFIG_PCCARD=m
+CONFIG_PCMCIA=m
+CONFIG_PCMCIA_LOAD_CIS=y
+CONFIG_PCMCIA_IOCTL=y
+
+#
+# PC-card bridges
+#
+# CONFIG_I82365 is not set
+# CONFIG_TCIC is not set
+CONFIG_PCMCIA_SOC_COMMON=m
+CONFIG_PCMCIA_PXA2XX=m
+# CONFIG_PCMCIA_DEBUG is not set
+CONFIG_PCMCIA_PROBE=y
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=31:02 rootfstype=jffs2 ro console=ttyS0,115200"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Power Management
+#
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=m
+CONFIG_CPU_FREQ_GOV_USERSPACE=m
+CONFIG_CPU_FREQ_GOV_ONDEMAND=m
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+CONFIG_APM_EMULATION=y
+# CONFIG_PM_RUNTIME is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+# CONFIG_BT_SCO is not set
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+# CONFIG_BT_BNEP_MC_FILTER is not set
+# CONFIG_BT_BNEP_PROTO_FILTER is not set
+# CONFIG_BT_HIDP is not set
+
+#
+# Bluetooth device drivers
+#
+# CONFIG_BT_HCIBTUSB is not set
+# CONFIG_BT_HCIBTSDIO is not set
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
+# CONFIG_BT_HCIUART_LL is not set
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBPA10X is not set
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_BT_HCIDTL1 is not set
+# CONFIG_BT_HCIBT3C is not set
+# CONFIG_BT_HCIBLUECARD is not set
+# CONFIG_BT_HCIBTUART is not set
+# CONFIG_BT_HCIVHCI is not set
+# CONFIG_BT_MRVL is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+CONFIG_WIRELESS_EXT=y
+CONFIG_WEXT_CORE=y
+CONFIG_WEXT_PROC=y
+CONFIG_WEXT_SPY=y
+CONFIG_WEXT_PRIV=y
+CONFIG_CFG80211=m
+# CONFIG_NL80211_TESTMODE is not set
+# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
+# CONFIG_CFG80211_REG_DEBUG is not set
+CONFIG_CFG80211_DEFAULT_PS=y
+# CONFIG_WIRELESS_OLD_REGULATORY is not set
+CONFIG_CFG80211_WEXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+CONFIG_LIB80211=m
+# CONFIG_LIB80211_DEBUG is not set
+CONFIG_MAC80211=m
+CONFIG_MAC80211_RC_MINSTREL=y
+# CONFIG_MAC80211_RC_DEFAULT_PID is not set
+CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
+CONFIG_MAC80211_RC_DEFAULT="minstrel"
+# CONFIG_MAC80211_MESH is not set
+# CONFIG_MAC80211_LEDS is not set
+# CONFIG_MAC80211_DEBUG_MENU is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+CONFIG_MTD_REDBOOT_PARTS_READONLY=y
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+# CONFIG_MTD_MAP_BANK_WIDTH_4 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+# CONFIG_MTD_CFI_I2 is not set
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_OTP is not set
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+CONFIG_MTD_RAM=y
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_XIP is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
+CONFIG_MTD_PXA2XX=y
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_IMPA7 is not set
+# CONFIG_MTD_GPIO_ADDR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SST25L is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+# CONFIG_PNP is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+
+#
+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected
+#
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MG_DISK is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+CONFIG_EEPROM_AT24=m
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_IWMC3200TOP is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=m
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_SCSI_PROC_FS is not set
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+CONFIG_ATA=m
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_ATA_VERBOSE_ERROR=y
+# CONFIG_SATA_PMP is not set
+CONFIG_ATA_SFF=y
+# CONFIG_SATA_MV is not set
+# CONFIG_PATA_LEGACY is not set
+CONFIG_PATA_PCMCIA=m
+# CONFIG_PATA_QDI is not set
+# CONFIG_PATA_WINBOND_VLB is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_ARCNET is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_SMC91X is not set
+CONFIG_DM9000=y
+CONFIG_DM9000_DEBUGLEVEL=4
+# CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMC911X is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_DNET is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_B44 is not set
+# CONFIG_CS89x0 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_TR is not set
+CONFIG_WLAN=y
+# CONFIG_PCMCIA_RAYCS is not set
+# CONFIG_LIBERTAS_THINFIRM is not set
+# CONFIG_ATMEL is not set
+# CONFIG_AT76C50X_USB is not set
+# CONFIG_AIRO_CS is not set
+# CONFIG_PCMCIA_WL3501 is not set
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_USB_NET_RNDIS_WLAN is not set
+# CONFIG_RTL8187 is not set
+# CONFIG_MAC80211_HWSIM is not set
+# CONFIG_ATH_COMMON is not set
+# CONFIG_B43 is not set
+# CONFIG_B43LEGACY is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_IWM is not set
+# CONFIG_LIBERTAS is not set
+CONFIG_HERMES=m
+CONFIG_HERMES_CACHE_FW_ON_INIT=y
+CONFIG_PCMCIA_HERMES=m
+# CONFIG_PCMCIA_SPECTRUM is not set
+# CONFIG_P54_COMMON is not set
+CONFIG_RT2X00=m
+# CONFIG_RT2500USB is not set
+CONFIG_RT73USB=m
+# CONFIG_RT2800USB is not set
+CONFIG_RT2X00_LIB_USB=m
+CONFIG_RT2X00_LIB=m
+CONFIG_RT2X00_LIB_FIRMWARE=y
+CONFIG_RT2X00_LIB_CRYPTO=y
+CONFIG_RT2X00_LIB_LEDS=y
+# CONFIG_RT2X00_DEBUG is not set
+# CONFIG_WL12XX is not set
+# CONFIG_ZD1211RW is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+CONFIG_NET_PCMCIA=y
+# CONFIG_PCMCIA_3C589 is not set
+# CONFIG_PCMCIA_3C574 is not set
+# CONFIG_PCMCIA_FMVJ18X is not set
+# CONFIG_PCMCIA_PCNET is not set
+# CONFIG_PCMCIA_NMCLAN is not set
+# CONFIG_PCMCIA_SMC91C92 is not set
+# CONFIG_PCMCIA_XIRC2PS is not set
+# CONFIG_PCMCIA_AXNET is not set
+# CONFIG_WAN is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPPOE is not set
+# CONFIG_PPPOL2TP is not set
+# CONFIG_SLIP is not set
+CONFIG_SLHC=m
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=m
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_ADS7846 is not set
+# CONFIG_TOUCHSCREEN_AD7877 is not set
+# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
+# CONFIG_TOUCHSCREEN_AD7879_SPI is not set
+# CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_EETI is not set
+CONFIG_TOUCHSCREEN_FUJITSU=m
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+CONFIG_TOUCHSCREEN_ELO=m
+# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_MCS5000 is not set
+CONFIG_TOUCHSCREEN_MTOUCH=m
+CONFIG_TOUCHSCREEN_INEXIO=m
+# CONFIG_TOUCHSCREEN_MK712 is not set
+CONFIG_TOUCHSCREEN_HTCPEN=m
+CONFIG_TOUCHSCREEN_PENMOUNT=m
+CONFIG_TOUCHSCREEN_TOUCHRIGHT=m
+CONFIG_TOUCHSCREEN_TOUCHWIN=m
+# CONFIG_TOUCHSCREEN_WM97XX is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+CONFIG_TOUCHSCREEN_TOUCHIT213=m
+# CONFIG_TOUCHSCREEN_TSC2007 is not set
+# CONFIG_TOUCHSCREEN_W90X900 is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_ATI_REMOTE is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INPUT_CM109 is not set
+CONFIG_INPUT_UINPUT=m
+# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_CS is not set
+CONFIG_SERIAL_8250_NR_UARTS=7
+CONFIG_SERIAL_8250_RUNTIME_UARTS=7
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MAX3100 is not set
+# CONFIG_SERIAL_PXA is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=m
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_CARDMAN_4000 is not set
+# CONFIG_CARDMAN_4040 is not set
+# CONFIG_IPWIRELESS is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_HELPER_AUTO is not set
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=y
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_DESIGNWARE is not set
+CONFIG_I2C_GPIO=y
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_PXA=y
+# CONFIG_I2C_PXA_SLAVE is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_ELEKTOR is not set
+# CONFIG_I2C_PCA_ISA is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
+CONFIG_SPI_PXA2XX=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+CONFIG_GPIO_PCA953X=y
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
+
+#
+# AC97 GPIO expanders:
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Native drivers
+#
+# CONFIG_SENSORS_AD7414 is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADCXX is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7462 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7473 is not set
+# CONFIG_SENSORS_ADT7475 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_G760A is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 is not set
+CONFIG_SENSORS_LM75=m
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_LTC4215 is not set
+# CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_LM95241 is not set
+# CONFIG_SENSORS_MAX1111 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_SHT15 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
+# CONFIG_SENSORS_TMP421 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_SENSORS_LIS3_SPI is not set
+# CONFIG_THERMAL is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_SA1100_WATCHDOG is not set
+
+#
+# ISA-based Watchdog Cards
+#
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_WDT is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_UCB1400_CORE is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13783 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=m
+CONFIG_FB_CFB_COPYAREA=m
+CONFIG_FB_CFB_IMAGEBLIT=m
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_PXA=m
+# CONFIG_FB_PXA_OVERLAY is not set
+# CONFIG_FB_PXA_SMARTPANEL is not set
+CONFIG_FB_PXA_PARAMETERS=y
+# CONFIG_FB_MBX is not set
+# CONFIG_FB_W100 is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=m
+# CONFIG_LCD_LMS283GF05 is not set
+# CONFIG_LCD_LTV350QV is not set
+# CONFIG_LCD_ILI9320 is not set
+# CONFIG_LCD_TDO24M is not set
+# CONFIG_LCD_VGG2432A4 is not set
+# CONFIG_LCD_PLATFORM is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=m
+CONFIG_BACKLIGHT_GENERIC=m
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=m
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_SOUND=m
+CONFIG_SOUND_OSS_CORE=y
+CONFIG_SOUND_OSS_CORE_PRECLAIM=y
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_JACK=y
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+# CONFIG_SND_SUPPORT_OLD_API is not set
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+CONFIG_SND_VMASTER=y
+# CONFIG_SND_RAWMIDI_SEQ is not set
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
+CONFIG_SND_AC97_CODEC=m
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+# CONFIG_SND_AC97_POWER_SAVE is not set
+CONFIG_SND_ARM=y
+CONFIG_SND_PXA2XX_PCM=m
+CONFIG_SND_PXA2XX_LIB=m
+CONFIG_SND_PXA2XX_LIB_AC97=y
+CONFIG_SND_PXA2XX_AC97=m
+# CONFIG_SND_SPI is not set
+CONFIG_SND_USB=y
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_CAIAQ is not set
+# CONFIG_SND_PCMCIA is not set
+CONFIG_SND_SOC=m
+CONFIG_SND_PXA2XX_SOC=m
+CONFIG_SND_SOC_I2C_AND_SPI=m
+# CONFIG_SND_SOC_ALL_CODECS is not set
+# CONFIG_SOUND_PRIME is not set
+CONFIG_AC97_BUS=m
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_MON is not set
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_ACM=m
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+CONFIG_USB_SERIAL=m
+# CONFIG_USB_EZUSB is not set
+CONFIG_USB_SERIAL_GENERIC=y
+# CONFIG_USB_SERIAL_AIRCABLE is not set
+# CONFIG_USB_SERIAL_ARK3116 is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_CH341 is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_CP210X is not set
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_FUNSOFT is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+# CONFIG_USB_SERIAL_IPW is not set
+# CONFIG_USB_SERIAL_IUU is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+CONFIG_USB_SERIAL_MCT_U232=m
+# CONFIG_USB_SERIAL_MOS7720 is not set
+# CONFIG_USB_SERIAL_MOS7840 is not set
+# CONFIG_USB_SERIAL_MOTOROLA is not set
+# CONFIG_USB_SERIAL_NAVMAN is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_OTI6858 is not set
+# CONFIG_USB_SERIAL_QUALCOMM is not set
+# CONFIG_USB_SERIAL_SPCP8X5 is not set
+# CONFIG_USB_SERIAL_HP4X is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_SIEMENS_MPI is not set
+# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
+# CONFIG_USB_SERIAL_SYMBOL is not set
+# CONFIG_USB_SERIAL_TI is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OPTION is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_SERIAL_OPTICON is not set
+# CONFIG_USB_SERIAL_DEBUG is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+CONFIG_USB_GADGET=m
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_VBUS_DRAW=2
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_PXA25X is not set
+# CONFIG_USB_GADGET_R8A66597 is not set
+CONFIG_USB_GADGET_PXA27X=y
+CONFIG_USB_PXA27X=m
+# CONFIG_USB_GADGET_S3C_HSOTG is not set
+# CONFIG_USB_GADGET_IMX is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_FSL_QE is not set
+# CONFIG_USB_GADGET_CI13XXX is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LANGWELL is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_AUDIO is not set
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_ETH_EEM is not set
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+CONFIG_USB_G_SERIAL=m
+# CONFIG_USB_MIDI_GADGET is not set
+CONFIG_USB_G_PRINTER=m
+# CONFIG_USB_CDC_COMPOSITE is not set
+
+#
+# OTG and related infrastructure
+#
+CONFIG_USB_OTG_UTILS=y
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_NOP_USB_XCEIV is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+CONFIG_MMC_PXA=y
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_AT91 is not set
+# CONFIG_MMC_ATMELMCI is not set
+# CONFIG_MMC_SPI is not set
+# CONFIG_MEMSTICK is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=m
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_PCA9532 is not set
+CONFIG_LEDS_GPIO=m
+CONFIG_LEDS_GPIO_PLATFORM=y
+# CONFIG_LEDS_LP3944 is not set
+# CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_DAC124S085 is not set
+# CONFIG_LEDS_BD2802 is not set
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=m
+CONFIG_LEDS_TRIGGER_HEARTBEAT=m
+CONFIG_LEDS_TRIGGER_BACKLIGHT=m
+CONFIG_LEDS_TRIGGER_GPIO=m
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=m
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=m
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+CONFIG_RTC_DRV_ISL1208=m
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_MSM6242 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_RP5C01 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_SA1100 is not set
+CONFIG_RTC_DRV_PXA=m
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+# CONFIG_DNOTIFY is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+# CONFIG_MSDOS_FS is not set
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
+# CONFIG_NFSD_V4 is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=m
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=m
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+CONFIG_NLS_ISO8859_15=m
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=m
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+CONFIG_DEBUG_MEMORY_INIT=y
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+# CONFIG_PAGE_POISONING is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
+# CONFIG_BOOT_TRACER is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+CONFIG_ARM_UNWIND=y
+# CONFIG_DEBUG_USER is not set
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_LL is not set
+# CONFIG_OC_ETM is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_DEFAULT_SECURITY_SELINUX is not set
+# CONFIG_DEFAULT_SECURITY_SMACK is not set
+# CONFIG_DEFAULT_SECURITY_TOMOYO is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=m
+CONFIG_CRYPTO_ALGAPI2=m
+CONFIG_CRYPTO_AEAD2=m
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_BLKCIPHER2=m
+CONFIG_CRYPTO_HASH=m
+CONFIG_CRYPTO_HASH2=m
+CONFIG_CRYPTO_RNG2=m
+CONFIG_CRYPTO_PCOMP=m
+CONFIG_CRYPTO_MANAGER=m
+CONFIG_CRYPTO_MANAGER2=m
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_WORKQUEUE=m
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+CONFIG_CRYPTO_MICHAEL_MIC=m
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=m
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=m
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=m
+CONFIG_CRC_T10DIF=m
+CONFIG_CRC_ITU_T=m
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
index e7ccf7e697ce4c30bdb744f855fb2488284f7c59..dd00f747e2ad00aeb844dd6b8c8373dd34b2a853 100644 (file)
@@ -54,5 +54,6 @@ endif
 
 head-y                 := head$(MMUEXT).o
 obj-$(CONFIG_DEBUG_LL) += debug.o
+obj-$(CONFIG_EARLY_PRINTK)     += early_printk.o
 
 extra-y := $(head-y) init_task.o vmlinux.lds
diff --git a/arch/arm/kernel/early_printk.c b/arch/arm/kernel/early_printk.c
new file mode 100644 (file)
index 0000000..85aa2b2
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ *  linux/arch/arm/kernel/early_printk.c
+ *
+ *  Copyright (C) 2009 Sascha Hauer <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/kernel.h>
+#include <linux/console.h>
+#include <linux/init.h>
+
+extern void printch(int);
+
+static void early_write(const char *s, unsigned n)
+{
+       while (n-- > 0) {
+               if (*s == '\n')
+                       printch('\r');
+               printch(*s);
+               s++;
+       }
+}
+
+static void early_console_write(struct console *con, const char *s, unsigned n)
+{
+       early_write(s, n);
+}
+
+static struct console early_console = {
+       .name =         "earlycon",
+       .write =        early_console_write,
+       .flags =        CON_PRINTBUFFER | CON_BOOT,
+       .index =        -1,
+};
+
+asmlinkage void early_printk(const char *fmt, ...)
+{
+       char buf[512];
+       int n;
+       va_list ap;
+
+       va_start(ap, fmt);
+       n = vscnprintf(buf, sizeof(buf), fmt, ap);
+       early_write(buf, n);
+       va_end(ap);
+}
+
+static int __init setup_early_printk(char *buf)
+{
+       register_console(&early_console);
+       return 0;
+}
+
+early_param("earlyprintk", setup_early_printk);
index a73a34dccf2a6de247f20bb5fc4e9622b03561a1..ea02a7b1c244af0afd610f6fc00c7f836f72ae4d 100644 (file)
@@ -160,6 +160,7 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk)
 
        /* Make sure our local interrupt controller has this enabled */
        local_irq_save(flags);
+       irq_to_desc(clk->irq)->status |= IRQ_NOPROBE;
        get_irq_chip(clk->irq)->unmask(clk->irq);
        local_irq_restore(flags);
 
index e522b20bcbc25efcd17f4976c0544ea43252b57d..f70d52be48a2a61c88b7276a830b7b3abf17aee5 100644 (file)
@@ -30,6 +30,8 @@
 
 #define __virt_to_bus(x)       ((x) - PAGE_OFFSET)
 #define __bus_to_virt(x)       ((x) + PAGE_OFFSET)
+#define __pfn_to_bus(x)                (__pfn_to_phys(x) - PHYS_OFFSET)
+#define __bus_to_pfn(x)                __phys_to_pfn((x) + PHYS_OFFSET)
 
 #endif
 
index b97f529e58e8455016f675d965f2cc568fda1b2e..41febc796b1c7e1564684eccc910516568fb54ad 100644 (file)
@@ -201,6 +201,11 @@ void __init footbridge_map_io(void)
 
 #ifdef CONFIG_FOOTBRIDGE_ADDIN
 
+static inline unsigned long fb_bus_sdram_offset(void)
+{
+       return *CSR_PCISDRAMBASE & 0xfffffff0;
+}
+
 /*
  * These two functions convert virtual addresses to PCI addresses and PCI
  * addresses to virtual addresses.  Note that it is only legal to use these
@@ -210,14 +215,13 @@ unsigned long __virt_to_bus(unsigned long res)
 {
        WARN_ON(res < PAGE_OFFSET || res >= (unsigned long)high_memory);
 
-       return (res - PAGE_OFFSET) + (*CSR_PCISDRAMBASE & 0xfffffff0);
+       return res + (fb_bus_sdram_offset() - PAGE_OFFSET);
 }
 EXPORT_SYMBOL(__virt_to_bus);
 
 unsigned long __bus_to_virt(unsigned long res)
 {
-       res -= (*CSR_PCISDRAMBASE & 0xfffffff0);
-       res += PAGE_OFFSET;
+       res = res - (fb_bus_sdram_offset() - PAGE_OFFSET);
 
        WARN_ON(res < PAGE_OFFSET || res >= (unsigned long)high_memory);
 
@@ -225,4 +229,16 @@ unsigned long __bus_to_virt(unsigned long res)
 }
 EXPORT_SYMBOL(__bus_to_virt);
 
+unsigned long __pfn_to_bus(unsigned long pfn)
+{
+       return __pfn_to_phys(pfn) + (fb_bus_sdram_offset() - PHYS_OFFSET));
+}
+EXPORT_SYMBOL(__pfn_to_bus);
+
+unsigned long __bus_to_pfn(unsigned long bus)
+{
+       return __phys_to_pfn(bus - (fb_bus_sdram_offset() - PHYS_OFFSET));
+}
+EXPORT_SYMBOL(__bus_to_pfn);
+
 #endif
index cb16e59d87b63c81f807b67c65b013fa7c11e763..8d64f45740873e419c62f8547031322c1894836a 100644 (file)
@@ -29,6 +29,8 @@
 #ifndef __ASSEMBLY__
 extern unsigned long __virt_to_bus(unsigned long);
 extern unsigned long __bus_to_virt(unsigned long);
+extern unsigned long __pfn_to_bus(unsigned long);
+extern unsigned long __bus_to_pfn(unsigned long);
 #endif
 #define __virt_to_bus  __virt_to_bus
 #define __bus_to_virt  __bus_to_virt
@@ -36,14 +38,15 @@ extern unsigned long __bus_to_virt(unsigned long);
 #elif defined(CONFIG_FOOTBRIDGE_HOST)
 
 /*
- * The footbridge is programmed to expose the system RAM at the corresponding
- * address.  So, if PAGE_OFFSET is 0xc0000000, RAM appears at 0xe0000000.
- * If 0x80000000, then its exposed at 0xa0000000 on the bus. etc.
- * The only requirement is that the RAM isn't placed at bus address 0 which
+ * The footbridge is programmed to expose the system RAM at 0xe0000000.
+ * The requirement is that the RAM isn't placed at bus address 0, which
  * would clash with VGA cards.
  */
-#define __virt_to_bus(x)       ((x) - 0xe0000000)
-#define __bus_to_virt(x)       ((x) + 0xe0000000)
+#define BUS_OFFSET             0xe0000000
+#define __virt_to_bus(x)       ((x) + (BUS_OFFSET - PAGE_OFFSET))
+#define __bus_to_virt(x)       ((x) - (BUS_OFFSET - PAGE_OFFSET))
+#define __pfn_to_bus(x)                (__pfn_to_phys(x) + (BUS_OFFSET - PHYS_OFFSET))
+#define __bus_to_pfn(x)                __phys_to_pfn((x) - (BUS_OFFSET - PHYS_OFFSET))
 
 #else
 
index 4891828454f5fdca8c72f5146633e2e5a362c204..991f24d2c1150d0ee72b0341be967715ed0361bb 100644 (file)
@@ -28,6 +28,7 @@
 #define BUS_OFFSET     UL(0x80000000)
 #define __virt_to_bus(x)       ((x) - PAGE_OFFSET + BUS_OFFSET)
 #define __bus_to_virt(x)       ((x) - BUS_OFFSET + PAGE_OFFSET)
-#define __pfn_to_bus(x)                (((x) << PAGE_SHIFT) + BUS_OFFSET)
+#define __pfn_to_bus(x)                (__pfn_to_phys(x) + (BUS_OFFSET - PHYS_OFFSET))
+#define __bus_to_pfn(x)                __phys_to_pfn((x) - (BUS_OFFSET - PHYS_OFFSET))
 
 #endif
index aee7eb8a71b24eb7d8580534551866c5c068efaf..98e3471be15bc28081987de78700720ac9f04ed6 100644 (file)
 
 #include <mach/ixp2000-regs.h>
 
-#define __virt_to_bus(v) \
-       (((__virt_to_phys(v) - 0x0) + (*IXP2000_PCI_SDRAM_BAR & 0xfffffff0)))
+#define IXP2000_PCI_SDRAM_OFFSET       (*IXP2000_PCI_SDRAM_BAR & 0xfffffff0)
 
-#define __bus_to_virt(b) \
-       __phys_to_virt((((b - (*IXP2000_PCI_SDRAM_BAR & 0xfffffff0)) + 0x0)))
+#define __phys_to_bus(x)       ((x) + (IXP2000_PCI_SDRAM_OFFSET - PHYS_OFFSET))
+#define __bus_to_phys(x)       ((x) - (IXP2000_PCI_SDRAM_OFFSET - PHYS_OFFSET))
+
+#define __virt_to_bus(v)       __phys_to_bus(__virt_to_phys(v))
+#define __bus_to_virt(b)       __phys_to_virt(__bus_to_phys(b))
+#define __pfn_to_bus(p)                __phys_to_bus(__pfn_to_phys(p))
+#define __bus_to_pfn(b)                __phys_to_pfn(__bus_to_phys(b))
 
 #endif
 
index fdd138706c704f7b0e72264f2a60248e94f0f0f6..94a3a86cfeb8be7ae854aa26162e33c7796683d0 100644 (file)
  */
 #define PHYS_OFFSET            (0x00000000)
 
-#define __virt_to_bus(v)                                               \
-       ({ unsigned int ret;                                            \
-       ret = ((__virt_to_phys(v) - 0x00000000) +                       \
-        (*((volatile int *)IXP23XX_PCI_SDRAM_BAR) & 0xfffffff0));      \
-       ret; })
-
-#define __bus_to_virt(b)                                               \
-       ({ unsigned int data;                                           \
-       data = *((volatile int *)IXP23XX_PCI_SDRAM_BAR);                \
-        __phys_to_virt((((b - (data & 0xfffffff0)) + 0x00000000))); })
+#define IXP23XX_PCI_SDRAM_OFFSET (*((volatile int *)IXP23XX_PCI_SDRAM_BAR) & 0xfffffff0))
+
+#define __phys_to_bus(x)       ((x) + (IXP23XX_PCI_SDRAM_OFFSET - PHYS_OFFSET))
+#define __bus_to_phys(x)       ((x) - (IXP23XX_PCI_SDRAM_OFFSET - PHYS_OFFSET))
+
+#define __virt_to_bus(v)       __phys_to_bus(__virt_to_phys(v))
+#define __bus_to_virt(b)       __phys_to_virt(__bus_to_phys(b))
+#define __pfn_to_bus(p)                __phys_to_bus(__pfn_to_phys(p))
+#define __bus_to_pfn(b)                __phys_to_pfn(__bus_to_phys(b))
 
 #define arch_is_coherent()     1
 
index 6182f5410b4de466a88b6da43f72050463363411..fcaf876f19b6617dc25495885a933cae0b2baee0 100644 (file)
@@ -7,8 +7,6 @@
  *  version 2 as published by the Free Software Foundation.
  *
  */
-
-#include <linux/cpufreq.h>
 #include <mach/hardware.h>
 #include <mach/clocks.h>
 #include <linux/err.h>
@@ -31,12 +29,6 @@ struct clk {
 #define HCLKDIV(c)     (((c) >>  0) & 0x02)
 #define PCLKDIV(c)     (((c) >> 16) & 0x03)
 
-unsigned int cpufreq_get (unsigned int cpu) /* in kHz */
-{
-       return fclkfreq_get ()/1000;
-}
-EXPORT_SYMBOL(cpufreq_get);
-
 unsigned int fclkfreq_get (void)
 {
        unsigned int clkset = CSC_CLKSET;
index db9374bc528b588f8b51545dd8e686d4c10bef00..e508904fb67e3addfe4066f44860e6ecd737afd8 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/delay.h>
-#include <linux/i2c/twl4030.h>
+#include <linux/i2c/twl.h>
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/io.h>
index 4cfb7b68dfadc574181e4884dfb493b923abd263..c90b0d0b1927e58911dad6d7bfe593b712323557 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/input/matrix_keypad.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
-#include <linux/i2c/twl4030.h>
+#include <linux/i2c/twl.h>
 #include <linux/regulator/machine.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
index 37431738f1c2a40632b024f70e4b3cbd70cc133b..995d4a2b2dfd5fa61c7337ee350d1e0e60b5f000 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
 #include <linux/regulator/machine.h>
-#include <linux/i2c/twl4030.h>
+#include <linux/i2c/twl.h>
 #include <linux/io.h>
 #include <linux/smsc911x.h>
 
index 6ada8029f9a8bb605e797295f5e0e6091bfb4a86..231cb4ec1847cfd51c038e2d533c7f40ae9d1295 100644 (file)
@@ -29,7 +29,7 @@
 #include <linux/mtd/nand.h>
 
 #include <linux/regulator/machine.h>
-#include <linux/i2c/twl4030.h>
+#include <linux/i2c/twl.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
index 6f6c601eeab7c1ecbdd12dc88c77ec853248f372..ef17cf1ab6d7cc37b132a30d3b443ea4e93f9bf0 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
 #include <linux/regulator/machine.h>
-#include <linux/i2c/twl4030.h>
+#include <linux/i2c/twl.h>
 #include <linux/leds.h>
 #include <linux/input.h>
 #include <linux/input/matrix_keypad.h>
index 5b78a87217e056754ccd08a0f3c7bd7280cf9448..d192dd98a591779ac126fdf3c3ab0fbb2b489f51 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
-#include <linux/i2c/twl4030.h>
+#include <linux/i2c/twl.h>
 #include <linux/regulator/machine.h>
 
 #include <linux/mtd/mtd.h>
index bf26ad31f9ba59eda3002eaa2e2d4bcf307fbb45..17f3c91231dbfb066725d730984b2e99dc9f1b1d 100644 (file)
@@ -402,15 +402,9 @@ static struct twl4030_usb_data rx51_usb_data = {
 
 static struct twl4030_ins sleep_on_seq[] __initdata = {
 /*
- * Turn off VDD1 and VDD2.
+ * Turn off everything
  */
-       {MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_OFF), 4},
-       {MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_OFF), 2},
-/*
- * And also turn off the OMAP3 PLLs and the sysclk output.
- */
-       {MSG_SINGULAR(DEV_GRP_P1, 0x7, RES_STATE_OFF), 3},
-       {MSG_SINGULAR(DEV_GRP_P1, 0x17, RES_STATE_OFF), 3},
+       {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, 1, 0, RES_STATE_SLEEP), 2},
 };
 
 static struct twl4030_script sleep_on_script __initdata = {
@@ -421,14 +415,9 @@ static struct twl4030_script sleep_on_script __initdata = {
 
 static struct twl4030_ins wakeup_seq[] __initdata = {
 /*
- * Reenable the OMAP3 PLLs.
- * Wakeup VDD1 and VDD2.
- * Reenable sysclk output.
+ * Reenable everything
  */
-       {MSG_SINGULAR(DEV_GRP_P1, 0x7, RES_STATE_ACTIVE), 0x30},
-       {MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_ACTIVE), 0x30},
-       {MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_ACTIVE), 0x37},
-       {MSG_SINGULAR(DEV_GRP_P1, 0x19, RES_STATE_ACTIVE), 3},
+       {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, 1, 0, RES_STATE_ACTIVE), 2},
 };
 
 static struct twl4030_script wakeup_script __initdata = {
@@ -439,10 +428,9 @@ static struct twl4030_script wakeup_script __initdata = {
 
 static struct twl4030_ins wakeup_p3_seq[] __initdata = {
 /*
- * Wakeup VDD1 (dummy to be able to insert a delay)
- * Enable CLKEN
+ * Reenable everything
  */
-       {MSG_SINGULAR(DEV_GRP_P1, 0x17, RES_STATE_ACTIVE), 3},
+       {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, 1, 0, RES_STATE_ACTIVE), 2},
 };
 
 static struct twl4030_script wakeup_p3_script __initdata = {
@@ -463,12 +451,11 @@ static struct twl4030_ins wrst_seq[] __initdata = {
        {MSG_SINGULAR(DEV_GRP_NULL, RES_RESET, RES_STATE_OFF), 2},
        {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, 0, 1, RES_STATE_ACTIVE),
                0x13},
-       {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_PP, 0, 2, RES_STATE_WRST), 0x13},
        {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_PP, 0, 3, RES_STATE_OFF), 0x13},
        {MSG_SINGULAR(DEV_GRP_NULL, RES_VDD1, RES_STATE_WRST), 0x13},
        {MSG_SINGULAR(DEV_GRP_NULL, RES_VDD2, RES_STATE_WRST), 0x13},
        {MSG_SINGULAR(DEV_GRP_NULL, RES_VPLL1, RES_STATE_WRST), 0x35},
-       {MSG_SINGULAR(DEV_GRP_P1, RES_HFCLKOUT, RES_STATE_ACTIVE), 2},
+       {MSG_SINGULAR(DEV_GRP_P3, RES_HFCLKOUT, RES_STATE_ACTIVE), 2},
        {MSG_SINGULAR(DEV_GRP_NULL, RES_RESET, RES_STATE_ACTIVE), 2},
 };
 
@@ -490,22 +477,81 @@ static struct twl4030_script *twl4030_scripts[] __initdata = {
 };
 
 static struct twl4030_resconfig twl4030_rconfig[] __initdata = {
-       { .resource = RES_VINTANA1, .devgroup = -1, .type = -1, .type2 = 1 },
-       { .resource = RES_VINTANA2, .devgroup = -1, .type = -1, .type2 = 1 },
-       { .resource = RES_VINTDIG, .devgroup = -1, .type = -1, .type2 = 1 },
-       { .resource = RES_VMMC1, .devgroup = -1, .type = -1, .type2 = 3},
-       { .resource = RES_VMMC2, .devgroup = DEV_GRP_NULL, .type = -1,
-         .type2 = 3},
-       { .resource = RES_VAUX1, .devgroup = -1, .type = -1, .type2 = 3},
-       { .resource = RES_VAUX2, .devgroup = -1, .type = -1, .type2 = 3},
-       { .resource = RES_VAUX3, .devgroup = -1, .type = -1, .type2 = 3},
-       { .resource = RES_VAUX4, .devgroup = -1, .type = -1, .type2 = 3},
-       { .resource = RES_VPLL2, .devgroup = -1, .type = -1, .type2 = 3},
-       { .resource = RES_VDAC, .devgroup = -1, .type = -1, .type2 = 3},
-       { .resource = RES_VSIM, .devgroup = DEV_GRP_NULL, .type = -1,
-         .type2 = 3},
-       { .resource = RES_CLKEN, .devgroup = DEV_GRP_P3, .type = -1,
-               .type2 = 1 },
+       { .resource = RES_VDD1, .devgroup = -1,
+         .type = 1, .type2 = -1, .remap_off = RES_STATE_OFF,
+         .remap_sleep = RES_STATE_OFF
+       },
+       { .resource = RES_VDD2, .devgroup = -1,
+         .type = 1, .type2 = -1, .remap_off = RES_STATE_OFF,
+         .remap_sleep = RES_STATE_OFF
+       },
+       { .resource = RES_VPLL1, .devgroup = -1,
+         .type = 1, .type2 = -1, .remap_off = RES_STATE_OFF,
+         .remap_sleep = RES_STATE_OFF
+       },
+       { .resource = RES_VPLL2, .devgroup = -1,
+         .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
+       },
+       { .resource = RES_VAUX1, .devgroup = -1,
+         .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
+       },
+       { .resource = RES_VAUX2, .devgroup = -1,
+         .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
+       },
+       { .resource = RES_VAUX3, .devgroup = -1,
+         .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
+       },
+       { .resource = RES_VAUX4, .devgroup = -1,
+         .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
+       },
+       { .resource = RES_VMMC1, .devgroup = -1,
+         .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
+       },
+       { .resource = RES_VMMC2, .devgroup = -1,
+         .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
+       },
+       { .resource = RES_VDAC, .devgroup = -1,
+         .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
+       },
+       { .resource = RES_VSIM, .devgroup = -1,
+         .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
+       },
+       { .resource = RES_VINTANA1, .devgroup = DEV_GRP_P1 | DEV_GRP_P3,
+         .type = -1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
+       },
+       { .resource = RES_VINTANA2, .devgroup = DEV_GRP_P1 | DEV_GRP_P3,
+         .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
+       },
+       { .resource = RES_VINTDIG, .devgroup = DEV_GRP_P1 | DEV_GRP_P3,
+         .type = -1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
+       },
+       { .resource = RES_VIO, .devgroup = DEV_GRP_P3,
+         .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
+       },
+       { .resource = RES_CLKEN, .devgroup = DEV_GRP_P1 | DEV_GRP_P3,
+         .type = 1, .type2 = -1 , .remap_off = -1, .remap_sleep = -1
+       },
+       { .resource = RES_REGEN, .devgroup = DEV_GRP_P1 | DEV_GRP_P3,
+         .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
+       },
+       { .resource = RES_NRES_PWRON, .devgroup = DEV_GRP_P1 | DEV_GRP_P3,
+         .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
+       },
+       { .resource = RES_SYSEN, .devgroup = DEV_GRP_P1 | DEV_GRP_P3,
+         .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
+       },
+       { .resource = RES_HFCLKOUT, .devgroup = DEV_GRP_P3,
+         .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
+       },
+       { .resource = RES_32KCLKOUT, .devgroup = -1,
+         .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
+       },
+       { .resource = RES_RESET, .devgroup = -1,
+         .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
+       },
+       { .resource = RES_Main_Ref, .devgroup = -1,
+         .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
+       },
        { 0, 0},
 };
 
index d89c6adbe8bc44a3434a43bd0253716be0340c54..e6d8e10ae5d1fe74c8e8b17414a325c69a763f6c 100644 (file)
@@ -63,6 +63,15 @@ config ARCH_VIPER
        select HAVE_PWM
        select PXA_HAVE_BOARD_IRQS
        select PXA_HAVE_ISA_IRQS
+       select ARCOM_PCMCIA
+
+config MACH_ARCOM_ZEUS
+       bool "Arcom/Eurotech ZEUS SBC"
+       select PXA27x
+       select ISA
+       select PXA_HAVE_BOARD_IRQS
+       select PXA_HAVE_ISA_IRQS
+       select ARCOM_PCMCIA
 
 config MACH_BALLOON3
        bool "Balloon 3 board"
@@ -179,6 +188,11 @@ config MACH_TRIZEPS_ANY
 
 endchoice
 
+config ARCOM_PCMCIA
+       bool
+       help
+         Generic option for Arcom Viper/Zeus PCMCIA
+
 config TRIZEPS_PCMCIA
        bool
        help
index b5d29e60a3412b6f0abbbdfa8a584d2d4a53c69e..f64afda7e6f6323c65ddbffa13ddc7c3370959e8 100644 (file)
@@ -38,6 +38,7 @@ obj-$(CONFIG_MACH_SAAR)               += saar.o
 # 3rd Party Dev Platforms
 obj-$(CONFIG_ARCH_PXA_IDP)     += idp.o
 obj-$(CONFIG_ARCH_VIPER)       += viper.o
+obj-$(CONFIG_MACH_ARCOM_ZEUS)  += zeus.o
 obj-$(CONFIG_MACH_BALLOON3)    += balloon3.o
 obj-$(CONFIG_MACH_CSB726)      += csb726.o
 obj-$(CONFIG_CSB726_CSB701)    += csb701.o
index 1c0de808b54d456e9c780146efc26b2168e0a85f..c8a01bc85fdefe2452e9acb74ad590a05953831d 100644 (file)
@@ -497,16 +497,15 @@ static int em_x270_usb_hub_init(void)
                goto err_free_vbus_gpio;
 
        /* USB Hub power-on and reset */
-       gpio_direction_output(usb_hub_reset, 0);
+       gpio_direction_output(usb_hub_reset, 1);
+       gpio_direction_output(GPIO9_USB_VBUS_EN, 0);
        regulator_enable(em_x270_usb_ldo);
-       gpio_set_value(usb_hub_reset, 1);
        gpio_set_value(usb_hub_reset, 0);
+       gpio_set_value(usb_hub_reset, 1);
        regulator_disable(em_x270_usb_ldo);
        regulator_enable(em_x270_usb_ldo);
-       gpio_set_value(usb_hub_reset, 1);
-
-       /* enable VBUS */
-       gpio_direction_output(GPIO9_USB_VBUS_EN, 1);
+       gpio_set_value(usb_hub_reset, 0);
+       gpio_set_value(GPIO9_USB_VBUS_EN, 1);
 
        return 0;
 
diff --git a/arch/arm/mach-pxa/include/mach/arcom-pcmcia.h b/arch/arm/mach-pxa/include/mach/arcom-pcmcia.h
new file mode 100644 (file)
index 0000000..d428be4
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef __ARCOM_PCMCIA_H
+#define __ARCOM_PCMCIA_H
+
+struct arcom_pcmcia_pdata {
+       int     cd_gpio;
+       int     rdy_gpio;
+       int     pwr_gpio;
+       void    (*reset)(int state);
+};
+
+#endif
index 10988c270ca3270aab82dd8af321332c63125e71..5f5fbf1f648944b0768fee4278611b21505f06b8 100644 (file)
@@ -85,8 +85,6 @@
 /* Interrupt and Configuration Register (VIPER_ICR) */
 /* This is a write only register. Only CF_RST is used under Linux */
 
-extern void viper_cf_rst(int state);
-
 #define VIPER_ICR_RETRIG       (1 << 0)
 #define VIPER_ICR_AUTO_CLR     (1 << 1)
 #define VIPER_ICR_R_DIS                (1 << 2)
diff --git a/arch/arm/mach-pxa/include/mach/zeus.h b/arch/arm/mach-pxa/include/mach/zeus.h
new file mode 100644 (file)
index 0000000..c387046
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ *  arch/arm/mach-pxa/include/mach/zeus.h
+ *
+ *  Author:    David Vrabel
+ *  Created:   Sept 28, 2005
+ *  Copyright: Arcom Control Systems Ltd.
+ *
+ *  Maintained by: Marc Zyngier <maz@misterjones.org>
+ *
+ * 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 _MACH_ZEUS_H
+#define _MACH_ZEUS_H
+
+/* Physical addresses */
+#define ZEUS_FLASH_PHYS                PXA_CS0_PHYS
+#define ZEUS_ETH0_PHYS         PXA_CS1_PHYS
+#define ZEUS_ETH1_PHYS         PXA_CS2_PHYS
+#define ZEUS_CPLD_PHYS         (PXA_CS4_PHYS+0x2000000)
+#define ZEUS_SRAM_PHYS         PXA_CS5_PHYS
+#define ZEUS_PC104IO_PHYS      (0x30000000)
+
+#define ZEUS_CPLD_VERSION_PHYS (ZEUS_CPLD_PHYS + 0x00000000)
+#define ZEUS_CPLD_ISA_IRQ_PHYS (ZEUS_CPLD_PHYS + 0x00800000)
+#define ZEUS_CPLD_CONTROL_PHYS (ZEUS_CPLD_PHYS + 0x01000000)
+#define ZEUS_CPLD_EXTWDOG_PHYS (ZEUS_CPLD_PHYS + 0x01800000)
+
+/* GPIOs */
+#define ZEUS_AC97_GPIO         0
+#define ZEUS_WAKEUP_GPIO       1
+#define ZEUS_UARTA_GPIO                9
+#define ZEUS_UARTB_GPIO                10
+#define ZEUS_UARTC_GPIO                12
+#define ZEUS_UARTD_GPIO                11
+#define ZEUS_ETH0_GPIO         14
+#define ZEUS_ISA_GPIO          17
+#define ZEUS_BKLEN_GPIO                19
+#define ZEUS_USB2_PWREN_GPIO   22
+#define ZEUS_PTT_GPIO          27
+#define ZEUS_CF_CD_GPIO         35
+#define ZEUS_MMC_WP_GPIO        52
+#define ZEUS_MMC_CD_GPIO        53
+#define ZEUS_EXTGPIO_GPIO      91
+#define ZEUS_CF_PWEN_GPIO       97
+#define ZEUS_CF_RDY_GPIO        99
+#define ZEUS_LCD_EN_GPIO       101
+#define ZEUS_ETH1_GPIO         113
+#define ZEUS_CAN_GPIO          116
+
+#define ZEUS_EXT0_GPIO_BASE    128
+#define ZEUS_EXT1_GPIO_BASE    160
+#define ZEUS_USER_GPIO_BASE    192
+
+#define ZEUS_EXT0_GPIO(x)      (ZEUS_EXT0_GPIO_BASE + (x))
+#define ZEUS_EXT1_GPIO(x)      (ZEUS_EXT1_GPIO_BASE + (x))
+#define ZEUS_USER_GPIO(x)      (ZEUS_USER_GPIO_BASE + (x))
+
+/*
+ * CPLD registers:
+ * Only 4 registers, but spreaded over a 32MB address space.
+ * Be gentle, and remap that over 32kB...
+ */
+
+#define ZEUS_CPLD              (0xf0000000)
+#define ZEUS_CPLD_VERSION      (ZEUS_CPLD + 0x0000)
+#define ZEUS_CPLD_ISA_IRQ      (ZEUS_CPLD + 0x1000)
+#define ZEUS_CPLD_CONTROL      (ZEUS_CPLD + 0x2000)
+#define ZEUS_CPLD_EXTWDOG      (ZEUS_CPLD + 0x3000)
+
+/* CPLD register bits */
+#define ZEUS_CPLD_CONTROL_CF_RST        0x01
+
+#define ZEUS_PC104IO           (0xf1000000)
+
+#define ZEUS_SRAM_SIZE         (256 * 1024)
+
+#endif
+
+
index cf0d71b7797e09427f9339137e57a58575df31e6..5352b4e5a7dda117cad09368339733f3fef9e106 100644 (file)
@@ -47,6 +47,7 @@
 #include <mach/pxafb.h>
 #include <plat/i2c.h>
 #include <mach/regs-uart.h>
+#include <mach/arcom-pcmcia.h>
 #include <mach/viper.h>
 
 #include <asm/setup.h>
@@ -76,14 +77,28 @@ static void viper_icr_clear_bit(unsigned int bit)
 }
 
 /* This function is used from the pcmcia module to reset the CF */
-void viper_cf_rst(int state)
+static void viper_cf_reset(int state)
 {
        if (state)
                viper_icr_set_bit(VIPER_ICR_CF_RST);
        else
                viper_icr_clear_bit(VIPER_ICR_CF_RST);
 }
-EXPORT_SYMBOL(viper_cf_rst);
+
+static struct arcom_pcmcia_pdata viper_pcmcia_info = {
+       .cd_gpio        = VIPER_CF_CD_GPIO,
+       .rdy_gpio       = VIPER_CF_RDY_GPIO,
+       .pwr_gpio       = VIPER_CF_POWER_GPIO,
+       .reset          = viper_cf_reset,
+};
+
+static struct platform_device viper_pcmcia_device = {
+       .name           = "viper-pcmcia",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &viper_pcmcia_info,
+       },
+};
 
 /*
  * The CPLD version register was not present on VIPER boards prior to
@@ -685,6 +700,7 @@ static struct platform_device *viper_devs[] __initdata = {
        &viper_mtd_devices[0],
        &viper_mtd_devices[1],
        &viper_backlight_device,
+       &viper_pcmcia_device,
 };
 
 static mfp_cfg_t viper_pin_config[] __initdata = {
diff --git a/arch/arm/mach-pxa/zeus.c b/arch/arm/mach-pxa/zeus.c
new file mode 100644 (file)
index 0000000..5b986a8
--- /dev/null
@@ -0,0 +1,820 @@
+/*
+ *  Support for the Arcom ZEUS.
+ *
+ *  Copyright (C) 2006 Arcom Control Systems Ltd.
+ *
+ *  Loosely based on Arcom's 2.6.16.28.
+ *  Maintained by Marc Zyngier <maz@misterjones.org>
+ *
+ *  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/cpufreq.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/pm.h>
+#include <linux/gpio.h>
+#include <linux/serial_8250.h>
+#include <linux/dm9000.h>
+#include <linux/mmc/host.h>
+#include <linux/spi/spi.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/i2c.h>
+#include <linux/i2c/pca953x.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <plat/i2c.h>
+
+#include <mach/pxa2xx-regs.h>
+#include <mach/regs-uart.h>
+#include <mach/ohci.h>
+#include <mach/mmc.h>
+#include <mach/pxa27x-udc.h>
+#include <mach/udc.h>
+#include <mach/pxafb.h>
+#include <mach/pxa2xx_spi.h>
+#include <mach/mfp-pxa27x.h>
+#include <mach/pm.h>
+#include <mach/audio.h>
+#include <mach/arcom-pcmcia.h>
+#include <mach/zeus.h>
+
+#include "generic.h"
+
+/*
+ * Interrupt handling
+ */
+
+static unsigned long zeus_irq_enabled_mask;
+static const int zeus_isa_irqs[] = { 3, 4, 5, 6, 7, 10, 11, 12, };
+static const int zeus_isa_irq_map[] = {
+       0,              /* ISA irq #0, invalid */
+       0,              /* ISA irq #1, invalid */
+       0,              /* ISA irq #2, invalid */
+       1 << 0,         /* ISA irq #3 */
+       1 << 1,         /* ISA irq #4 */
+       1 << 2,         /* ISA irq #5 */
+       1 << 3,         /* ISA irq #6 */
+       1 << 4,         /* ISA irq #7 */
+       0,              /* ISA irq #8, invalid */
+       0,              /* ISA irq #9, invalid */
+       1 << 5,         /* ISA irq #10 */
+       1 << 6,         /* ISA irq #11 */
+       1 << 7,         /* ISA irq #12 */
+};
+
+static inline int zeus_irq_to_bitmask(unsigned int irq)
+{
+       return zeus_isa_irq_map[irq - PXA_ISA_IRQ(0)];
+}
+
+static inline int zeus_bit_to_irq(int bit)
+{
+       return zeus_isa_irqs[bit] + PXA_ISA_IRQ(0);
+}
+
+static void zeus_ack_irq(unsigned int irq)
+{
+       __raw_writew(zeus_irq_to_bitmask(irq), ZEUS_CPLD_ISA_IRQ);
+}
+
+static void zeus_mask_irq(unsigned int irq)
+{
+       zeus_irq_enabled_mask &= ~(zeus_irq_to_bitmask(irq));
+}
+
+static void zeus_unmask_irq(unsigned int irq)
+{
+       zeus_irq_enabled_mask |= zeus_irq_to_bitmask(irq);
+}
+
+static inline unsigned long zeus_irq_pending(void)
+{
+       return __raw_readw(ZEUS_CPLD_ISA_IRQ) & zeus_irq_enabled_mask;
+}
+
+static void zeus_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+       unsigned long pending;
+
+       pending = zeus_irq_pending();
+       do {
+               /* we're in a chained irq handler,
+                * so ack the interrupt by hand */
+               desc->chip->ack(gpio_to_irq(ZEUS_ISA_GPIO));
+
+               if (likely(pending)) {
+                       irq = zeus_bit_to_irq(__ffs(pending));
+                       generic_handle_irq(irq);
+               }
+               pending = zeus_irq_pending();
+       } while (pending);
+}
+
+static struct irq_chip zeus_irq_chip = {
+       .name   = "ISA",
+       .ack    = zeus_ack_irq,
+       .mask   = zeus_mask_irq,
+       .unmask = zeus_unmask_irq,
+};
+
+static void __init zeus_init_irq(void)
+{
+       int level;
+       int isa_irq;
+
+       pxa27x_init_irq();
+
+       /* Peripheral IRQs. It would be nice to move those inside driver
+          configuration, but it is not supported at the moment. */
+       set_irq_type(gpio_to_irq(ZEUS_AC97_GPIO),       IRQ_TYPE_EDGE_RISING);
+       set_irq_type(gpio_to_irq(ZEUS_WAKEUP_GPIO),     IRQ_TYPE_EDGE_RISING);
+       set_irq_type(gpio_to_irq(ZEUS_PTT_GPIO),        IRQ_TYPE_EDGE_RISING);
+       set_irq_type(gpio_to_irq(ZEUS_EXTGPIO_GPIO),    IRQ_TYPE_EDGE_FALLING);
+       set_irq_type(gpio_to_irq(ZEUS_CAN_GPIO),        IRQ_TYPE_EDGE_FALLING);
+
+       /* Setup ISA IRQs */
+       for (level = 0; level < ARRAY_SIZE(zeus_isa_irqs); level++) {
+               isa_irq = zeus_bit_to_irq(level);
+               set_irq_chip(isa_irq, &zeus_irq_chip);
+               set_irq_handler(isa_irq, handle_edge_irq);
+               set_irq_flags(isa_irq, IRQF_VALID | IRQF_PROBE);
+       }
+
+       set_irq_type(gpio_to_irq(ZEUS_ISA_GPIO), IRQ_TYPE_EDGE_RISING);
+       set_irq_chained_handler(gpio_to_irq(ZEUS_ISA_GPIO), zeus_irq_handler);
+}
+
+
+/*
+ * Platform devices
+ */
+
+/* Flash */
+static struct resource zeus_mtd_resources[] = {
+       [0] = { /* NOR Flash (up to 64MB) */
+               .start  = ZEUS_FLASH_PHYS,
+               .end    = ZEUS_FLASH_PHYS + SZ_64M - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = { /* SRAM */
+               .start  = ZEUS_SRAM_PHYS,
+               .end    = ZEUS_SRAM_PHYS + SZ_512K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct physmap_flash_data zeus_flash_data[] = {
+       [0] = {
+               .width          = 2,
+               .parts          = NULL,
+               .nr_parts       = 0,
+       },
+};
+
+static struct platform_device zeus_mtd_devices[] = {
+       [0] = {
+               .name           = "physmap-flash",
+               .id             = 0,
+               .dev            = {
+                       .platform_data = &zeus_flash_data[0],
+               },
+               .resource       = &zeus_mtd_resources[0],
+               .num_resources  = 1,
+       },
+};
+
+/* Serial */
+static struct resource zeus_serial_resources[] = {
+       {
+               .start  = 0x10000000,
+               .end    = 0x1000000f,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = 0x10800000,
+               .end    = 0x1080000f,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = 0x11000000,
+               .end    = 0x1100000f,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = 0x40100000,
+               .end    = 0x4010001f,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = 0x40200000,
+               .end    = 0x4020001f,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = 0x40700000,
+               .end    = 0x4070001f,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct plat_serial8250_port serial_platform_data[] = {
+       /* External UARTs */
+       /* FIXME: Shared IRQs on COM1-COM4 will not work properly on v1i1 hardware. */
+       { /* COM1 */
+               .mapbase        = 0x10000000,
+               .irq            = gpio_to_irq(ZEUS_UARTA_GPIO),
+               .irqflags       = IRQF_TRIGGER_RISING,
+               .uartclk        = 14745600,
+               .regshift       = 1,
+               .flags          = UPF_IOREMAP | UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+               .iotype         = UPIO_MEM,
+       },
+       { /* COM2 */
+               .mapbase        = 0x10800000,
+               .irq            = gpio_to_irq(ZEUS_UARTB_GPIO),
+               .irqflags       = IRQF_TRIGGER_RISING,
+               .uartclk        = 14745600,
+               .regshift       = 1,
+               .flags          = UPF_IOREMAP | UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+               .iotype         = UPIO_MEM,
+       },
+       { /* COM3 */
+               .mapbase        = 0x11000000,
+               .irq            = gpio_to_irq(ZEUS_UARTC_GPIO),
+               .irqflags       = IRQF_TRIGGER_RISING,
+               .uartclk        = 14745600,
+               .regshift       = 1,
+               .flags          = UPF_IOREMAP | UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+               .iotype         = UPIO_MEM,
+       },
+       { /* COM4 */
+               .mapbase        = 0x11800000,
+               .irq            = gpio_to_irq(ZEUS_UARTD_GPIO),
+               .irqflags       = IRQF_TRIGGER_RISING,
+               .uartclk        = 14745600,
+               .regshift       = 1,
+               .flags          = UPF_IOREMAP | UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+               .iotype         = UPIO_MEM,
+       },
+       /* Internal UARTs */
+       { /* FFUART */
+               .membase        = (void *)&FFUART,
+               .mapbase        = __PREG(FFUART),
+               .irq            = IRQ_FFUART,
+               .uartclk        = 921600 * 16,
+               .regshift       = 2,
+               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+               .iotype         = UPIO_MEM,
+       },
+       { /* BTUART */
+               .membase        = (void *)&BTUART,
+               .mapbase        = __PREG(BTUART),
+               .irq            = IRQ_BTUART,
+               .uartclk        = 921600 * 16,
+               .regshift       = 2,
+               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+               .iotype         = UPIO_MEM,
+       },
+       { /* STUART */
+               .membase        = (void *)&STUART,
+               .mapbase        = __PREG(STUART),
+               .irq            = IRQ_STUART,
+               .uartclk        = 921600 * 16,
+               .regshift       = 2,
+               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+               .iotype         = UPIO_MEM,
+       },
+       { },
+};
+
+static struct platform_device zeus_serial_device = {
+       .name = "serial8250",
+       .id   = PLAT8250_DEV_PLATFORM,
+       .dev  = {
+               .platform_data = serial_platform_data,
+       },
+       .num_resources  = ARRAY_SIZE(zeus_serial_resources),
+       .resource       = zeus_serial_resources,
+};
+
+/* Ethernet */
+static struct resource zeus_dm9k0_resource[] = {
+       [0] = {
+               .start = ZEUS_ETH0_PHYS,
+               .end   = ZEUS_ETH0_PHYS + 1,
+               .flags = IORESOURCE_MEM
+       },
+       [1] = {
+               .start = ZEUS_ETH0_PHYS + 2,
+               .end   = ZEUS_ETH0_PHYS + 3,
+               .flags = IORESOURCE_MEM
+       },
+       [2] = {
+               .start = gpio_to_irq(ZEUS_ETH0_GPIO),
+               .end   = gpio_to_irq(ZEUS_ETH0_GPIO),
+               .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE,
+       },
+};
+
+static struct resource zeus_dm9k1_resource[] = {
+       [0] = {
+               .start = ZEUS_ETH1_PHYS,
+               .end   = ZEUS_ETH1_PHYS + 1,
+               .flags = IORESOURCE_MEM
+       },
+       [1] = {
+               .start = ZEUS_ETH1_PHYS + 2,
+               .end   = ZEUS_ETH1_PHYS + 3,
+               .flags = IORESOURCE_MEM,
+       },
+       [2] = {
+               .start = gpio_to_irq(ZEUS_ETH1_GPIO),
+               .end   = gpio_to_irq(ZEUS_ETH1_GPIO),
+               .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE,
+       },
+};
+
+static struct dm9000_plat_data zeus_dm9k_platdata = {
+       .flags          = DM9000_PLATF_16BITONLY,
+};
+
+static struct platform_device zeus_dm9k0_device = {
+       .name           = "dm9000",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(zeus_dm9k0_resource),
+       .resource       = zeus_dm9k0_resource,
+       .dev            = {
+               .platform_data = &zeus_dm9k_platdata,
+       }
+};
+
+static struct platform_device zeus_dm9k1_device = {
+       .name           = "dm9000",
+       .id             = 1,
+       .num_resources  = ARRAY_SIZE(zeus_dm9k1_resource),
+       .resource       = zeus_dm9k1_resource,
+       .dev            = {
+               .platform_data = &zeus_dm9k_platdata,
+       }
+};
+
+/* External SRAM */
+static struct resource zeus_sram_resource = {
+       .start          = ZEUS_SRAM_PHYS,
+       .end            = ZEUS_SRAM_PHYS + ZEUS_SRAM_SIZE * 2 - 1,
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device zeus_sram_device = {
+       .name           = "pxa2xx-8bit-sram",
+       .id             = 0,
+       .num_resources  = 1,
+       .resource       = &zeus_sram_resource,
+};
+
+/* SPI interface on SSP3 */
+static struct pxa2xx_spi_master pxa2xx_spi_ssp3_master_info = {
+       .num_chipselect = 1,
+       .enable_dma     = 1,
+};
+
+static struct platform_device pxa2xx_spi_ssp3_device = {
+       .name = "pxa2xx-spi",
+       .id = 3,
+       .dev = {
+               .platform_data = &pxa2xx_spi_ssp3_master_info,
+       },
+};
+
+/* Leds */
+static struct gpio_led zeus_leds[] = {
+       [0] = {
+               .name            = "zeus:yellow:1",
+               .default_trigger = "heartbeat",
+               .gpio            = ZEUS_EXT0_GPIO(3),
+               .active_low      = 1,
+       },
+       [1] = {
+               .name            = "zeus:yellow:2",
+               .default_trigger = "default-on",
+               .gpio            = ZEUS_EXT0_GPIO(4),
+               .active_low      = 1,
+       },
+       [2] = {
+               .name            = "zeus:yellow:3",
+               .default_trigger = "default-on",
+               .gpio            = ZEUS_EXT0_GPIO(5),
+               .active_low      = 1,
+       },
+};
+
+static struct gpio_led_platform_data zeus_leds_info = {
+       .leds           = zeus_leds,
+       .num_leds       = ARRAY_SIZE(zeus_leds),
+};
+
+static struct platform_device zeus_leds_device = {
+       .name           = "leds-gpio",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &zeus_leds_info,
+       },
+};
+
+static void zeus_cf_reset(int state)
+{
+       u16 cpld_state = __raw_readw(ZEUS_CPLD_CONTROL);
+
+       if (state)
+               cpld_state |= ZEUS_CPLD_CONTROL_CF_RST;
+       else
+               cpld_state &= ~ZEUS_CPLD_CONTROL_CF_RST;
+
+       __raw_writew(cpld_state, ZEUS_CPLD_CONTROL);
+}
+
+static struct arcom_pcmcia_pdata zeus_pcmcia_info = {
+       .cd_gpio        = ZEUS_CF_CD_GPIO,
+       .rdy_gpio       = ZEUS_CF_RDY_GPIO,
+       .pwr_gpio       = ZEUS_CF_PWEN_GPIO,
+       .reset          = zeus_cf_reset,
+};
+
+static struct platform_device zeus_pcmcia_device = {
+       .name           = "zeus-pcmcia",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &zeus_pcmcia_info,
+       },
+};
+
+static struct platform_device *zeus_devices[] __initdata = {
+       &zeus_serial_device,
+       &zeus_mtd_devices[0],
+       &zeus_dm9k0_device,
+       &zeus_dm9k1_device,
+       &zeus_sram_device,
+       &pxa2xx_spi_ssp3_device,
+       &zeus_leds_device,
+       &zeus_pcmcia_device,
+};
+
+/* AC'97 */
+static pxa2xx_audio_ops_t zeus_ac97_info = {
+       .reset_gpio = 95,
+};
+
+
+/*
+ * USB host
+ */
+
+static int zeus_ohci_init(struct device *dev)
+{
+       int err;
+
+       /* Switch on port 2. */
+       if ((err = gpio_request(ZEUS_USB2_PWREN_GPIO, "USB2_PWREN"))) {
+               dev_err(dev, "Can't request USB2_PWREN\n");
+               return err;
+       }
+
+       if ((err = gpio_direction_output(ZEUS_USB2_PWREN_GPIO, 1))) {
+               gpio_free(ZEUS_USB2_PWREN_GPIO);
+               dev_err(dev, "Can't enable USB2_PWREN\n");
+               return err;
+       }
+
+       /* Port 2 is shared between host and client interface. */
+       UP2OCR = UP2OCR_HXOE | UP2OCR_HXS | UP2OCR_DMPDE | UP2OCR_DPPDE;
+
+       return 0;
+}
+
+static void zeus_ohci_exit(struct device *dev)
+{
+       /* Power-off port 2 */
+       gpio_direction_output(ZEUS_USB2_PWREN_GPIO, 0);
+       gpio_free(ZEUS_USB2_PWREN_GPIO);
+}
+
+static struct pxaohci_platform_data zeus_ohci_platform_data = {
+       .port_mode      = PMM_NPS_MODE,
+       .flags          = ENABLE_PORT_ALL | POWER_CONTROL_LOW | POWER_SENSE_LOW,
+       .init           = zeus_ohci_init,
+       .exit           = zeus_ohci_exit,
+};
+
+/*
+ * Flat Panel
+ */
+
+static void zeus_lcd_power(int on, struct fb_var_screeninfo *si)
+{
+       gpio_set_value(ZEUS_LCD_EN_GPIO, on);
+}
+
+static void zeus_backlight_power(int on)
+{
+       gpio_set_value(ZEUS_BKLEN_GPIO, on);
+}
+
+static int zeus_setup_fb_gpios(void)
+{
+       int err;
+
+       if ((err = gpio_request(ZEUS_LCD_EN_GPIO, "LCD_EN")))
+               goto out_err;
+
+       if ((err = gpio_direction_output(ZEUS_LCD_EN_GPIO, 0)))
+               goto out_err_lcd;
+
+       if ((err = gpio_request(ZEUS_BKLEN_GPIO, "BKLEN")))
+               goto out_err_lcd;
+
+       if ((err = gpio_direction_output(ZEUS_BKLEN_GPIO, 0)))
+               goto out_err_bkl;
+
+       return 0;
+
+out_err_bkl:
+       gpio_free(ZEUS_BKLEN_GPIO);
+out_err_lcd:
+       gpio_free(ZEUS_LCD_EN_GPIO);
+out_err:
+       return err;
+}
+
+static struct pxafb_mode_info zeus_fb_mode_info[] = {
+       {
+               .pixclock       = 39722,
+
+               .xres           = 640,
+               .yres           = 480,
+
+               .bpp            = 16,
+
+               .hsync_len      = 63,
+               .left_margin    = 16,
+               .right_margin   = 81,
+
+               .vsync_len      = 2,
+               .upper_margin   = 12,
+               .lower_margin   = 31,
+
+               .sync           = 0,
+       },
+};
+
+static struct pxafb_mach_info zeus_fb_info = {
+       .modes                  = zeus_fb_mode_info,
+       .num_modes              = 1,
+       .lcd_conn               = LCD_COLOR_TFT_16BPP | LCD_PCLK_EDGE_FALL,
+       .pxafb_lcd_power        = zeus_lcd_power,
+       .pxafb_backlight_power  = zeus_backlight_power,
+};
+
+/*
+ * MMC/SD Device
+ *
+ * The card detect interrupt isn't debounced so we delay it by 250ms
+ * to give the card a chance to fully insert/eject.
+ */
+
+static struct pxamci_platform_data zeus_mci_platform_data = {
+       .ocr_mask               = MMC_VDD_32_33|MMC_VDD_33_34,
+       .detect_delay           = HZ/4,
+       .gpio_card_detect       = ZEUS_MMC_CD_GPIO,
+       .gpio_card_ro           = ZEUS_MMC_WP_GPIO,
+       .gpio_card_ro_invert    = 1,
+       .gpio_power             = -1
+};
+
+/*
+ * USB Device Controller
+ */
+static void zeus_udc_command(int cmd)
+{
+       switch (cmd) {
+       case PXA2XX_UDC_CMD_DISCONNECT:
+               pr_info("zeus: disconnecting USB client\n");
+               UP2OCR = UP2OCR_HXOE | UP2OCR_HXS | UP2OCR_DMPDE | UP2OCR_DPPDE;
+               break;
+
+       case PXA2XX_UDC_CMD_CONNECT:
+               pr_info("zeus: connecting USB client\n");
+               UP2OCR = UP2OCR_HXOE | UP2OCR_DPPUE;
+               break;
+       }
+}
+
+static struct pxa2xx_udc_mach_info zeus_udc_info = {
+       .udc_command = zeus_udc_command,
+};
+
+static void zeus_power_off(void)
+{
+       local_irq_disable();
+       pxa27x_cpu_suspend(PWRMODE_DEEPSLEEP);
+}
+
+int zeus_get_pcb_info(struct i2c_client *client, unsigned gpio,
+                     unsigned ngpio, void *context)
+{
+       int i;
+       u8 pcb_info = 0;
+
+       for (i = 0; i < 8; i++) {
+               int pcb_bit = gpio + i + 8;
+
+               if (gpio_request(pcb_bit, "pcb info")) {
+                       dev_err(&client->dev, "Can't request pcb info %d\n", i);
+                       continue;
+               }
+
+               if (gpio_direction_input(pcb_bit)) {
+                       dev_err(&client->dev, "Can't read pcb info %d\n", i);
+                       gpio_free(pcb_bit);
+                       continue;
+               }
+
+               pcb_info |= !!gpio_get_value(pcb_bit) << i;
+
+               gpio_free(pcb_bit);
+       }
+
+       dev_info(&client->dev, "Zeus PCB version %d issue %d\n",
+                pcb_info >> 4, pcb_info & 0xf);
+
+       return 0;
+}
+
+static struct pca953x_platform_data zeus_pca953x_pdata[] = {
+       [0] = { .gpio_base      = ZEUS_EXT0_GPIO_BASE, },
+       [1] = {
+               .gpio_base      = ZEUS_EXT1_GPIO_BASE,
+               .setup          = zeus_get_pcb_info,
+       },
+       [2] = { .gpio_base = ZEUS_USER_GPIO_BASE, },
+};
+
+static struct i2c_board_info __initdata zeus_i2c_devices[] = {
+       {
+               I2C_BOARD_INFO("pca9535",       0x21),
+               .platform_data  = &zeus_pca953x_pdata[0],
+       },
+       {
+               I2C_BOARD_INFO("pca9535",       0x22),
+               .platform_data  = &zeus_pca953x_pdata[1],
+       },
+       {
+               I2C_BOARD_INFO("pca9535",       0x20),
+               .platform_data  = &zeus_pca953x_pdata[2],
+               .irq            = gpio_to_irq(ZEUS_EXTGPIO_GPIO),
+       },
+       { I2C_BOARD_INFO("lm75a",       0x48) },
+       { I2C_BOARD_INFO("24c01",       0x50) },
+       { I2C_BOARD_INFO("isl1208",     0x6f) },
+};
+
+static mfp_cfg_t zeus_pin_config[] __initdata = {
+       GPIO15_nCS_1,
+       GPIO78_nCS_2,
+       GPIO80_nCS_4,
+       GPIO33_nCS_5,
+
+       GPIO22_GPIO,
+       GPIO32_MMC_CLK,
+       GPIO92_MMC_DAT_0,
+       GPIO109_MMC_DAT_1,
+       GPIO110_MMC_DAT_2,
+       GPIO111_MMC_DAT_3,
+       GPIO112_MMC_CMD,
+
+       GPIO88_USBH1_PWR,
+       GPIO89_USBH1_PEN,
+       GPIO119_USBH2_PWR,
+       GPIO120_USBH2_PEN,
+
+       GPIO86_LCD_LDD_16,
+       GPIO87_LCD_LDD_17,
+
+       GPIO102_GPIO,
+       GPIO104_CIF_DD_2,
+       GPIO105_CIF_DD_1,
+
+       GPIO48_nPOE,
+       GPIO49_nPWE,
+       GPIO50_nPIOR,
+       GPIO51_nPIOW,
+       GPIO85_nPCE_1,
+       GPIO54_nPCE_2,
+       GPIO79_PSKTSEL,
+       GPIO55_nPREG,
+       GPIO56_nPWAIT,
+       GPIO57_nIOIS16,
+       GPIO36_GPIO,            /* CF CD */
+       GPIO97_GPIO,            /* CF PWREN */
+       GPIO99_GPIO,            /* CF RDY */
+};
+
+static void __init zeus_init(void)
+{
+       u16 dm9000_msc = 0xe279;
+
+       system_rev = __raw_readw(ZEUS_CPLD_VERSION);
+       pr_info("Zeus CPLD V%dI%d\n", (system_rev & 0xf0) >> 4, (system_rev & 0x0f));
+
+       /* Fix timings for dm9000s (CS1/CS2)*/
+       MSC0 = (MSC0 & 0xffff) | (dm9000_msc << 16);
+       MSC1 = (MSC1 & 0xffff0000) | dm9000_msc;
+
+       pm_power_off = zeus_power_off;
+
+       pxa2xx_mfp_config(ARRAY_AND_SIZE(zeus_pin_config));
+
+       platform_add_devices(zeus_devices, ARRAY_SIZE(zeus_devices));
+
+       pxa_set_ohci_info(&zeus_ohci_platform_data);
+
+       if (zeus_setup_fb_gpios())
+               pr_err("Failed to setup fb gpios\n");
+       else
+               set_pxa_fb_info(&zeus_fb_info);
+
+       pxa_set_mci_info(&zeus_mci_platform_data);
+       pxa_set_udc_info(&zeus_udc_info);
+       pxa_set_ac97_info(&zeus_ac97_info);
+       pxa_set_i2c_info(NULL);
+       i2c_register_board_info(0, ARRAY_AND_SIZE(zeus_i2c_devices));
+}
+
+static struct map_desc zeus_io_desc[] __initdata = {
+       {
+               .virtual = ZEUS_CPLD_VERSION,
+               .pfn     = __phys_to_pfn(ZEUS_CPLD_VERSION_PHYS),
+               .length  = 0x1000,
+               .type    = MT_DEVICE,
+       },
+       {
+               .virtual = ZEUS_CPLD_ISA_IRQ,
+               .pfn     = __phys_to_pfn(ZEUS_CPLD_ISA_IRQ_PHYS),
+               .length  = 0x1000,
+               .type    = MT_DEVICE,
+       },
+       {
+               .virtual = ZEUS_CPLD_CONTROL,
+               .pfn     = __phys_to_pfn(ZEUS_CPLD_CONTROL_PHYS),
+               .length  = 0x1000,
+               .type    = MT_DEVICE,
+       },
+       {
+               .virtual = ZEUS_CPLD_EXTWDOG,
+               .pfn     = __phys_to_pfn(ZEUS_CPLD_EXTWDOG_PHYS),
+               .length  = 0x1000,
+               .type    = MT_DEVICE,
+       },
+       {
+               .virtual = ZEUS_PC104IO,
+               .pfn     = __phys_to_pfn(ZEUS_PC104IO_PHYS),
+               .length  = 0x00800000,
+               .type    = MT_DEVICE,
+       },
+};
+
+static void __init zeus_map_io(void)
+{
+       pxa_map_io();
+
+       iotable_init(zeus_io_desc, ARRAY_SIZE(zeus_io_desc));
+
+       /* Clear PSPR to ensure a full restart on wake-up. */
+       PMCR = PSPR = 0;
+
+       /* enable internal 32.768Khz oscillator (ignore OSCC_OOK) */
+       OSCC |= OSCC_OON;
+
+       /* Some clock cycles later (from OSCC_ON), programme PCFR (OPDE...).
+        * float chip selects and PCMCIA */
+       PCFR = PCFR_OPDE | PCFR_DC_EN | PCFR_FS | PCFR_FP;
+}
+
+MACHINE_START(ARCOM_ZEUS, "Arcom ZEUS")
+       /* Maintainer: Marc Zyngier <maz@misterjones.org> */
+       .phys_io        = 0x40000000,
+       .io_pg_offst    = ((io_p2v(0x40000000) >> 18) & 0xfffc),
+       .boot_params    = 0xa0000100,
+       .map_io         = zeus_map_io,
+       .init_irq       = zeus_init_irq,
+       .timer          = &pxa_timer,
+       .init_machine   = zeus_init,
+MACHINE_END
+
index c48e1f2c3349492472d02316fb77f0cb7f29c8ed..ee5e392430e87e4f45721320e33172f68e933e56 100644 (file)
@@ -70,7 +70,7 @@ config MACH_REALVIEW_PBX
        bool "Support RealView/PBX platform"
        select ARM_GIC
        select HAVE_PATA_PLATFORM
-       select ARCH_SPARSEMEM_ENABLE if CPU_V7 && !HIGH_PHYS_OFFSET
+       select ARCH_SPARSEMEM_ENABLE if CPU_V7 && !REALVIEW_HIGH_PHYS_OFFSET
        select ZONE_DMA if SPARSEMEM
        help
          Include support for the ARM(R) RealView PBX platform.
index 585211ca0187487e0cbfc60bc98cc38899a926ec..7d74fd5c8d665aa2aa899c91ed5915aa9a98defe 100644 (file)
@@ -15,5 +15,7 @@
 
 #define __virt_to_bus(x) __virt_to_phys(x)
 #define __bus_to_virt(x) __phys_to_virt(x)
+#define __pfn_to_bus(x) __pfn_to_phys(x)
+#define __bus_to_pfn(x)        __phys_to_pfn(x)
 
 #endif
index 03a7f3857c5e69e210b4370ab5e15218a3b014bd..b17d52f7cc48739b2d02d24e690021c4e28d69fc 100644 (file)
@@ -4,6 +4,7 @@ menu "SA11x0 Implementations"
 
 config SA1100_ASSABET
        bool "Assabet"
+       select CPU_FREQ_SA1110
        help
          Say Y here if you are using the Intel(R) StrongARM(R) SA-1110
          Microprocessor Development Board (also known as the Assabet).
@@ -19,6 +20,7 @@ config ASSABET_NEPONSET
 
 config SA1100_CERF
        bool "CerfBoard"
+       select CPU_FREQ_SA1110
        help
          The Intrinsyc CerfBoard is based on the StrongARM 1110 (Discontinued).
          More information is available at:
@@ -45,6 +47,7 @@ endchoice
 
 config SA1100_COLLIE
        bool "Sharp Zaurus SL5500"
+       # FIXME: select CPU_FREQ_SA11x0
        select SHARP_LOCOMO
        select SHARP_SCOOP
        select SHARP_PARAM
@@ -54,6 +57,7 @@ config SA1100_COLLIE
 config SA1100_H3100
        bool "Compaq iPAQ H3100"
        select HTC_EGPIO
+       select CPU_FREQ_SA1100
        help
          Say Y here if you intend to run this kernel on the Compaq iPAQ
          H3100 handheld computer.  Information about this machine and the
@@ -64,6 +68,7 @@ config SA1100_H3100
 config SA1100_H3600
        bool "Compaq iPAQ H3600/H3700"
        select HTC_EGPIO
+       select CPU_FREQ_SA1100
        help
          Say Y here if you intend to run this kernel on the Compaq iPAQ
          H3600 handheld computer.  Information about this machine and the
@@ -74,6 +79,7 @@ config SA1100_H3600
 config SA1100_BADGE4
        bool "HP Labs BadgePAD 4"
        select SA1111
+       select CPU_FREQ_SA1100
        help
          Say Y here if you want to build a kernel for the HP Laboratories
          BadgePAD 4.
@@ -81,6 +87,7 @@ config SA1100_BADGE4
 config SA1100_JORNADA720
        bool "HP Jornada 720"
        select SA1111
+       # FIXME: select CPU_FREQ_SA11x0
        help
          Say Y here if you want to build a kernel for the HP Jornada 720
          handheld computer.  See <http://www.hp.com/jornada/products/720>
@@ -98,12 +105,14 @@ config SA1100_JORNADA720_SSP
 
 config SA1100_HACKKIT
        bool "HackKit Core CPU Board"
+       select CPU_FREQ_SA1100
        help
          Say Y here to support the HackKit Core CPU Board
          <http://hackkit.eletztrick.de>;
 
 config SA1100_LART
        bool "LART"
+       select CPU_FREQ_SA1100
        help
          Say Y here if you are using the Linux Advanced Radio Terminal
          (also known as the LART).  See <http://www.lartmaker.nl/> for
@@ -111,6 +120,7 @@ config SA1100_LART
 
 config SA1100_PLEB
        bool "PLEB"
+       select CPU_FREQ_SA1100
        help
          Say Y here if you are using version 1 of the Portable Linux
          Embedded Board (also known as PLEB).
@@ -119,6 +129,7 @@ config SA1100_PLEB
 
 config SA1100_SHANNON
        bool "Shannon"
+       select CPU_FREQ_SA1100
        help
          The Shannon (also known as a Tuxscreen, and also as a IS2630) was a
          limited edition webphone produced by Philips. The Shannon is a SA1100
@@ -127,6 +138,7 @@ config SA1100_SHANNON
 
 config SA1100_SIMPAD
        bool "Simpad"
+       select CPU_FREQ_SA1110
        help
          The SIEMENS webpad SIMpad is based on the StrongARM 1110. There
          are two different versions CL4 and SL4. CL4 has 32MB RAM and 16MB
@@ -145,3 +157,4 @@ config SA1100_SSP
 endmenu
 
 endif
+
index 9faea1511c1f06554277b99a35192641e23cade0..3c1fcd6967145cc91a04752db09c856d031f4e49 100644 (file)
@@ -58,7 +58,6 @@ static const unsigned short cclk_frequency_100khz[NR_FREQS] = {
        2802    /* 280.2 MHz */
 };
 
-#if defined(CONFIG_CPU_FREQ_SA1100) || defined(CONFIG_CPU_FREQ_SA1110)
 /* rounds up(!)  */
 unsigned int sa11x0_freq_to_ppcr(unsigned int khz)
 {
@@ -110,17 +109,6 @@ unsigned int sa11x0_getspeed(unsigned int cpu)
        return cclk_frequency_100khz[PPCR & 0xf] * 100;
 }
 
-#else
-/*
- * We still need to provide this so building without cpufreq works.
- */
-unsigned int cpufreq_get(unsigned int cpu)
-{
-       return cclk_frequency_100khz[PPCR & 0xf] * 100;
-}
-EXPORT_SYMBOL(cpufreq_get);
-#endif
-
 /*
  * This is the SA11x0 sched_clock implementation.  This has
  * a resolution of 271ns, and a maximum value of 32025597s (370 days).
diff --git a/arch/arm/mach-w90x900/include/mach/nuc900_spi.h b/arch/arm/mach-w90x900/include/mach/nuc900_spi.h
new file mode 100644 (file)
index 0000000..bd94819
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * arch/arm/mach-w90x900/include/mach/nuc900_spi.h
+ *
+ * Copyright (c) 2009 Nuvoton technology corporation.
+ *
+ * Wan ZongShun <mcuos.com@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;version 2 of the License.
+ *
+ */
+
+#ifndef __ASM_ARCH_SPI_H
+#define __ASM_ARCH_SPI_H
+
+extern void mfp_set_groupg(struct device *dev);
+
+struct nuc900_spi_info {
+       unsigned int num_cs;
+       unsigned int lsb;
+       unsigned int txneg;
+       unsigned int rxneg;
+       unsigned int divider;
+       unsigned int sleep;
+       unsigned int txnum;
+       unsigned int txbitlen;
+       int bus_num;
+};
+
+struct nuc900_spi_chip {
+       unsigned char bits_per_word;
+};
+
+#endif /* __ASM_ARCH_SPI_H */
index ce5dd2d1dc21507caf2212fa2b86064205f1d099..97d6c50c3dcb00b24d1d43551e6a4a3b8402621f 100644 (file)
 #endif
 #define TWL4030_GPIO_IRQ_END   (TWL4030_GPIO_IRQ_BASE + TWL4030_GPIO_NR_IRQS)
 
+#define        TWL6030_IRQ_BASE        (OMAP_FPGA_IRQ_END)
+#ifdef CONFIG_TWL4030_CORE
+#define        TWL6030_BASE_NR_IRQS    20
+#else
+#define        TWL6030_BASE_NR_IRQS    0
+#endif
+#define TWL6030_IRQ_END                (TWL6030_IRQ_BASE + TWL6030_BASE_NR_IRQS)
+
 /* Total number of interrupts depends on the enabled blocks above */
-#define NR_IRQS                        TWL4030_GPIO_IRQ_END
+#if (TWL4030_GPIO_IRQ_END > TWL6030_IRQ_END)
+#define TWL_IRQ_END            TWL4030_GPIO_IRQ_END
+#else
+#define TWL_IRQ_END            TWL6030_IRQ_END
+#endif
+
+#define NR_IRQS                        TWL_IRQ_END
 
 #define OMAP_IRQ_BIT(irq)      (1 << ((irq) % 32))
 
index 2d7423af1197a3418f1b7bb84222f04f77954884..aed05bc3c2eaecf29ddd63c1aabf1842d8f9440f 100644 (file)
@@ -38,16 +38,72 @@ union vfp_state *last_VFP_context[NR_CPUS];
  */
 unsigned int VFP_arch;
 
+/*
+ * Per-thread VFP initialization.
+ */
+static void vfp_thread_flush(struct thread_info *thread)
+{
+       union vfp_state *vfp = &thread->vfpstate;
+       unsigned int cpu;
+
+       memset(vfp, 0, sizeof(union vfp_state));
+
+       vfp->hard.fpexc = FPEXC_EN;
+       vfp->hard.fpscr = FPSCR_ROUND_NEAREST;
+
+       /*
+        * Disable VFP to ensure we initialize it first.  We must ensure
+        * that the modification of last_VFP_context[] and hardware disable
+        * are done for the same CPU and without preemption.
+        */
+       cpu = get_cpu();
+       if (last_VFP_context[cpu] == vfp)
+               last_VFP_context[cpu] = NULL;
+       fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
+       put_cpu();
+}
+
+static void vfp_thread_release(struct thread_info *thread)
+{
+       /* release case: Per-thread VFP cleanup. */
+       union vfp_state *vfp = &thread->vfpstate;
+       unsigned int cpu = thread->cpu;
+
+       if (last_VFP_context[cpu] == vfp)
+               last_VFP_context[cpu] = NULL;
+}
+
+/*
+ * When this function is called with the following 'cmd's, the following
+ * is true while this function is being run:
+ *  THREAD_NOFTIFY_SWTICH:
+ *   - the previously running thread will not be scheduled onto another CPU.
+ *   - the next thread to be run (v) will not be running on another CPU.
+ *   - thread->cpu is the local CPU number
+ *   - not preemptible as we're called in the middle of a thread switch
+ *  THREAD_NOTIFY_FLUSH:
+ *   - the thread (v) will be running on the local CPU, so
+ *     v === current_thread_info()
+ *   - thread->cpu is the local CPU number at the time it is accessed,
+ *     but may change at any time.
+ *   - we could be preempted if tree preempt rcu is enabled, so
+ *     it is unsafe to use thread->cpu.
+ *  THREAD_NOTIFY_RELEASE:
+ *   - the thread (v) will not be running on any CPU; it is a dead thread.
+ *   - thread->cpu will be the last CPU the thread ran on, which may not
+ *     be the current CPU.
+ *   - we could be preempted if tree preempt rcu is enabled.
+ */
 static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
 {
        struct thread_info *thread = v;
-       union vfp_state *vfp;
-       __u32 cpu = thread->cpu;
 
        if (likely(cmd == THREAD_NOTIFY_SWITCH)) {
                u32 fpexc = fmrx(FPEXC);
 
 #ifdef CONFIG_SMP
+               unsigned int cpu = thread->cpu;
+
                /*
                 * On SMP, if VFP is enabled, save the old state in
                 * case the thread migrates to a different CPU. The
@@ -74,25 +130,10 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
                return NOTIFY_DONE;
        }
 
-       vfp = &thread->vfpstate;
-       if (cmd == THREAD_NOTIFY_FLUSH) {
-               /*
-                * Per-thread VFP initialisation.
-                */
-               memset(vfp, 0, sizeof(union vfp_state));
-
-               vfp->hard.fpexc = FPEXC_EN;
-               vfp->hard.fpscr = FPSCR_ROUND_NEAREST;
-
-               /*
-                * Disable VFP to ensure we initialise it first.
-                */
-               fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
-       }
-
-       /* flush and release case: Per-thread VFP cleanup. */
-       if (last_VFP_context[cpu] == vfp)
-               last_VFP_context[cpu] = NULL;
+       if (cmd == THREAD_NOTIFY_FLUSH)
+               vfp_thread_flush(thread);
+       else
+               vfp_thread_release(thread);
 
        return NOTIFY_DONE;
 }
index 1ee596cd942ff8c3a3915b2428acacb206c1f6b8..2d7f56a98e0f484ce80d544223b4b9923526cb2a 100644 (file)
@@ -87,9 +87,6 @@ config GENERIC_TIME_VSYSCALL
        bool
        default y
 
-config HAVE_LEGACY_PER_CPU_AREA
-       def_bool y
-
 config HAVE_SETUP_PER_CPU_AREA
        def_bool y
 
index 688a812c017d64c1f5c9763012ecac75d7b00f0e..61c7b1750b169f33ccb544b5cb83c83e1dd432ee 100644 (file)
@@ -61,7 +61,7 @@ extern int register_active_ranges(u64 start, u64 len, int nid);
 
 #ifdef CONFIG_VIRTUAL_MEM_MAP
 # define LARGE_GAP     0x40000000 /* Use virtual mem map if hole is > than this */
-  extern unsigned long vmalloc_end;
+  extern unsigned long VMALLOC_END;
   extern struct page *vmem_map;
   extern int find_largest_hole(u64 start, u64 end, void *arg);
   extern int create_mem_map_page_table(u64 start, u64 end, void *arg);
index 8840a690d1e7aa346b82fc68672186631c2e0828..69bf13857a9fc8ac9ff07e73a24436c17af19adb 100644 (file)
@@ -228,8 +228,7 @@ ia64_phys_addr_valid (unsigned long addr)
 #define VMALLOC_START          (RGN_BASE(RGN_GATE) + 0x200000000UL)
 #ifdef CONFIG_VIRTUAL_MEM_MAP
 # define VMALLOC_END_INIT      (RGN_BASE(RGN_GATE) + (1UL << (4*PAGE_SHIFT - 9)))
-# define VMALLOC_END           vmalloc_end
-  extern unsigned long vmalloc_end;
+extern unsigned long VMALLOC_END;
 #else
 #if defined(CONFIG_SPARSEMEM) && defined(CONFIG_SPARSEMEM_VMEMMAP)
 /* SPARSEMEM_VMEMMAP uses half of vmalloc... */
index 3eaeedf1aef2cf20d5a8c707d64ddd34746c18b2..7fa90f73f6be37757e3a36ed46c85ac3ede3df77 100644 (file)
@@ -229,7 +229,7 @@ struct cpuinfo_ia64 {
 #endif
 };
 
-DECLARE_PER_CPU(struct cpuinfo_ia64, cpu_info);
+DECLARE_PER_CPU(struct cpuinfo_ia64, ia64_cpu_info);
 
 /*
  * The "local" data variable.  It refers to the per-CPU data of the currently executing
@@ -237,8 +237,8 @@ DECLARE_PER_CPU(struct cpuinfo_ia64, cpu_info);
  * Do not use the address of local_cpu_data, since it will be different from
  * cpu_data(smp_processor_id())!
  */
-#define local_cpu_data         (&__ia64_per_cpu_var(cpu_info))
-#define cpu_data(cpu)          (&per_cpu(cpu_info, cpu))
+#define local_cpu_data         (&__ia64_per_cpu_var(ia64_cpu_info))
+#define cpu_data(cpu)          (&per_cpu(ia64_cpu_info, cpu))
 
 extern void print_cpu_info (struct cpuinfo_ia64 *);
 
index baec6f00f7f3feee71c5110b01f12b5c8b3f4fda..40574ae114018e4db5efce7fc499435c4c863eec 100644 (file)
@@ -702,11 +702,23 @@ int __init early_acpi_boot_init(void)
                printk(KERN_ERR PREFIX
                       "Error parsing MADT - no LAPIC entries\n");
 
+#ifdef CONFIG_SMP
+       if (available_cpus == 0) {
+               printk(KERN_INFO "ACPI: Found 0 CPUS; assuming 1\n");
+               printk(KERN_INFO "CPU 0 (0x%04x)", hard_smp_processor_id());
+               smp_boot_data.cpu_phys_id[available_cpus] =
+                   hard_smp_processor_id();
+               available_cpus = 1;     /* We've got at least one of these, no? */
+       }
+       smp_boot_data.cpu_count = available_cpus;
+#endif
+       /* Make boot-up look pretty */
+       printk(KERN_INFO "%d CPUs available, %d CPUs total\n", available_cpus,
+              total_cpus);
+
        return 0;
 }
 
-
-
 int __init acpi_boot_init(void)
 {
 
@@ -769,18 +781,8 @@ int __init acpi_boot_init(void)
        if (acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt))
                printk(KERN_ERR PREFIX "Can't find FADT\n");
 
+#ifdef CONFIG_ACPI_NUMA
 #ifdef CONFIG_SMP
-       if (available_cpus == 0) {
-               printk(KERN_INFO "ACPI: Found 0 CPUS; assuming 1\n");
-               printk(KERN_INFO "CPU 0 (0x%04x)", hard_smp_processor_id());
-               smp_boot_data.cpu_phys_id[available_cpus] =
-                   hard_smp_processor_id();
-               available_cpus = 1;     /* We've got at least one of these, no? */
-       }
-       smp_boot_data.cpu_count = available_cpus;
-
-       smp_build_cpu_map();
-# ifdef CONFIG_ACPI_NUMA
        if (srat_num_cpus == 0) {
                int cpu, i = 1;
                for (cpu = 0; cpu < smp_boot_data.cpu_count; cpu++)
@@ -789,14 +791,9 @@ int __init acpi_boot_init(void)
                                node_cpuid[i++].phys_id =
                                    smp_boot_data.cpu_phys_id[cpu];
        }
-# endif
 #endif
-#ifdef CONFIG_ACPI_NUMA
        build_cpu_to_node_map();
 #endif
-       /* Make boot-up look pretty */
-       printk(KERN_INFO "%d CPUs available, %d CPUs total\n", available_cpus,
-              total_cpus);
        return 0;
 }
 
index 696eff28a0c44c477465314a4c3ee5daa71b4198..17a9fba38930ab0504aa7b17262765af117c2740 100644 (file)
@@ -1051,7 +1051,7 @@ END(ia64_delay_loop)
  * intermediate precision so that we can produce a full 64-bit result.
  */
 GLOBAL_ENTRY(ia64_native_sched_clock)
-       addl r8=THIS_CPU(cpu_info) + IA64_CPUINFO_NSEC_PER_CYC_OFFSET,r0
+       addl r8=THIS_CPU(ia64_cpu_info) + IA64_CPUINFO_NSEC_PER_CYC_OFFSET,r0
        mov.m r9=ar.itc         // fetch cycle-counter                          (35 cyc)
        ;;
        ldf8 f8=[r8]
@@ -1077,7 +1077,7 @@ sched_clock = ia64_native_sched_clock
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
 GLOBAL_ENTRY(cycle_to_cputime)
        alloc r16=ar.pfs,1,0,0,0
-       addl r8=THIS_CPU(cpu_info) + IA64_CPUINFO_NSEC_PER_CYC_OFFSET,r0
+       addl r8=THIS_CPU(ia64_cpu_info) + IA64_CPUINFO_NSEC_PER_CYC_OFFSET,r0
        ;;
        ldf8 f8=[r8]
        ;;
index 14d39e3006274fb054382505d8f0ba32959c6cb8..461b99902bf6ff2f703029c6fed6463271584048 100644 (file)
@@ -30,7 +30,7 @@ EXPORT_SYMBOL(max_low_pfn);   /* defined by bootmem.c, but not exported by generic
 #endif
 
 #include <asm/processor.h>
-EXPORT_SYMBOL(per_cpu__cpu_info);
+EXPORT_SYMBOL(per_cpu__ia64_cpu_info);
 #ifdef CONFIG_SMP
 EXPORT_SYMBOL(per_cpu__local_per_cpu_offset);
 #endif
index 7461d2573d41106191fe7b7a42d7cfe2d370a9bf..d5bdf9de36b6362f81a039b4494f0fa657497e87 100644 (file)
@@ -59,7 +59,7 @@
 ia64_do_tlb_purge:
 #define O(member)      IA64_CPUINFO_##member##_OFFSET
 
-       GET_THIS_PADDR(r2, cpu_info)    // load phys addr of cpu_info into r2
+       GET_THIS_PADDR(r2, ia64_cpu_info) // load phys addr of cpu_info into r2
        ;;
        addl r17=O(PTCE_STRIDE),r2
        addl r2=O(PTCE_BASE),r2
index 32f6fc131fbe2946831ee4eb2ef15d2f35bf132e..c370e02f0061fbf8414457b16dd342fbd5201872 100644 (file)
@@ -61,7 +61,7 @@ GLOBAL_ENTRY(relocate_new_kernel)
 
        // purge all TC entries
 #define O(member)       IA64_CPUINFO_##member##_OFFSET
-        GET_THIS_PADDR(r2, cpu_info)    // load phys addr of cpu_info into r2
+        GET_THIS_PADDR(r2, ia64_cpu_info) // load phys addr of cpu_info into r2
         ;;
         addl r17=O(PTCE_STRIDE),r2
         addl r2=O(PTCE_BASE),r2
index 1de86c96801d60fe81ae2d6fc4930bdfdc190c45..a1ea879197770a2347ccff6ac0049146937d1ca9 100644 (file)
@@ -74,7 +74,7 @@ unsigned long __per_cpu_offset[NR_CPUS];
 EXPORT_SYMBOL(__per_cpu_offset);
 #endif
 
-DEFINE_PER_CPU(struct cpuinfo_ia64, cpu_info);
+DEFINE_PER_CPU(struct cpuinfo_ia64, ia64_cpu_info);
 DEFINE_PER_CPU(unsigned long, local_per_cpu_offset);
 unsigned long ia64_cycles_per_usec;
 struct ia64_boot_param *ia64_boot_param;
@@ -566,19 +566,18 @@ setup_arch (char **cmdline_p)
        early_acpi_boot_init();
 # ifdef CONFIG_ACPI_NUMA
        acpi_numa_init();
-#ifdef CONFIG_ACPI_HOTPLUG_CPU
+#  ifdef CONFIG_ACPI_HOTPLUG_CPU
        prefill_possible_map();
-#endif
+#  endif
        per_cpu_scan_finalize((cpus_weight(early_cpu_possible_map) == 0 ?
                32 : cpus_weight(early_cpu_possible_map)),
                additional_cpus > 0 ? additional_cpus : 0);
 # endif
-#else
-# ifdef CONFIG_SMP
-       smp_build_cpu_map();    /* happens, e.g., with the Ski simulator */
-# endif
 #endif /* CONFIG_APCI_BOOT */
 
+#ifdef CONFIG_SMP
+       smp_build_cpu_map();
+#endif
        find_memory();
 
        /* process SAL system table: */
@@ -855,18 +854,6 @@ identify_cpu (struct cpuinfo_ia64 *c)
        c->unimpl_pa_mask = ~((1L<<63) | ((1L << phys_addr_size) - 1));
 }
 
-/*
- * In UP configuration, setup_per_cpu_areas() is defined in
- * include/linux/percpu.h
- */
-#ifdef CONFIG_SMP
-void __init
-setup_per_cpu_areas (void)
-{
-       /* start_kernel() requires this... */
-}
-#endif
-
 /*
  * Do the following calculations:
  *
@@ -980,7 +967,7 @@ cpu_init (void)
         * depends on the data returned by identify_cpu().  We break the dependency by
         * accessing cpu_data() through the canonical per-CPU address.
         */
-       cpu_info = cpu_data + ((char *) &__ia64_per_cpu_var(cpu_info) - __per_cpu_start);
+       cpu_info = cpu_data + ((char *) &__ia64_per_cpu_var(ia64_cpu_info) - __per_cpu_start);
        identify_cpu(cpu_info);
 
 #ifdef CONFIG_MCKINLEY
index 0a0c77b2c9881cd01c9766b203ac0af7adefc95d..1295ba327f6ff2728f422079aedd6090bc51013b 100644 (file)
@@ -166,6 +166,12 @@ SECTIONS
        }
 #endif
 
+#ifdef CONFIG_SMP
+  . = ALIGN(PERCPU_PAGE_SIZE);
+  __cpu0_per_cpu = .;
+  . = . + PERCPU_PAGE_SIZE;    /* cpu0 per-cpu space */
+#endif
+
   . = ALIGN(PAGE_SIZE);
   __init_end = .;
 
@@ -198,11 +204,6 @@ SECTIONS
   data : { } :data
   .data : AT(ADDR(.data) - LOAD_OFFSET)
        {
-#ifdef CONFIG_SMP
-  . = ALIGN(PERCPU_PAGE_SIZE);
-               __cpu0_per_cpu = .;
-  . = . + PERCPU_PAGE_SIZE;    /* cpu0 per-cpu space */
-#endif
                INIT_TASK_DATA(PAGE_SIZE)
                CACHELINE_ALIGNED_DATA(SMP_CACHE_BYTES)
                READ_MOSTLY_DATA(SMP_CACHE_BYTES)
index 2f724d2bf2995d42251ed223bcca86ce2db21131..54bf540598118339a04919e1f08c505a5ad57cd8 100644 (file)
@@ -154,38 +154,99 @@ static void *cpu_data;
 void * __cpuinit
 per_cpu_init (void)
 {
-       int cpu;
-       static int first_time=1;
+       static bool first_time = true;
+       void *cpu0_data = __cpu0_per_cpu;
+       unsigned int cpu;
+
+       if (!first_time)
+               goto skip;
+       first_time = false;
 
        /*
-        * get_free_pages() cannot be used before cpu_init() done.  BSP
-        * allocates "NR_CPUS" pages for all CPUs to avoid that AP calls
-        * get_zeroed_page().
+        * get_free_pages() cannot be used before cpu_init() done.
+        * BSP allocates PERCPU_PAGE_SIZE bytes for all possible CPUs
+        * to avoid that AP calls get_zeroed_page().
         */
-       if (first_time) {
-               void *cpu0_data = __cpu0_per_cpu;
+       for_each_possible_cpu(cpu) {
+               void *src = cpu == 0 ? cpu0_data : __phys_per_cpu_start;
 
-               first_time=0;
+               memcpy(cpu_data, src, __per_cpu_end - __per_cpu_start);
+               __per_cpu_offset[cpu] = (char *)cpu_data - __per_cpu_start;
+               per_cpu(local_per_cpu_offset, cpu) = __per_cpu_offset[cpu];
 
-               __per_cpu_offset[0] = (char *) cpu0_data - __per_cpu_start;
-               per_cpu(local_per_cpu_offset, 0) = __per_cpu_offset[0];
+               /*
+                * percpu area for cpu0 is moved from the __init area
+                * which is setup by head.S and used till this point.
+                * Update ar.k3.  This move is ensures that percpu
+                * area for cpu0 is on the correct node and its
+                * virtual address isn't insanely far from other
+                * percpu areas which is important for congruent
+                * percpu allocator.
+                */
+               if (cpu == 0)
+                       ia64_set_kr(IA64_KR_PER_CPU_DATA, __pa(cpu_data) -
+                                   (unsigned long)__per_cpu_start);
 
-               for (cpu = 1; cpu < NR_CPUS; cpu++) {
-                       memcpy(cpu_data, __phys_per_cpu_start, __per_cpu_end - __per_cpu_start);
-                       __per_cpu_offset[cpu] = (char *) cpu_data - __per_cpu_start;
-                       cpu_data += PERCPU_PAGE_SIZE;
-                       per_cpu(local_per_cpu_offset, cpu) = __per_cpu_offset[cpu];
-               }
+               cpu_data += PERCPU_PAGE_SIZE;
        }
+skip:
        return __per_cpu_start + __per_cpu_offset[smp_processor_id()];
 }
 
 static inline void
 alloc_per_cpu_data(void)
 {
-       cpu_data = __alloc_bootmem(PERCPU_PAGE_SIZE * NR_CPUS-1,
+       cpu_data = __alloc_bootmem(PERCPU_PAGE_SIZE * num_possible_cpus(),
                                   PERCPU_PAGE_SIZE, __pa(MAX_DMA_ADDRESS));
 }
+
+/**
+ * setup_per_cpu_areas - setup percpu areas
+ *
+ * Arch code has already allocated and initialized percpu areas.  All
+ * this function has to do is to teach the determined layout to the
+ * dynamic percpu allocator, which happens to be more complex than
+ * creating whole new ones using helpers.
+ */
+void __init
+setup_per_cpu_areas(void)
+{
+       struct pcpu_alloc_info *ai;
+       struct pcpu_group_info *gi;
+       unsigned int cpu;
+       ssize_t static_size, reserved_size, dyn_size;
+       int rc;
+
+       ai = pcpu_alloc_alloc_info(1, num_possible_cpus());
+       if (!ai)
+               panic("failed to allocate pcpu_alloc_info");
+       gi = &ai->groups[0];
+
+       /* units are assigned consecutively to possible cpus */
+       for_each_possible_cpu(cpu)
+               gi->cpu_map[gi->nr_units++] = cpu;
+
+       /* set parameters */
+       static_size = __per_cpu_end - __per_cpu_start;
+       reserved_size = PERCPU_MODULE_RESERVE;
+       dyn_size = PERCPU_PAGE_SIZE - static_size - reserved_size;
+       if (dyn_size < 0)
+               panic("percpu area overflow static=%zd reserved=%zd\n",
+                     static_size, reserved_size);
+
+       ai->static_size         = static_size;
+       ai->reserved_size       = reserved_size;
+       ai->dyn_size            = dyn_size;
+       ai->unit_size           = PERCPU_PAGE_SIZE;
+       ai->atom_size           = PAGE_SIZE;
+       ai->alloc_size          = PERCPU_PAGE_SIZE;
+
+       rc = pcpu_setup_first_chunk(ai, __per_cpu_start + __per_cpu_offset[0]);
+       if (rc)
+               panic("failed to setup percpu area (err=%d)", rc);
+
+       pcpu_free_alloc_info(ai);
+}
 #else
 #define alloc_per_cpu_data() do { } while (0)
 #endif /* CONFIG_SMP */
@@ -270,8 +331,8 @@ paging_init (void)
 
                map_size = PAGE_ALIGN(ALIGN(max_low_pfn, MAX_ORDER_NR_PAGES) *
                        sizeof(struct page));
-               vmalloc_end -= map_size;
-               vmem_map = (struct page *) vmalloc_end;
+               VMALLOC_END -= map_size;
+               vmem_map = (struct page *) VMALLOC_END;
                efi_memmap_walk(create_mem_map_page_table, NULL);
 
                /*
index d85ba98d90087dea812636768a2f223e6a940fdf..19c4b2195dceef1af966bccf388c432050b1f3e3 100644 (file)
@@ -143,22 +143,120 @@ static void *per_cpu_node_setup(void *cpu_data, int node)
        int cpu;
 
        for_each_possible_early_cpu(cpu) {
-               if (cpu == 0) {
-                       void *cpu0_data = __cpu0_per_cpu;
-                       __per_cpu_offset[cpu] = (char*)cpu0_data -
-                               __per_cpu_start;
-               } else if (node == node_cpuid[cpu].nid) {
-                       memcpy(__va(cpu_data), __phys_per_cpu_start,
-                              __per_cpu_end - __per_cpu_start);
-                       __per_cpu_offset[cpu] = (char*)__va(cpu_data) -
-                               __per_cpu_start;
-                       cpu_data += PERCPU_PAGE_SIZE;
-               }
+               void *src = cpu == 0 ? __cpu0_per_cpu : __phys_per_cpu_start;
+
+               if (node != node_cpuid[cpu].nid)
+                       continue;
+
+               memcpy(__va(cpu_data), src, __per_cpu_end - __per_cpu_start);
+               __per_cpu_offset[cpu] = (char *)__va(cpu_data) -
+                       __per_cpu_start;
+
+               /*
+                * percpu area for cpu0 is moved from the __init area
+                * which is setup by head.S and used till this point.
+                * Update ar.k3.  This move is ensures that percpu
+                * area for cpu0 is on the correct node and its
+                * virtual address isn't insanely far from other
+                * percpu areas which is important for congruent
+                * percpu allocator.
+                */
+               if (cpu == 0)
+                       ia64_set_kr(IA64_KR_PER_CPU_DATA,
+                                   (unsigned long)cpu_data -
+                                   (unsigned long)__per_cpu_start);
+
+               cpu_data += PERCPU_PAGE_SIZE;
        }
 #endif
        return cpu_data;
 }
 
+#ifdef CONFIG_SMP
+/**
+ * setup_per_cpu_areas - setup percpu areas
+ *
+ * Arch code has already allocated and initialized percpu areas.  All
+ * this function has to do is to teach the determined layout to the
+ * dynamic percpu allocator, which happens to be more complex than
+ * creating whole new ones using helpers.
+ */
+void __init setup_per_cpu_areas(void)
+{
+       struct pcpu_alloc_info *ai;
+       struct pcpu_group_info *uninitialized_var(gi);
+       unsigned int *cpu_map;
+       void *base;
+       unsigned long base_offset;
+       unsigned int cpu;
+       ssize_t static_size, reserved_size, dyn_size;
+       int node, prev_node, unit, nr_units, rc;
+
+       ai = pcpu_alloc_alloc_info(MAX_NUMNODES, nr_cpu_ids);
+       if (!ai)
+               panic("failed to allocate pcpu_alloc_info");
+       cpu_map = ai->groups[0].cpu_map;
+
+       /* determine base */
+       base = (void *)ULONG_MAX;
+       for_each_possible_cpu(cpu)
+               base = min(base,
+                          (void *)(__per_cpu_offset[cpu] + __per_cpu_start));
+       base_offset = (void *)__per_cpu_start - base;
+
+       /* build cpu_map, units are grouped by node */
+       unit = 0;
+       for_each_node(node)
+               for_each_possible_cpu(cpu)
+                       if (node == node_cpuid[cpu].nid)
+                               cpu_map[unit++] = cpu;
+       nr_units = unit;
+
+       /* set basic parameters */
+       static_size = __per_cpu_end - __per_cpu_start;
+       reserved_size = PERCPU_MODULE_RESERVE;
+       dyn_size = PERCPU_PAGE_SIZE - static_size - reserved_size;
+       if (dyn_size < 0)
+               panic("percpu area overflow static=%zd reserved=%zd\n",
+                     static_size, reserved_size);
+
+       ai->static_size         = static_size;
+       ai->reserved_size       = reserved_size;
+       ai->dyn_size            = dyn_size;
+       ai->unit_size           = PERCPU_PAGE_SIZE;
+       ai->atom_size           = PAGE_SIZE;
+       ai->alloc_size          = PERCPU_PAGE_SIZE;
+
+       /*
+        * CPUs are put into groups according to node.  Walk cpu_map
+        * and create new groups at node boundaries.
+        */
+       prev_node = -1;
+       ai->nr_groups = 0;
+       for (unit = 0; unit < nr_units; unit++) {
+               cpu = cpu_map[unit];
+               node = node_cpuid[cpu].nid;
+
+               if (node == prev_node) {
+                       gi->nr_units++;
+                       continue;
+               }
+               prev_node = node;
+
+               gi = &ai->groups[ai->nr_groups++];
+               gi->nr_units            = 1;
+               gi->base_offset         = __per_cpu_offset[cpu] + base_offset;
+               gi->cpu_map             = &cpu_map[unit];
+       }
+
+       rc = pcpu_setup_first_chunk(ai, base);
+       if (rc)
+               panic("failed to setup percpu area (err=%d)", rc);
+
+       pcpu_free_alloc_info(ai);
+}
+#endif
+
 /**
  * fill_pernode - initialize pernode data.
  * @node: the node id.
@@ -352,7 +450,8 @@ static void __init initialize_pernode_data(void)
        /* Set the node_data pointer for each per-cpu struct */
        for_each_possible_early_cpu(cpu) {
                node = node_cpuid[cpu].nid;
-               per_cpu(cpu_info, cpu).node_data = mem_data[node].node_data;
+               per_cpu(ia64_cpu_info, cpu).node_data =
+                       mem_data[node].node_data;
        }
 #else
        {
@@ -360,7 +459,7 @@ static void __init initialize_pernode_data(void)
                cpu = 0;
                node = node_cpuid[cpu].nid;
                cpu0_cpu_info = (struct cpuinfo_ia64 *)(__phys_per_cpu_start +
-                       ((char *)&per_cpu__cpu_info - __per_cpu_start));
+                       ((char *)&per_cpu__ia64_cpu_info - __per_cpu_start));
                cpu0_cpu_info->node_data = mem_data[node].node_data;
        }
 #endif /* CONFIG_SMP */
@@ -666,9 +765,9 @@ void __init paging_init(void)
        sparse_init();
 
 #ifdef CONFIG_VIRTUAL_MEM_MAP
-       vmalloc_end -= PAGE_ALIGN(ALIGN(max_low_pfn, MAX_ORDER_NR_PAGES) *
+       VMALLOC_END -= PAGE_ALIGN(ALIGN(max_low_pfn, MAX_ORDER_NR_PAGES) *
                sizeof(struct page));
-       vmem_map = (struct page *) vmalloc_end;
+       vmem_map = (struct page *) VMALLOC_END;
        efi_memmap_walk(create_mem_map_page_table, NULL);
        printk("Virtual mem_map starts at 0x%p\n", vmem_map);
 #endif
index 1857766a63c1850d968320559471c22a851b6335..b9609c69343a373f5e742be333bcac7d24cf4381 100644 (file)
@@ -44,8 +44,8 @@ extern void ia64_tlb_init (void);
 unsigned long MAX_DMA_ADDRESS = PAGE_OFFSET + 0x100000000UL;
 
 #ifdef CONFIG_VIRTUAL_MEM_MAP
-unsigned long vmalloc_end = VMALLOC_END_INIT;
-EXPORT_SYMBOL(vmalloc_end);
+unsigned long VMALLOC_END = VMALLOC_END_INIT;
+EXPORT_SYMBOL(VMALLOC_END);
 struct page *vmem_map;
 EXPORT_SYMBOL(vmem_map);
 #endif
index 1176506b2baeb780e5cad3ba08cb533c54a801d8..e884ba4e031de4d1550cc2811a52a5a2c182db42 100644 (file)
@@ -496,13 +496,13 @@ static int sn2_ptc_seq_show(struct seq_file *file, void *data)
                seq_printf(file, "cpu %d %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld\n", cpu, stat->ptc_l,
                                stat->change_rid, stat->shub_ptc_flushes, stat->nodes_flushed,
                                stat->deadlocks,
-                               1000 * stat->lock_itc_clocks / per_cpu(cpu_info, cpu).cyc_per_usec,
-                               1000 * stat->shub_itc_clocks / per_cpu(cpu_info, cpu).cyc_per_usec,
-                               1000 * stat->shub_itc_clocks_max / per_cpu(cpu_info, cpu).cyc_per_usec,
+                               1000 * stat->lock_itc_clocks / per_cpu(ia64_cpu_info, cpu).cyc_per_usec,
+                               1000 * stat->shub_itc_clocks / per_cpu(ia64_cpu_info, cpu).cyc_per_usec,
+                               1000 * stat->shub_itc_clocks_max / per_cpu(ia64_cpu_info, cpu).cyc_per_usec,
                                stat->shub_ptc_flushes_not_my_mm,
                                stat->deadlocks2,
                                stat->shub_ipi_flushes,
-                               1000 * stat->shub_ipi_flushes_itc_clocks / per_cpu(cpu_info, cpu).cyc_per_usec);
+                               1000 * stat->shub_ipi_flushes_itc_clocks / per_cpu(ia64_cpu_info, cpu).cyc_per_usec);
        }
        return 0;
 }
index f042e192d2feadd4f32c0188154920771d225fae..a3fb7cf9ae1db1664217a7f7bd915b597ebeb483 100644 (file)
@@ -63,19 +63,19 @@ xen_free_irq_vector(int vector)
 }
 
 
-static DEFINE_PER_CPU(int, timer_irq) = -1;
-static DEFINE_PER_CPU(int, ipi_irq) = -1;
-static DEFINE_PER_CPU(int, resched_irq) = -1;
-static DEFINE_PER_CPU(int, cmc_irq) = -1;
-static DEFINE_PER_CPU(int, cmcp_irq) = -1;
-static DEFINE_PER_CPU(int, cpep_irq) = -1;
+static DEFINE_PER_CPU(int, xen_timer_irq) = -1;
+static DEFINE_PER_CPU(int, xen_ipi_irq) = -1;
+static DEFINE_PER_CPU(int, xen_resched_irq) = -1;
+static DEFINE_PER_CPU(int, xen_cmc_irq) = -1;
+static DEFINE_PER_CPU(int, xen_cmcp_irq) = -1;
+static DEFINE_PER_CPU(int, xen_cpep_irq) = -1;
 #define NAME_SIZE      15
-static DEFINE_PER_CPU(char[NAME_SIZE], timer_name);
-static DEFINE_PER_CPU(char[NAME_SIZE], ipi_name);
-static DEFINE_PER_CPU(char[NAME_SIZE], resched_name);
-static DEFINE_PER_CPU(char[NAME_SIZE], cmc_name);
-static DEFINE_PER_CPU(char[NAME_SIZE], cmcp_name);
-static DEFINE_PER_CPU(char[NAME_SIZE], cpep_name);
+static DEFINE_PER_CPU(char[NAME_SIZE], xen_timer_name);
+static DEFINE_PER_CPU(char[NAME_SIZE], xen_ipi_name);
+static DEFINE_PER_CPU(char[NAME_SIZE], xen_resched_name);
+static DEFINE_PER_CPU(char[NAME_SIZE], xen_cmc_name);
+static DEFINE_PER_CPU(char[NAME_SIZE], xen_cmcp_name);
+static DEFINE_PER_CPU(char[NAME_SIZE], xen_cpep_name);
 #undef NAME_SIZE
 
 struct saved_irq {
@@ -144,64 +144,64 @@ __xen_register_percpu_irq(unsigned int cpu, unsigned int vec,
        if (xen_slab_ready) {
                switch (vec) {
                case IA64_TIMER_VECTOR:
-                       snprintf(per_cpu(timer_name, cpu),
-                                sizeof(per_cpu(timer_name, cpu)),
+                       snprintf(per_cpu(xen_timer_name, cpu),
+                                sizeof(per_cpu(xen_timer_name, cpu)),
                                 "%s%d", action->name, cpu);
                        irq = bind_virq_to_irqhandler(VIRQ_ITC, cpu,
                                action->handler, action->flags,
-                               per_cpu(timer_name, cpu), action->dev_id);
-                       per_cpu(timer_irq, cpu) = irq;
+                               per_cpu(xen_timer_name, cpu), action->dev_id);
+                       per_cpu(xen_timer_irq, cpu) = irq;
                        break;
                case IA64_IPI_RESCHEDULE:
-                       snprintf(per_cpu(resched_name, cpu),
-                                sizeof(per_cpu(resched_name, cpu)),
+                       snprintf(per_cpu(xen_resched_name, cpu),
+                                sizeof(per_cpu(xen_resched_name, cpu)),
                                 "%s%d", action->name, cpu);
                        irq = bind_ipi_to_irqhandler(XEN_RESCHEDULE_VECTOR, cpu,
                                action->handler, action->flags,
-                               per_cpu(resched_name, cpu), action->dev_id);
-                       per_cpu(resched_irq, cpu) = irq;
+                               per_cpu(xen_resched_name, cpu), action->dev_id);
+                       per_cpu(xen_resched_irq, cpu) = irq;
                        break;
                case IA64_IPI_VECTOR:
-                       snprintf(per_cpu(ipi_name, cpu),
-                                sizeof(per_cpu(ipi_name, cpu)),
+                       snprintf(per_cpu(xen_ipi_name, cpu),
+                                sizeof(per_cpu(xen_ipi_name, cpu)),
                                 "%s%d", action->name, cpu);
                        irq = bind_ipi_to_irqhandler(XEN_IPI_VECTOR, cpu,
                                action->handler, action->flags,
-                               per_cpu(ipi_name, cpu), action->dev_id);
-                       per_cpu(ipi_irq, cpu) = irq;
+                               per_cpu(xen_ipi_name, cpu), action->dev_id);
+                       per_cpu(xen_ipi_irq, cpu) = irq;
                        break;
                case IA64_CMC_VECTOR:
-                       snprintf(per_cpu(cmc_name, cpu),
-                                sizeof(per_cpu(cmc_name, cpu)),
+                       snprintf(per_cpu(xen_cmc_name, cpu),
+                                sizeof(per_cpu(xen_cmc_name, cpu)),
                                 "%s%d", action->name, cpu);
                        irq = bind_virq_to_irqhandler(VIRQ_MCA_CMC, cpu,
-                                                     action->handler,
-                                                     action->flags,
-                                                     per_cpu(cmc_name, cpu),
-                                                     action->dev_id);
-                       per_cpu(cmc_irq, cpu) = irq;
+                                               action->handler,
+                                               action->flags,
+                                               per_cpu(xen_cmc_name, cpu),
+                                               action->dev_id);
+                       per_cpu(xen_cmc_irq, cpu) = irq;
                        break;
                case IA64_CMCP_VECTOR:
-                       snprintf(per_cpu(cmcp_name, cpu),
-                                sizeof(per_cpu(cmcp_name, cpu)),
+                       snprintf(per_cpu(xen_cmcp_name, cpu),
+                                sizeof(per_cpu(xen_cmcp_name, cpu)),
                                 "%s%d", action->name, cpu);
                        irq = bind_ipi_to_irqhandler(XEN_CMCP_VECTOR, cpu,
-                                                    action->handler,
-                                                    action->flags,
-                                                    per_cpu(cmcp_name, cpu),
-                                                    action->dev_id);
-                       per_cpu(cmcp_irq, cpu) = irq;
+                                               action->handler,
+                                               action->flags,
+                                               per_cpu(xen_cmcp_name, cpu),
+                                               action->dev_id);
+                       per_cpu(xen_cmcp_irq, cpu) = irq;
                        break;
                case IA64_CPEP_VECTOR:
-                       snprintf(per_cpu(cpep_name, cpu),
-                                sizeof(per_cpu(cpep_name, cpu)),
+                       snprintf(per_cpu(xen_cpep_name, cpu),
+                                sizeof(per_cpu(xen_cpep_name, cpu)),
                                 "%s%d", action->name, cpu);
                        irq = bind_ipi_to_irqhandler(XEN_CPEP_VECTOR, cpu,
-                                                    action->handler,
-                                                    action->flags,
-                                                    per_cpu(cpep_name, cpu),
-                                                    action->dev_id);
-                       per_cpu(cpep_irq, cpu) = irq;
+                                               action->handler,
+                                               action->flags,
+                                               per_cpu(xen_cpep_name, cpu),
+                                               action->dev_id);
+                       per_cpu(xen_cpep_irq, cpu) = irq;
                        break;
                case IA64_CPE_VECTOR:
                case IA64_MCA_RENDEZ_VECTOR:
@@ -275,30 +275,33 @@ unbind_evtchn_callback(struct notifier_block *nfb,
 
        if (action == CPU_DEAD) {
                /* Unregister evtchn.  */
-               if (per_cpu(cpep_irq, cpu) >= 0) {
-                       unbind_from_irqhandler(per_cpu(cpep_irq, cpu), NULL);
-                       per_cpu(cpep_irq, cpu) = -1;
+               if (per_cpu(xen_cpep_irq, cpu) >= 0) {
+                       unbind_from_irqhandler(per_cpu(xen_cpep_irq, cpu),
+                                              NULL);
+                       per_cpu(xen_cpep_irq, cpu) = -1;
                }
-               if (per_cpu(cmcp_irq, cpu) >= 0) {
-                       unbind_from_irqhandler(per_cpu(cmcp_irq, cpu), NULL);
-                       per_cpu(cmcp_irq, cpu) = -1;
+               if (per_cpu(xen_cmcp_irq, cpu) >= 0) {
+                       unbind_from_irqhandler(per_cpu(xen_cmcp_irq, cpu),
+                                              NULL);
+                       per_cpu(xen_cmcp_irq, cpu) = -1;
                }
-               if (per_cpu(cmc_irq, cpu) >= 0) {
-                       unbind_from_irqhandler(per_cpu(cmc_irq, cpu), NULL);
-                       per_cpu(cmc_irq, cpu) = -1;
+               if (per_cpu(xen_cmc_irq, cpu) >= 0) {
+                       unbind_from_irqhandler(per_cpu(xen_cmc_irq, cpu), NULL);
+                       per_cpu(xen_cmc_irq, cpu) = -1;
                }
-               if (per_cpu(ipi_irq, cpu) >= 0) {
-                       unbind_from_irqhandler(per_cpu(ipi_irq, cpu), NULL);
-                       per_cpu(ipi_irq, cpu) = -1;
+               if (per_cpu(xen_ipi_irq, cpu) >= 0) {
+                       unbind_from_irqhandler(per_cpu(xen_ipi_irq, cpu), NULL);
+                       per_cpu(xen_ipi_irq, cpu) = -1;
                }
-               if (per_cpu(resched_irq, cpu) >= 0) {
-                       unbind_from_irqhandler(per_cpu(resched_irq, cpu),
-                                               NULL);
-                       per_cpu(resched_irq, cpu) = -1;
+               if (per_cpu(xen_resched_irq, cpu) >= 0) {
+                       unbind_from_irqhandler(per_cpu(xen_resched_irq, cpu),
+                                              NULL);
+                       per_cpu(xen_resched_irq, cpu) = -1;
                }
-               if (per_cpu(timer_irq, cpu) >= 0) {
-                       unbind_from_irqhandler(per_cpu(timer_irq, cpu), NULL);
-                       per_cpu(timer_irq, cpu) = -1;
+               if (per_cpu(xen_timer_irq, cpu) >= 0) {
+                       unbind_from_irqhandler(per_cpu(xen_timer_irq, cpu),
+                                              NULL);
+                       per_cpu(xen_timer_irq, cpu) = -1;
                }
        }
        return NOTIFY_OK;
index dbeadb9c8e20550fd0e4a6ad4d2c84e7420430b9..c1c544513e8d0926a8a4bd879f0056240f067bb0 100644 (file)
 
 #include "../kernel/fsyscall_gtod_data.h"
 
-DEFINE_PER_CPU(struct vcpu_runstate_info, runstate);
-DEFINE_PER_CPU(unsigned long, processed_stolen_time);
-DEFINE_PER_CPU(unsigned long, processed_blocked_time);
+static DEFINE_PER_CPU(struct vcpu_runstate_info, xen_runstate);
+static DEFINE_PER_CPU(unsigned long, xen_stolen_time);
+static DEFINE_PER_CPU(unsigned long, xen_blocked_time);
 
 /* taken from i386/kernel/time-xen.c */
 static void xen_init_missing_ticks_accounting(int cpu)
 {
        struct vcpu_register_runstate_memory_area area;
-       struct vcpu_runstate_info *runstate = &per_cpu(runstate, cpu);
+       struct vcpu_runstate_info *runstate = &per_cpu(xen_runstate, cpu);
        int rc;
 
        memset(runstate, 0, sizeof(*runstate));
@@ -52,8 +52,8 @@ static void xen_init_missing_ticks_accounting(int cpu)
                                &area);
        WARN_ON(rc && rc != -ENOSYS);
 
-       per_cpu(processed_blocked_time, cpu) = runstate->time[RUNSTATE_blocked];
-       per_cpu(processed_stolen_time, cpu) = runstate->time[RUNSTATE_runnable]
+       per_cpu(xen_blocked_time, cpu) = runstate->time[RUNSTATE_blocked];
+       per_cpu(xen_stolen_time, cpu) = runstate->time[RUNSTATE_runnable]
                                            + runstate->time[RUNSTATE_offline];
 }
 
@@ -68,7 +68,7 @@ static void get_runstate_snapshot(struct vcpu_runstate_info *res)
 
        BUG_ON(preemptible());
 
-       state = &__get_cpu_var(runstate);
+       state = &__get_cpu_var(xen_runstate);
 
        /*
         * The runstate info is always updated by the hypervisor on
@@ -103,12 +103,12 @@ consider_steal_time(unsigned long new_itm)
         * This function just checks and reject this effect.
         */
        if (!time_after_eq(runstate.time[RUNSTATE_blocked],
-                          per_cpu(processed_blocked_time, cpu)))
+                          per_cpu(xen_blocked_time, cpu)))
                blocked = 0;
 
        if (!time_after_eq(runstate.time[RUNSTATE_runnable] +
                           runstate.time[RUNSTATE_offline],
-                          per_cpu(processed_stolen_time, cpu)))
+                          per_cpu(xen_stolen_time, cpu)))
                stolen = 0;
 
        if (!time_after(delta_itm + new_itm, ia64_get_itc()))
@@ -147,8 +147,8 @@ consider_steal_time(unsigned long new_itm)
                } else {
                        local_cpu_data->itm_next = delta_itm + new_itm;
                }
-               per_cpu(processed_stolen_time, cpu) += NS_PER_TICK * stolen;
-               per_cpu(processed_blocked_time, cpu) += NS_PER_TICK * blocked;
+               per_cpu(xen_stolen_time, cpu) += NS_PER_TICK * stolen;
+               per_cpu(xen_blocked_time, cpu) += NS_PER_TICK * blocked;
        }
        return delta_itm;
 }
index fe60e1abaee8900523cb827ea8d9ca1a410dcde8..aca0e28581c7733febbd2029a5c0a687f41b7485 100644 (file)
@@ -83,9 +83,9 @@
 #define VMALLOC_START (((unsigned long) high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
 #define VMALLOC_END KMAP_START
 #else
-extern unsigned long vmalloc_end;
+extern unsigned long m68k_vmalloc_end;
 #define VMALLOC_START 0x0f800000
-#define VMALLOC_END vmalloc_end
+#define VMALLOC_END m68k_vmalloc_end
 #endif /* CONFIG_SUN3 */
 
 /* zero page used for uninitialized stuff */
index 3cd19390aae51fcfa73ebe35b8c8075249cf780e..94f81ecfe3f83f91217dc1d721402d658e204dc5 100644 (file)
@@ -45,8 +45,8 @@
 ** Globals
 */
 
-unsigned long vmalloc_end;
-EXPORT_SYMBOL(vmalloc_end);
+unsigned long m68k_vmalloc_end;
+EXPORT_SYMBOL(m68k_vmalloc_end);
 
 unsigned long pmeg_vaddr[PMEGS_NUM];
 unsigned char pmeg_alloc[PMEGS_NUM];
@@ -172,8 +172,8 @@ void mmu_emu_init(unsigned long bootmem_end)
 #endif
                        // the lowest mapping here is the end of our
                        // vmalloc region
-                       if(!vmalloc_end)
-                               vmalloc_end = seg;
+                       if (!m68k_vmalloc_end)
+                               m68k_vmalloc_end = seg;
 
                        // mark the segmap alloc'd, and reserve any
                        // of the first 0xbff pages the hardware is
index bbd8327f18901d80d5eefe3e27015f65993a099f..fd53e500be67b21e5d48c96f9e745d8dfa0e158a 100644 (file)
@@ -6,8 +6,15 @@ mainmenu "Linux/Microblaze Kernel Configuration"
 config MICROBLAZE
        def_bool y
        select HAVE_LMB
+       select HAVE_FUNCTION_TRACER
+       select HAVE_FUNCTION_TRACE_MCOUNT_TEST
+       select HAVE_FUNCTION_GRAPH_TRACER
+       select HAVE_DYNAMIC_FTRACE
+       select HAVE_FTRACE_MCOUNT_RECORD
        select USB_ARCH_HAS_EHCI
        select ARCH_WANT_OPTIONAL_GPIOLIB
+       select HAVE_OPROFILE
+       select TRACING_SUPPORT
 
 config SWAP
        def_bool n
@@ -57,12 +64,24 @@ config GENERIC_GPIO
 config GENERIC_CSUM
        def_bool y
 
+config STACKTRACE_SUPPORT
+       def_bool y
+
+config LOCKDEP_SUPPORT
+       def_bool y
+
+config HAVE_LATENCYTOP_SUPPORT
+       def_bool y
+
 config PCI
        def_bool n
 
 config NO_DMA
        def_bool y
 
+config DTC
+       def_bool y
+
 source "init/Kconfig"
 
 source "kernel/Kconfig.freezer"
index 242cd35bdb4bfe22970a0110be801e98a410d616..9dc708a7f7005a5bf35f55c6b80654743a9b4e54 100644 (file)
@@ -3,6 +3,9 @@
 
 menu "Kernel hacking"
 
+config TRACE_IRQFLAGS_SUPPORT
+       def_bool y
+
 source "lib/Kconfig.debug"
 
 config EARLY_PRINTK
index 34187354304a6217d16ff3dab5315e605409ab05..d2d6cfcb1a3028bde39bad803094746713518d5d 100644 (file)
@@ -51,6 +51,8 @@ core-y += arch/microblaze/kernel/
 core-y += arch/microblaze/mm/
 core-y += arch/microblaze/platform/
 
+drivers-$(CONFIG_OPROFILE) += arch/microblaze/oprofile/
+
 boot := arch/microblaze/boot
 
 # Are we making a simpleImage.<boardname> target? If so, crack out the boardname
index 21f13322a4cad74da687055e50eb840804dda78b..902cf9846c3cb9b89f0940a8a635554cb265fd0b 100644 (file)
@@ -2,11 +2,13 @@
 # arch/microblaze/boot/Makefile
 #
 
+MKIMAGE := $(srctree)/scripts/mkuboot.sh
+
 obj-y += linked_dtb.o
 
 targets := linux.bin linux.bin.gz simpleImage.%
 
-OBJCOPYFLAGS_linux.bin  := -O binary
+OBJCOPYFLAGS := -O binary
 
 # Where the DTS files live
 dtstree         := $(srctree)/$(src)/dts
@@ -24,6 +26,7 @@ $(obj)/linux.bin: vmlinux FORCE
        [ -n $(CONFIG_INITRAMFS_SOURCE) ] && [ ! -e $(CONFIG_INITRAMFS_SOURCE) ] && \
        touch $(CONFIG_INITRAMFS_SOURCE) || echo "No CPIO image"
        $(call if_changed,objcopy)
+       $(call if_changed,uimage)
        @echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
 
 $(obj)/linux.bin.gz: $(obj)/linux.bin FORCE
@@ -36,8 +39,16 @@ quiet_cmd_cp = CP      $< $@$2
 quiet_cmd_strip = STRIP   $@
       cmd_strip = $(STRIP) -K _start -K _end -K __log_buf -K _fdt_start vmlinux -o $@
 
+quiet_cmd_uimage = UIMAGE  $@.ub
+      cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A microblaze -O linux -T kernel \
+                   -C none -n 'Linux-$(KERNELRELEASE)' \
+                   -a $(CONFIG_KERNEL_BASE_ADDR) -e $(CONFIG_KERNEL_BASE_ADDR) \
+                   -d $@ $@.ub
+
 $(obj)/simpleImage.%: vmlinux FORCE
        $(call if_changed,cp,.unstrip)
+       $(call if_changed,objcopy)
+       $(call if_changed,uimage)
        $(call if_changed,strip)
        @echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
 
@@ -53,4 +64,4 @@ $(obj)/%.dtb: $(dtstree)/%.dts FORCE
 
 clean-kernel += linux.bin linux.bin.gz simpleImage.*
 
-clean-files += *.dtb
+clean-files += *.dtb simpleImage.*.unstrip
index c209c47509d52435303c8b09008405fb14837afc..e52210891d78ed167a71e24ca35c1cd9abee6bf4 100644 (file)
 
 #define SMP_CACHE_BYTES        L1_CACHE_BYTES
 
-void _enable_icache(void);
-void _disable_icache(void);
-void _invalidate_icache(unsigned int addr);
-
-#define __enable_icache()              _enable_icache()
-#define __disable_icache()             _disable_icache()
-#define __invalidate_icache(addr)      _invalidate_icache(addr)
-
-void _enable_dcache(void);
-void _disable_dcache(void);
-void _invalidate_dcache(unsigned int addr);
-
-#define __enable_dcache()              _enable_dcache()
-#define __disable_dcache()             _disable_dcache()
-#define __invalidate_dcache(addr)      _invalidate_dcache(addr)
-
 #endif /* _ASM_MICROBLAZE_CACHE_H */
index 088076e657b32189ac16e6b9a9e3d0959740633a..a6edd356cd08c583807fb278913f943172f7ae20 100644 (file)
@@ -18,6 +18,8 @@
 /* Somebody depends on this; sigh... */
 #include <linux/mm.h>
 
+/* Look at Documentation/cachetlb.txt */
+
 /*
  * Cache handling functions.
  * Microblaze has a write-through data cache, meaning that the data cache
  * instruction cache to make sure we don't fetch old, bad code.
  */
 
+/* struct cache, d=dcache, i=icache, fl = flush, iv = invalidate,
+ * suffix r = range */
+struct scache {
+       /* icache */
+       void (*ie)(void); /* enable */
+       void (*id)(void); /* disable */
+       void (*ifl)(void); /* flush */
+       void (*iflr)(unsigned long a, unsigned long b);
+       void (*iin)(void); /* invalidate */
+       void (*iinr)(unsigned long a, unsigned long b);
+       /* dcache */
+       void (*de)(void); /* enable */
+       void (*dd)(void); /* disable */
+       void (*dfl)(void); /* flush */
+       void (*dflr)(unsigned long a, unsigned long b);
+       void (*din)(void); /* invalidate */
+       void (*dinr)(unsigned long a, unsigned long b);
+};
+
+/* microblaze cache */
+extern struct scache *mbc;
+
+void microblaze_cache_init(void);
+
+#define enable_icache()                                        mbc->ie();
+#define disable_icache()                               mbc->id();
+#define flush_icache()                                 mbc->ifl();
+#define flush_icache_range(start, end)                 mbc->iflr(start, end);
+#define invalidate_icache()                            mbc->iin();
+#define invalidate_icache_range(start, end)            mbc->iinr(start, end);
+
+
+#define flush_icache_user_range(vma, pg, adr, len)     flush_icache();
+#define flush_icache_page(vma, pg)                     do { } while (0)
+
+#define enable_dcache()                                        mbc->de();
+#define disable_dcache()                               mbc->dd();
 /* FIXME for LL-temac driver */
-#define invalidate_dcache_range(start, end) \
-                       __invalidate_dcache_range(start, end)
-
-#define flush_cache_all()                      __invalidate_cache_all()
-#define flush_cache_mm(mm)                     do { } while (0)
-#define flush_cache_range(vma, start, end)     __invalidate_cache_all()
-#define flush_cache_page(vma, vmaddr, pfn)     do { } while (0)
+#define invalidate_dcache()                            mbc->din();
+#define invalidate_dcache_range(start, end)            mbc->dinr(start, end);
+#define flush_dcache()                                 mbc->dfl();
+#define flush_dcache_range(start, end)                 mbc->dflr(start, end);
 
-#define flush_dcache_range(start, end) __invalidate_dcache_range(start, end)
 #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
+/* D-cache aliasing problem can't happen - cache is between MMU and ram */
 #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_icache_range(start, len) __invalidate_icache_range(start, len)
-#define flush_icache_page(vma, pg)             do { } while (0)
-
-#ifndef CONFIG_MMU
-# define flush_icache_user_range(start, len)   do { } while (0)
-#else
-# define flush_icache_user_range(vma, pg, adr, len) __invalidate_icache_all()
-
-# define flush_page_to_ram(page)               do { } while (0)
 
-# define flush_icache()                        __invalidate_icache_all()
-# define flush_cache_sigtramp(vaddr) \
-                       __invalidate_icache_range(vaddr, vaddr + 8)
-
-# define flush_dcache_mmap_lock(mapping)       do { } while (0)
-# define flush_dcache_mmap_unlock(mapping)     do { } while (0)
+#define flush_cache_dup_mm(mm)                         do { } while (0)
+#define flush_cache_vmap(start, end)                   do { } while (0)
+#define flush_cache_vunmap(start, end)                 do { } while (0)
+#define flush_cache_mm(mm)                     do { } while (0)
+#define flush_cache_page(vma, vmaddr, pfn)     do { } while (0)
 
-# define flush_cache_dup_mm(mm)                        do { } while (0)
+/* MS: kgdb code use this macro, wrong len with FLASH */
+#if 0
+#define flush_cache_range(vma, start, len)     {       \
+       flush_icache_range((unsigned) (start), (unsigned) (start) + (len)); \
+       flush_dcache_range((unsigned) (start), (unsigned) (start) + (len)); \
+}
 #endif
 
-#define flush_cache_vmap(start, end)           do { } while (0)
-#define flush_cache_vunmap(start, end)         do { } while (0)
-
-struct page;
-struct mm_struct;
-struct vm_area_struct;
-
-/* see arch/microblaze/kernel/cache.c */
-extern void __invalidate_icache_all(void);
-extern void __invalidate_icache_range(unsigned long start, unsigned long end);
-extern void __invalidate_icache_page(struct vm_area_struct *vma,
-                               struct page *page);
-extern void __invalidate_icache_user_range(struct vm_area_struct *vma,
-                               struct page *page,
-                               unsigned long adr, int len);
-extern void __invalidate_cache_sigtramp(unsigned long addr);
-
-extern void __invalidate_dcache_all(void);
-extern void __invalidate_dcache_range(unsigned long start, unsigned long end);
-extern void __invalidate_dcache_page(struct vm_area_struct *vma,
-                               struct page *page);
-extern void __invalidate_dcache_user_range(struct vm_area_struct *vma,
-                               struct page *page,
-                               unsigned long adr, int len);
-
-extern inline void __invalidate_cache_all(void)
-{
-       __invalidate_icache_all();
-       __invalidate_dcache_all();
-}
+#define flush_cache_range(vma, start, len) do { } while (0)
 
-#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
-do { memcpy((dst), (src), (len)); \
-       flush_icache_range((unsigned) (dst), (unsigned) (dst) + (len)); \
+#define copy_to_user_page(vma, page, vaddr, dst, src, len)             \
+do {                                                                   \
+       memcpy((dst), (src), (len));                                    \
+       flush_icache_range((unsigned) (dst), (unsigned) (dst) + (len)); \
 } while (0)
 
-#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
-       memcpy((dst), (src), (len))
+#define copy_from_user_page(vma, page, vaddr, dst, src, len)           \
+do {                                                                   \
+       memcpy((dst), (src), (len));                                    \
+} while (0)
 
 #endif /* _ASM_MICROBLAZE_CACHEFLUSH_H */
index 52f28f6dc4eb1b0985965d03f8fe9401a986c3f6..b4f5ca33aebf09a831226022ae0b9513c8344322 100644 (file)
@@ -43,7 +43,7 @@ struct cpuinfo {
        u32 use_icache;
        u32 icache_tagbits;
        u32 icache_write;
-       u32 icache_line;
+       u32 icache_line_length;
        u32 icache_size;
        unsigned long icache_base;
        unsigned long icache_high;
@@ -51,8 +51,9 @@ struct cpuinfo {
        u32 use_dcache;
        u32 dcache_tagbits;
        u32 dcache_write;
-       u32 dcache_line;
+       u32 dcache_line_length;
        u32 dcache_size;
+       u32 dcache_wb;
        unsigned long dcache_base;
        unsigned long dcache_high;
 
index 30286db27c1c2a08e94c513991deb2a4904d23c1..78a038452c0faa0106f3a0f7bb48e50e811c91da 100644 (file)
@@ -19,6 +19,18 @@ struct dev_archdata {
 struct pdev_archdata {
 };
 
+static inline void dev_archdata_set_node(struct dev_archdata *ad,
+                                        struct device_node *np)
+{
+       ad->of_node = np;
+}
+
+static inline struct device_node *
+dev_archdata_get_node(const struct dev_archdata *ad)
+{
+       return ad->of_node;
+}
+
 #endif /* _ASM_MICROBLAZE_DEVICE_H */
 
 
index 8b137891791fe96927ad78e64b0aad7bded08bdc..fd2fa2eca62f18fe2541300a8ffc5453632760d7 100644 (file)
@@ -1 +1,26 @@
+#ifndef _ASM_MICROBLAZE_FTRACE
+#define _ASM_MICROBLAZE_FTRACE
 
+#ifdef CONFIG_FUNCTION_TRACER
+
+#define MCOUNT_ADDR            ((long)(_mcount))
+#define MCOUNT_INSN_SIZE       8 /* sizeof mcount call */
+
+#ifndef __ASSEMBLY__
+extern void _mcount(void);
+extern void ftrace_call_graph(void);
+#endif
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+/* reloction of mcount call site is the same as the address */
+static inline unsigned long ftrace_call_adjust(unsigned long addr)
+{
+       return addr;
+}
+
+struct dyn_arch_ftrace {
+};
+#endif /* CONFIG_DYNAMIC_FTRACE */
+
+#endif /* CONFIG_FUNCTION_TRACER */
+#endif /* _ASM_MICROBLAZE_FTRACE */
index 0b745828f42bc9be46ded49786b887c9ad35df2d..8dbb6e7a03a2183c135656ca4fee82e302223885 100644 (file)
@@ -1 +1,126 @@
-#include <asm-generic/futex.h>
+#ifndef _ASM_MICROBLAZE_FUTEX_H
+#define _ASM_MICROBLAZE_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <linux/uaccess.h>
+#include <asm/errno.h>
+
+#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
+({                                                                     \
+       __asm__ __volatile__ (                                          \
+                       "1:     lwx     %0, %2, r0; "                   \
+                               insn                                    \
+                       "2:     swx     %1, %2, r0;                     \
+                               addic   %1, r0, 0;                      \
+                               bnei    %1, 1b;                         \
+                       3:                                              \
+                       .section .fixup,\"ax\";                         \
+                       4:      brid    3b;                             \
+                               addik   %1, r0, %3;                     \
+                       .previous;                                      \
+                       .section __ex_table,\"a\";                      \
+                       .word   1b,4b,2b,4b;                            \
+                       .previous;"                                     \
+       : "=&r" (oldval), "=&r" (ret)                                   \
+       : "b" (uaddr), "i" (-EFAULT), "r" (oparg)                       \
+       );                                                              \
+})
+
+static inline int
+futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
+{
+       int op = (encoded_op >> 28) & 7;
+       int cmp = (encoded_op >> 24) & 15;
+       int oparg = (encoded_op << 8) >> 20;
+       int cmparg = (encoded_op << 20) >> 20;
+       int oldval = 0, ret;
+       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+               oparg = 1 << oparg;
+
+       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+               return -EFAULT;
+
+       pagefault_disable();
+
+       switch (op) {
+       case FUTEX_OP_SET:
+               __futex_atomic_op("or %1,%4,%4;", ret, oldval, uaddr, oparg);
+               break;
+       case FUTEX_OP_ADD:
+               __futex_atomic_op("add %1,%0,%4;", ret, oldval, uaddr, oparg);
+               break;
+       case FUTEX_OP_OR:
+               __futex_atomic_op("or %1,%0,%4;", ret, oldval, uaddr, oparg);
+               break;
+       case FUTEX_OP_ANDN:
+               __futex_atomic_op("and %1,%0,%4;", ret, oldval, uaddr, oparg);
+               break;
+       case FUTEX_OP_XOR:
+               __futex_atomic_op("xor %1,%0,%4;", ret, oldval, uaddr, oparg);
+               break;
+       default:
+               ret = -ENOSYS;
+       }
+
+       pagefault_enable();
+
+       if (!ret) {
+               switch (cmp) {
+               case FUTEX_OP_CMP_EQ:
+                       ret = (oldval == cmparg);
+                       break;
+               case FUTEX_OP_CMP_NE:
+                       ret = (oldval != cmparg);
+                       break;
+               case FUTEX_OP_CMP_LT:
+                       ret = (oldval < cmparg);
+                       break;
+               case FUTEX_OP_CMP_GE:
+                       ret = (oldval >= cmparg);
+                       break;
+               case FUTEX_OP_CMP_LE:
+                       ret = (oldval <= cmparg);
+                       break;
+               case FUTEX_OP_CMP_GT:
+                       ret = (oldval > cmparg);
+                       break;
+               default:
+                       ret = -ENOSYS;
+               }
+       }
+       return ret;
+}
+
+static inline int
+futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+{
+       int prev, cmp;
+
+       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+               return -EFAULT;
+
+       __asm__ __volatile__ ("1:       lwx     %0, %2, r0;             \
+                                       cmp     %1, %0, %3;             \
+                                       beqi    %1, 3f;                 \
+                               2:      swx     %4, %2, r0;             \
+                                       addic   %1, r0, 0;              \
+                                       bnei    %1, 1b;                 \
+                               3:                                      \
+                               .section .fixup,\"ax\";                 \
+                               4:      brid    3b;                     \
+                                       addik   %0, r0, %5;             \
+                               .previous;                              \
+                               .section __ex_table,\"a\";              \
+                               .word   1b,4b,2b,4b;                    \
+                               .previous;"                             \
+               : "=&r" (prev), "=&r"(cmp)                              \
+               : "r" (uaddr), "r" (oldval), "r" (newval), "i" (-EFAULT));
+
+       return prev;
+}
+
+#endif /* __KERNEL__ */
+
+#endif
index dea65645a4f8d5d8cc591c534c6eec8adeb16b67..2c38c6d801769be469348fa80f4ef3283aab44e2 100644 (file)
 #define _ASM_MICROBLAZE_IRQFLAGS_H
 
 #include <linux/irqflags.h>
+#include <asm/registers.h>
 
 # if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
 
-# define local_irq_save(flags)                         \
+# define raw_local_irq_save(flags)                     \
        do {                                            \
-               asm volatile ("# local_irq_save \n\t"   \
-                               "msrclr %0, %1  \n\t"   \
-                               "nop    \n\t"           \
+               asm volatile (" msrclr %0, %1;          \
+                               nop;"                   \
                                : "=r"(flags)           \
                                : "i"(MSR_IE)           \
                                : "memory");            \
        } while (0)
 
-# define local_irq_disable()                                   \
-       do {                                                    \
-               asm volatile ("# local_irq_disable \n\t"        \
-                               "msrclr r0, %0 \n\t"            \
-                               "nop    \n\t"                   \
-                               :                               \
-                               : "i"(MSR_IE)                   \
-                               : "memory");                    \
+# define raw_local_irq_disable()                       \
+       do {                                            \
+               asm volatile (" msrclr r0, %0;          \
+                               nop;"                   \
+                               :                       \
+                               : "i"(MSR_IE)           \
+                               : "memory");            \
        } while (0)
 
-# define local_irq_enable()                                    \
-       do {                                                    \
-               asm volatile ("# local_irq_enable \n\t"         \
-                               "msrset r0, %0 \n\t"            \
-                               "nop    \n\t"                   \
-                               :                               \
-                               : "i"(MSR_IE)                   \
-                               : "memory");                    \
+# define raw_local_irq_enable()                                \
+       do {                                            \
+               asm volatile (" msrset  r0, %0;         \
+                               nop;"                   \
+                               :                       \
+                               : "i"(MSR_IE)           \
+                               : "memory");            \
        } while (0)
 
 # else /* CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR == 0 */
 
-# define local_irq_save(flags)                                 \
+# define raw_local_irq_save(flags)                             \
        do {                                                    \
                register unsigned tmp;                          \
-               asm volatile ("# local_irq_save \n\t"           \
-                               "mfs    %0, rmsr \n\t"          \
-                               "nop \n\t"                      \
-                               "andi   %1, %0, %2 \n\t"        \
-                               "mts    rmsr, %1 \n\t"          \
-                               "nop \n\t"                      \
+               asm volatile (" mfs     %0, rmsr;               \
+                               nop;                            \
+                               andi    %1, %0, %2;             \
+                               mts     rmsr, %1;               \
+                               nop;"                           \
                                : "=r"(flags), "=r" (tmp)       \
                                : "i"(~MSR_IE)                  \
                                : "memory");                    \
        } while (0)
 
-# define local_irq_disable()                                   \
+# define raw_local_irq_disable()                               \
        do {                                                    \
                register unsigned tmp;                          \
-               asm volatile ("# local_irq_disable \n\t"        \
-                               "mfs    %0, rmsr \n\t"          \
-                               "nop \n\t"                      \
-                               "andi   %0, %0, %1 \n\t"        \
-                               "mts    rmsr, %0 \n\t"          \
-                               "nop \n\t"                      \
+               asm volatile (" mfs     %0, rmsr;               \
+                               nop;                            \
+                               andi    %0, %0, %1;             \
+                               mts     rmsr, %0;               \
+                               nop;"                   \
                                : "=r"(tmp)                     \
                                : "i"(~MSR_IE)                  \
                                : "memory");                    \
        } while (0)
 
-# define local_irq_enable()                                    \
+# define raw_local_irq_enable()                                        \
        do {                                                    \
                register unsigned tmp;                          \
-               asm volatile ("# local_irq_enable \n\t"         \
-                               "mfs    %0, rmsr \n\t"          \
-                               "nop \n\t"                      \
-                               "ori    %0, %0, %1 \n\t"        \
-                               "mts    rmsr, %0 \n\t"          \
-                               "nop \n\t"                      \
+               asm volatile (" mfs     %0, rmsr;               \
+                               nop;                            \
+                               ori     %0, %0, %1;             \
+                               mts     rmsr, %0;               \
+                               nop;"                           \
                                : "=r"(tmp)                     \
                                : "i"(MSR_IE)                   \
                                : "memory");                    \
 
 # endif /* CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR */
 
-#define local_save_flags(flags)                                        \
+#define raw_local_irq_restore(flags)                           \
        do {                                                    \
-               asm volatile ("# local_save_flags \n\t"         \
-                               "mfs    %0, rmsr \n\t"          \
-                               "nop    \n\t"                   \
-                               : "=r"(flags)                   \
+               asm volatile (" mts     rmsr, %0;               \
+                               nop;"                           \
                                :                               \
+                               : "r"(flags)                    \
                                : "memory");                    \
        } while (0)
 
-#define local_irq_restore(flags)                       \
-       do {                                            \
-               asm volatile ("# local_irq_restore \n\t"\
-                               "mts    rmsr, %0 \n\t"  \
-                               "nop    \n\t"           \
-                               :                       \
-                               : "r"(flags)            \
-                               : "memory");            \
-       } while (0)
-
-static inline int irqs_disabled(void)
+static inline unsigned long get_msr(void)
 {
        unsigned long flags;
-
-       local_save_flags(flags);
-       return ((flags & MSR_IE) == 0);
+       asm volatile (" mfs     %0, rmsr;       \
+                       nop;"                   \
+                       : "=r"(flags)           \
+                       :                       \
+                       : "memory");            \
+       return flags;
 }
 
-#define raw_irqs_disabled irqs_disabled
-#define raw_irqs_disabled_flags(flags) ((flags) == 0)
+#define raw_local_save_flags(flags)    ((flags) = get_msr())
+#define raw_irqs_disabled()            ((get_msr() & MSR_IE) == 0)
+#define raw_irqs_disabled_flags(flags) ((flags & MSR_IE) == 0)
 
 #endif /* _ASM_MICROBLAZE_IRQFLAGS_H */
index 880c988c2237e2a333bbb7cc51c939a385ea9d07..9b66c0fa9a32caf5ba14e7f0c9478119808a0759 100644 (file)
@@ -164,7 +164,8 @@ extern int page_is_ram(unsigned long pfn);
 #  endif /* CONFIG_MMU */
 
 #  ifndef CONFIG_MMU
-#  define pfn_valid(pfn)       ((pfn) >= min_low_pfn && (pfn) <= max_mapnr)
+#  define pfn_valid(pfn)       (((pfn) >= min_low_pfn) && \
+                               ((pfn) <= (min_low_pfn + max_mapnr)))
 #  define ARCH_PFN_OFFSET      (PAGE_OFFSET >> PAGE_SHIFT)
 #  else /* CONFIG_MMU */
 #  define ARCH_PFN_OFFSET      (memory_start >> PAGE_SHIFT)
index b0131da1387bb131cd9e7666519eedb9591302e3..7547f50645608c9c34170e9680d3072b9e636a8d 100644 (file)
@@ -106,9 +106,6 @@ extern inline void free_pgd_slow(pgd_t *pgd)
  */
 #define pmd_alloc_one_fast(mm, address)        ({ BUG(); ((pmd_t *)1); })
 #define pmd_alloc_one(mm, address)     ({ BUG(); ((pmd_t *)2); })
-/* FIXME two definition - look below */
-#define pmd_free(mm, x)                        do { } while (0)
-#define pgd_populate(mm, pmd, pte)     BUG()
 
 static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
                unsigned long address)
@@ -192,14 +189,14 @@ extern inline void pte_free(struct mm_struct *mm, struct page *ptepage)
  * the pgd will always be present..
  */
 #define pmd_alloc_one(mm, address)     ({ BUG(); ((pmd_t *)2); })
-/*#define pmd_free(mm, x)                      do { } while (0)*/
-#define __pmd_free_tlb(tlb, x, addr)   do { } while (0)
+#define pmd_free(mm, x)                        do { } while (0)
+#define __pmd_free_tlb(tlb, x, addr)   pmd_free((tlb)->mm, x)
 #define pgd_populate(mm, pmd, pte)     BUG()
 
 extern int do_check_pgt_cache(int, int);
 
 #endif /* CONFIG_MMU */
 
-#define check_pgt_cache()      do {} while (0)
+#define check_pgt_cache()              do { } while (0)
 
 #endif /* _ASM_MICROBLAZE_PGALLOC_H */
index 66f1b30dd097db0fabde6ca1ddb475b71107b96a..e38abc7714b60bff43f11b2c52e5401cfd3e8db5 100644 (file)
@@ -76,20 +76,23 @@ struct pvr_s {
 #define PVR3_FSL_LINKS_MASK            0x00000380
 
 /* ICache config PVR masks */
-#define PVR4_USE_ICACHE_MASK           0x80000000
-#define PVR4_ICACHE_ADDR_TAG_BITS_MASK 0x7C000000
-#define PVR4_ICACHE_USE_FSL_MASK       0x02000000
-#define PVR4_ICACHE_ALLOW_WR_MASK      0x01000000
-#define PVR4_ICACHE_LINE_LEN_MASK      0x00E00000
-#define PVR4_ICACHE_BYTE_SIZE_MASK     0x001F0000
+#define PVR4_USE_ICACHE_MASK           0x80000000 /* ICU */
+#define PVR4_ICACHE_ADDR_TAG_BITS_MASK 0x7C000000 /* ICTS */
+#define PVR4_ICACHE_ALLOW_WR_MASK      0x01000000 /* ICW */
+#define PVR4_ICACHE_LINE_LEN_MASK      0x00E00000 /* ICLL */
+#define PVR4_ICACHE_BYTE_SIZE_MASK     0x001F0000 /* ICBS */
+#define PVR4_ICACHE_ALWAYS_USED                0x00008000 /* IAU */
+#define PVR4_ICACHE_INTERFACE          0x00002000 /* ICI */
 
 /* DCache config PVR masks */
-#define PVR5_USE_DCACHE_MASK           0x80000000
-#define PVR5_DCACHE_ADDR_TAG_BITS_MASK 0x7C000000
-#define PVR5_DCACHE_USE_FSL_MASK       0x02000000
-#define PVR5_DCACHE_ALLOW_WR_MASK      0x01000000
-#define PVR5_DCACHE_LINE_LEN_MASK      0x00E00000
-#define PVR5_DCACHE_BYTE_SIZE_MASK     0x001F0000
+#define PVR5_USE_DCACHE_MASK           0x80000000 /* DCU */
+#define PVR5_DCACHE_ADDR_TAG_BITS_MASK 0x7C000000 /* DCTS */
+#define PVR5_DCACHE_ALLOW_WR_MASK      0x01000000 /* DCW */
+#define PVR5_DCACHE_LINE_LEN_MASK      0x00E00000 /* DCLL */
+#define PVR5_DCACHE_BYTE_SIZE_MASK     0x001F0000 /* DCBS */
+#define PVR5_DCACHE_ALWAYS_USED                0x00008000 /* DAU */
+#define PVR5_DCACHE_USE_WRITEBACK      0x00004000 /* DWB */
+#define PVR5_DCACHE_INTERFACE          0x00002000 /* DCI */
 
 /* ICache base address PVR mask */
 #define PVR6_ICACHE_BASEADDR_MASK      0xFFFFFFFF
@@ -178,11 +181,14 @@ struct pvr_s {
                        ((pvr.pvr[5] & PVR5_DCACHE_ADDR_TAG_BITS_MASK) >> 26)
 #define PVR_DCACHE_USE_FSL(pvr)                (pvr.pvr[5] & PVR5_DCACHE_USE_FSL_MASK)
 #define PVR_DCACHE_ALLOW_WR(pvr)       (pvr.pvr[5] & PVR5_DCACHE_ALLOW_WR_MASK)
+/* FIXME two shifts on one line needs any comment */
 #define PVR_DCACHE_LINE_LEN(pvr) \
                        (1 << ((pvr.pvr[5] & PVR5_DCACHE_LINE_LEN_MASK) >> 21))
 #define PVR_DCACHE_BYTE_SIZE(pvr) \
                        (1 << ((pvr.pvr[5] & PVR5_DCACHE_BYTE_SIZE_MASK) >> 16))
 
+#define PVR_DCACHE_USE_WRITEBACK(pvr) \
+                       ((pvr.pvr[5] & PVR5_DCACHE_USE_WRITEBACK) >> 14)
 
 #define PVR_ICACHE_BASEADDR(pvr)       (pvr.pvr[6] & PVR6_ICACHE_BASEADDR_MASK)
 #define PVR_ICACHE_HIGHADDR(pvr)       (pvr.pvr[7] & PVR7_ICACHE_HIGHADDR_MASK)
index ed67c9ed15b8346f8752ff506b59ffe6e43afe17..7f31394985e05f5884d6848ab902de53f8c45ac4 100644 (file)
@@ -35,6 +35,8 @@ extern void mmu_reset(void);
 extern void early_console_reg_tlb_alloc(unsigned int addr);
 #   endif /* CONFIG_MMU */
 
+extern void of_platform_reset_gpio_probe(void);
+
 void time_init(void);
 void init_IRQ(void);
 void machine_early_init(const char *cmdline, unsigned int ram,
index b1ed6159066006bd3d635f57126316a12f25962a..157970688b2aba72037e94b4e08a96fc831184ac 100644 (file)
@@ -16,6 +16,8 @@
 #include <asm-generic/cmpxchg.h>
 #include <asm-generic/cmpxchg-local.h>
 
+#define __ARCH_WANT_INTERRUPTS_ON_CTXSW
+
 struct task_struct;
 struct thread_info;
 
index 5431b4631a7ad479bc23baf72de4563c68b8efb8..371bd6e56d9a20e60624147a050366f9fd06d2ea 100644 (file)
@@ -272,8 +272,9 @@ static inline int clear_user(char *to, int size)
        return size;
 }
 
-extern unsigned long __copy_tofrom_user(void __user *to,
-               const void __user *from, unsigned long size);
+#define __copy_from_user(to, from, n)  copy_from_user((to), (from), (n))
+#define __copy_from_user_inatomic(to, from, n) \
+               copy_from_user((to), (from), (n))
 
 #define copy_to_user(to, from, n)                                      \
        (access_ok(VERIFY_WRITE, (to), (n)) ?                           \
@@ -290,10 +291,6 @@ extern unsigned long __copy_tofrom_user(void __user *to,
                        (void __user *)(from), (n))                     \
                : -EFAULT)
 
-#define __copy_from_user(to, from, n)  copy_from_user((to), (from), (n))
-#define __copy_from_user_inatomic(to, from, n) \
-               copy_from_user((to), (from), (n))
-
 extern int __strncpy_user(char *to, const char __user *from, int len);
 extern int __strnlen_user(const char __user *sstr, int len);
 
@@ -305,6 +302,9 @@ extern int __strnlen_user(const char __user *sstr, int len);
 
 #endif /* CONFIG_MMU */
 
+extern unsigned long __copy_tofrom_user(void __user *to,
+               const void __user *from, unsigned long size);
+
 /*
  * The exception table consists of pairs of addresses: the first is the
  * address of an instruction that is allowed to fault, and the second is
index d487729683de8a0b66c6d082a8cefb096621687d..b07594eccf9b0d71c47e996bc33d22f61ffd39e4 100644 (file)
@@ -2,12 +2,22 @@
 # Makefile
 #
 
+ifdef CONFIG_FUNCTION_TRACER
+# Do not trace early boot code and low level code
+CFLAGS_REMOVE_timer.o = -pg
+CFLAGS_REMOVE_intc.o = -pg
+CFLAGS_REMOVE_early_printk.o = -pg
+CFLAGS_REMOVE_selfmod.o = -pg
+CFLAGS_REMOVE_heartbeat.o = -pg
+CFLAGS_REMOVE_ftrace.o = -pg
+endif
+
 extra-y := head.o vmlinux.lds
 
 obj-y += exceptions.o \
        hw_exception_handler.o init_task.o intc.o irq.o of_device.o \
        of_platform.o process.o prom.o prom_parse.o ptrace.o \
-       setup.o signal.o sys_microblaze.o timer.o traps.o
+       setup.o signal.o sys_microblaze.o timer.o traps.o reset.o
 
 obj-y += cpu/
 
@@ -16,5 +26,7 @@ obj-$(CONFIG_SELFMOD)         += selfmod.o
 obj-$(CONFIG_HEART_BEAT)       += heartbeat.o
 obj-$(CONFIG_MODULES)          += microblaze_ksyms.o module.o
 obj-$(CONFIG_MMU)              += misc.o
+obj-$(CONFIG_STACKTRACE)       += stacktrace.o
+obj-$(CONFIG_FUNCTION_TRACER)  += ftrace.o mcount.o
 
 obj-y  += entry$(MMU).o
index 20646e5492710bd51893e07e8452a0c481c32b07..59cc7bceaf8c493d35ef426e9bafaad914dbf3ab 100644 (file)
@@ -2,6 +2,10 @@
 # Build the appropriate CPU version support
 #
 
+ifdef CONFIG_FUNCTION_TRACER
+CFLAGS_REMOVE_cache.o = -pg
+endif
+
 EXTRA_CFLAGS += -DCPU_MAJOR=$(CPU_MAJOR) -DCPU_MINOR=$(CPU_MINOR) \
                -DCPU_REV=$(CPU_REV)
 
index af866a4501256a4028b0daa99c92ff40a8b40e69..d9d63831cc2f9d6318257fa358ac41d41553c789 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
  * Copyright (C) 2007-2009 PetaLogix
- * Copyright (C) 2007 John Williams <john.williams@petalogix.com>
+ * Copyright (C) 2007-2009 John Williams <john.williams@petalogix.com>
  *
  * This file is subject to the terms and conditions of the GNU General
  * Public License. See the file COPYING in the main directory of this
 #include <asm/cacheflush.h>
 #include <linux/cache.h>
 #include <asm/cpuinfo.h>
+#include <asm/pvr.h>
 
-/* Exported functions */
+static inline void __invalidate_flush_icache(unsigned int addr)
+{
+       __asm__ __volatile__ ("wic      %0, r0;"        \
+                                       : : "r" (addr));
+}
+
+static inline void __flush_dcache(unsigned int addr)
+{
+       __asm__ __volatile__ ("wdc.flush        %0, r0;"        \
+                                       : : "r" (addr));
+}
+
+static inline void __invalidate_dcache(unsigned int baseaddr,
+                                               unsigned int offset)
+{
+       __asm__ __volatile__ ("wdc.clear        %0, %1;"        \
+                                       : : "r" (baseaddr), "r" (offset));
+}
 
-void _enable_icache(void)
+static inline void __enable_icache_msr(void)
 {
-       if (cpuinfo.use_icache) {
-#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
-               __asm__ __volatile__ ("                                 \
-                               msrset  r0, %0;                         \
-                               nop; "                                  \
-                               :                                       \
-                               : "i" (MSR_ICE)                         \
+       __asm__ __volatile__ (" msrset  r0, %0;         \
+                               nop; "                  \
+                       : : "i" (MSR_ICE) : "memory");
+}
+
+static inline void __disable_icache_msr(void)
+{
+       __asm__ __volatile__ (" msrclr  r0, %0;         \
+                               nop; "                  \
+                       : : "i" (MSR_ICE) : "memory");
+}
+
+static inline void __enable_dcache_msr(void)
+{
+       __asm__ __volatile__ (" msrset  r0, %0;         \
+                               nop; "                  \
+                               :                       \
+                               : "i" (MSR_DCE)         \
                                : "memory");
-#else
-               __asm__ __volatile__ ("                                 \
-                               mfs     r12, rmsr;                      \
-                               nop;                                    \
-                               ori     r12, r12, %0;                   \
-                               mts     rmsr, r12;                      \
-                               nop; "                                  \
-                               :                                       \
-                               : "i" (MSR_ICE)                         \
-                               : "memory", "r12");
-#endif
-       }
 }
 
-void _disable_icache(void)
+static inline void __disable_dcache_msr(void)
 {
-       if (cpuinfo.use_icache) {
-#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
-               __asm__ __volatile__ ("                                 \
-                               msrclr r0, %0;                          \
-                               nop; "                                  \
-                               :                                       \
-                               : "i" (MSR_ICE)                         \
+       __asm__ __volatile__ (" msrclr  r0, %0;         \
+                               nop; "                  \
+                               :                       \
+                               : "i" (MSR_DCE)         \
                                : "memory");
-#else
-               __asm__ __volatile__ ("                                 \
-                               mfs     r12, rmsr;                      \
-                               nop;                                    \
-                               andi    r12, r12, ~%0;                  \
-                               mts     rmsr, r12;                      \
-                               nop; "                                  \
-                               :                                       \
-                               : "i" (MSR_ICE)                         \
+}
+
+static inline void __enable_icache_nomsr(void)
+{
+       __asm__ __volatile__ (" mfs     r12, rmsr;      \
+                               nop;                    \
+                               ori     r12, r12, %0;   \
+                               mts     rmsr, r12;      \
+                               nop; "                  \
+                               :                       \
+                               : "i" (MSR_ICE)         \
                                : "memory", "r12");
-#endif
-       }
 }
 
-void _invalidate_icache(unsigned int addr)
+static inline void __disable_icache_nomsr(void)
 {
-       if (cpuinfo.use_icache) {
-               __asm__ __volatile__ ("                                 \
-                               wic     %0, r0"                         \
-                               :                                       \
-                               : "r" (addr));
-       }
+       __asm__ __volatile__ (" mfs     r12, rmsr;      \
+                               nop;                    \
+                               andi    r12, r12, ~%0;  \
+                               mts     rmsr, r12;      \
+                               nop; "                  \
+                               :                       \
+                               : "i" (MSR_ICE)         \
+                               : "memory", "r12");
 }
 
-void _enable_dcache(void)
+static inline void __enable_dcache_nomsr(void)
 {
-       if (cpuinfo.use_dcache) {
-#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
-               __asm__ __volatile__ ("                                 \
-                               msrset  r0, %0;                         \
-                               nop; "                                  \
-                               :                                       \
-                               : "i" (MSR_DCE)                         \
-                               : "memory");
-#else
-               __asm__ __volatile__ ("                                 \
-                               mfs     r12, rmsr;                      \
-                               nop;                                    \
-                               ori     r12, r12, %0;                   \
-                               mts     rmsr, r12;                      \
-                               nop; "                                  \
-                               :                                       \
-                               : "i" (MSR_DCE)                 \
+       __asm__ __volatile__ (" mfs     r12, rmsr;      \
+                               nop;                    \
+                               ori     r12, r12, %0;   \
+                               mts     rmsr, r12;      \
+                               nop; "                  \
+                               :                       \
+                               : "i" (MSR_DCE)         \
                                : "memory", "r12");
-#endif
-       }
 }
 
-void _disable_dcache(void)
+static inline void __disable_dcache_nomsr(void)
 {
-#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
-               __asm__ __volatile__ ("                                 \
-                               msrclr  r0, %0;                         \
-                               nop; "                                  \
-                               :                                       \
-                               : "i" (MSR_DCE)                 \
-                               : "memory");
-#else
-               __asm__ __volatile__ ("                                 \
-                               mfs     r12, rmsr;                      \
-                               nop;                                    \
-                               andi    r12, r12, ~%0;                  \
-                               mts     rmsr, r12;                      \
-                               nop; "                                  \
-                               :                                       \
-                               : "i" (MSR_DCE)                 \
+       __asm__ __volatile__ (" mfs     r12, rmsr;      \
+                               nop;                    \
+                               andi    r12, r12, ~%0;  \
+                               mts     rmsr, r12;      \
+                               nop; "                  \
+                               :                       \
+                               : "i" (MSR_DCE)         \
                                : "memory", "r12");
-#endif
 }
 
-void _invalidate_dcache(unsigned int addr)
+
+/* Helper macro for computing the limits of cache range loops */
+#define CACHE_LOOP_LIMITS(start, end, cache_line_length, cache_size)   \
+do {                                                                   \
+       int align = ~(cache_line_length - 1);                           \
+       end = min(start + cache_size, end);                             \
+       start &= align;                                                 \
+       end = ((end & align) + cache_line_length);                      \
+} while (0);
+
+/*
+ * Helper macro to loop over the specified cache_size/line_length and
+ * execute 'op' on that cacheline
+ */
+#define CACHE_ALL_LOOP(cache_size, line_length, op)                    \
+do {                                                                   \
+       unsigned int len = cache_size;                                  \
+       int step = -line_length;                                        \
+       BUG_ON(step >= 0);                                              \
+                                                                       \
+       __asm__ __volatile__ (" 1:      " #op " %0, r0;                 \
+                                       bgtid   %0, 1b;                 \
+                                       addk    %0, %0, %1;             \
+                                       " : : "r" (len), "r" (step)     \
+                                       : "memory");                    \
+} while (0);
+
+
+#define CACHE_ALL_LOOP2(cache_size, line_length, op)                   \
+do {                                                                   \
+       unsigned int len = cache_size;                                  \
+       int step = -line_length;                                        \
+       BUG_ON(step >= 0);                                              \
+                                                                       \
+       __asm__ __volatile__ (" 1:      " #op " r0, %0;                 \
+                                       bgtid   %0, 1b;                 \
+                                       addk    %0, %0, %1;             \
+                                       " : : "r" (len), "r" (step)     \
+                                       : "memory");                    \
+} while (0);
+
+/* for wdc.flush/clear */
+#define CACHE_RANGE_LOOP_2(start, end, line_length, op)                        \
+do {                                                                   \
+       int step = -line_length;                                        \
+       int count = end - start;                                        \
+       BUG_ON(count <= 0);                                             \
+                                                                       \
+       __asm__ __volatile__ (" 1:      " #op " %0, %1;                 \
+                                       bgtid   %1, 1b;                 \
+                                       addk    %1, %1, %2;             \
+                                       " : : "r" (start), "r" (count), \
+                                       "r" (step) : "memory");         \
+} while (0);
+
+/* It is used only first parameter for OP - for wic, wdc */
+#define CACHE_RANGE_LOOP_1(start, end, line_length, op)                        \
+do {                                                                   \
+       int step = -line_length;                                        \
+       int count = end - start;                                        \
+       BUG_ON(count <= 0);                                             \
+                                                                       \
+       __asm__ __volatile__ (" 1:      addk    %0, %0, %1;             \
+                                       " #op " %0, r0;                 \
+                                       bgtid   %1, 1b;                 \
+                                       addk    %1, %1, %2;             \
+                                       " : : "r" (start), "r" (count), \
+                                       "r" (step) : "memory");         \
+} while (0);
+
+static void __flush_icache_range_msr_irq(unsigned long start, unsigned long end)
 {
-               __asm__ __volatile__ ("                                 \
-                               wdc     %0, r0"                         \
-                               :                                       \
-                               : "r" (addr));
+       unsigned long flags;
+
+       pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
+                               (unsigned int)start, (unsigned int) end);
+
+       CACHE_LOOP_LIMITS(start, end,
+                       cpuinfo.icache_line_length, cpuinfo.icache_size);
+
+       local_irq_save(flags);
+       __disable_icache_msr();
+
+       CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic);
+
+       __enable_icache_msr();
+       local_irq_restore(flags);
 }
 
-void __invalidate_icache_all(void)
+static void __flush_icache_range_nomsr_irq(unsigned long start,
+                               unsigned long end)
 {
-       unsigned int i;
-       unsigned flags;
+       unsigned long flags;
 
-       if (cpuinfo.use_icache) {
-               local_irq_save(flags);
-               __disable_icache();
+       pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
+                               (unsigned int)start, (unsigned int) end);
 
-               /* Just loop through cache size and invalidate, no need to add
-                       CACHE_BASE address */
-               for (i = 0; i < cpuinfo.icache_size;
-                       i += cpuinfo.icache_line)
-                               __invalidate_icache(i);
+       CACHE_LOOP_LIMITS(start, end,
+                       cpuinfo.icache_line_length, cpuinfo.icache_size);
 
-               __enable_icache();
-               local_irq_restore(flags);
-       }
+       local_irq_save(flags);
+       __disable_icache_nomsr();
+
+       CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic);
+
+       __enable_icache_nomsr();
+       local_irq_restore(flags);
 }
 
-void __invalidate_icache_range(unsigned long start, unsigned long end)
+static void __flush_icache_range_noirq(unsigned long start,
+                               unsigned long end)
 {
-       unsigned int i;
-       unsigned flags;
-       unsigned int align;
-
-       if (cpuinfo.use_icache) {
-               /*
-                * No need to cover entire cache range,
-                * just cover cache footprint
-                */
-               end = min(start + cpuinfo.icache_size, end);
-               align = ~(cpuinfo.icache_line - 1);
-               start &= align; /* Make sure we are aligned */
-               /* Push end up to the next cache line */
-               end = ((end & align) + cpuinfo.icache_line);
-
-               local_irq_save(flags);
-               __disable_icache();
-
-               for (i = start; i < end; i += cpuinfo.icache_line)
-                       __invalidate_icache(i);
-
-               __enable_icache();
-               local_irq_restore(flags);
-       }
+       pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
+                               (unsigned int)start, (unsigned int) end);
+
+       CACHE_LOOP_LIMITS(start, end,
+                       cpuinfo.icache_line_length, cpuinfo.icache_size);
+       CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic);
+}
+
+static void __flush_icache_all_msr_irq(void)
+{
+       unsigned long flags;
+
+       pr_debug("%s\n", __func__);
+
+       local_irq_save(flags);
+       __disable_icache_msr();
+
+       CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic);
+
+       __enable_icache_msr();
+       local_irq_restore(flags);
+}
+
+static void __flush_icache_all_nomsr_irq(void)
+{
+       unsigned long flags;
+
+       pr_debug("%s\n", __func__);
+
+       local_irq_save(flags);
+       __disable_icache_nomsr();
+
+       CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic);
+
+       __enable_icache_nomsr();
+       local_irq_restore(flags);
 }
 
-void __invalidate_icache_page(struct vm_area_struct *vma, struct page *page)
+static void __flush_icache_all_noirq(void)
 {
-       __invalidate_icache_all();
+       pr_debug("%s\n", __func__);
+       CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic);
 }
 
-void __invalidate_icache_user_range(struct vm_area_struct *vma,
-                               struct page *page, unsigned long adr,
-                               int len)
+static void __invalidate_dcache_all_msr_irq(void)
 {
-       __invalidate_icache_all();
+       unsigned long flags;
+
+       pr_debug("%s\n", __func__);
+
+       local_irq_save(flags);
+       __disable_dcache_msr();
+
+       CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc);
+
+       __enable_dcache_msr();
+       local_irq_restore(flags);
 }
 
-void __invalidate_cache_sigtramp(unsigned long addr)
+static void __invalidate_dcache_all_nomsr_irq(void)
 {
-       __invalidate_icache_range(addr, addr + 8);
+       unsigned long flags;
+
+       pr_debug("%s\n", __func__);
+
+       local_irq_save(flags);
+       __disable_dcache_nomsr();
+
+       CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc);
+
+       __enable_dcache_nomsr();
+       local_irq_restore(flags);
 }
 
-void __invalidate_dcache_all(void)
+static void __invalidate_dcache_all_noirq_wt(void)
 {
-       unsigned int i;
-       unsigned flags;
-
-       if (cpuinfo.use_dcache) {
-               local_irq_save(flags);
-               __disable_dcache();
-
-               /*
-                * Just loop through cache size and invalidate,
-                * no need to add CACHE_BASE address
-                */
-               for (i = 0; i < cpuinfo.dcache_size;
-                       i += cpuinfo.dcache_line)
-                               __invalidate_dcache(i);
-
-               __enable_dcache();
-               local_irq_restore(flags);
-       }
+       pr_debug("%s\n", __func__);
+       CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc)
 }
 
-void __invalidate_dcache_range(unsigned long start, unsigned long end)
+/* FIXME this is weird - should be only wdc but not work
+ * MS: I am getting bus errors and other weird things */
+static void __invalidate_dcache_all_wb(void)
 {
+       pr_debug("%s\n", __func__);
+       CACHE_ALL_LOOP2(cpuinfo.dcache_size, cpuinfo.dcache_line_length,
+                                       wdc.clear)
+
+#if 0
        unsigned int i;
-       unsigned flags;
-       unsigned int align;
-
-       if (cpuinfo.use_dcache) {
-               /*
-                * No need to cover entire cache range,
-                * just cover cache footprint
-                */
-               end = min(start + cpuinfo.dcache_size, end);
-               align = ~(cpuinfo.dcache_line - 1);
-               start &= align; /* Make sure we are aligned */
-               /* Push end up to the next cache line */
-               end = ((end & align) + cpuinfo.dcache_line);
-               local_irq_save(flags);
-               __disable_dcache();
-
-               for (i = start; i < end; i += cpuinfo.dcache_line)
-                       __invalidate_dcache(i);
-
-               __enable_dcache();
-               local_irq_restore(flags);
-       }
+
+       pr_debug("%s\n", __func__);
+
+       /* Just loop through cache size and invalidate it */
+       for (i = 0; i < cpuinfo.dcache_size; i += cpuinfo.dcache_line_length)
+                       __invalidate_dcache(0, i);
+#endif
+}
+
+static void __invalidate_dcache_range_wb(unsigned long start,
+                                               unsigned long end)
+{
+       pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
+                               (unsigned int)start, (unsigned int) end);
+
+       CACHE_LOOP_LIMITS(start, end,
+                       cpuinfo.dcache_line_length, cpuinfo.dcache_size);
+       CACHE_RANGE_LOOP_2(start, end, cpuinfo.dcache_line_length, wdc.clear);
+}
+
+static void __invalidate_dcache_range_nomsr_wt(unsigned long start,
+                                                       unsigned long end)
+{
+       pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
+                               (unsigned int)start, (unsigned int) end);
+       CACHE_LOOP_LIMITS(start, end,
+                       cpuinfo.dcache_line_length, cpuinfo.dcache_size);
+
+       CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc);
 }
 
-void __invalidate_dcache_page(struct vm_area_struct *vma, struct page *page)
+static void __invalidate_dcache_range_msr_irq_wt(unsigned long start,
+                                                       unsigned long end)
 {
-       __invalidate_dcache_all();
+       unsigned long flags;
+
+       pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
+                               (unsigned int)start, (unsigned int) end);
+       CACHE_LOOP_LIMITS(start, end,
+                       cpuinfo.dcache_line_length, cpuinfo.dcache_size);
+
+       local_irq_save(flags);
+       __disable_dcache_msr();
+
+       CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc);
+
+       __enable_dcache_msr();
+       local_irq_restore(flags);
+}
+
+static void __invalidate_dcache_range_nomsr_irq(unsigned long start,
+                                                       unsigned long end)
+{
+       unsigned long flags;
+
+       pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
+                               (unsigned int)start, (unsigned int) end);
+
+       CACHE_LOOP_LIMITS(start, end,
+                       cpuinfo.dcache_line_length, cpuinfo.dcache_size);
+
+       local_irq_save(flags);
+       __disable_dcache_nomsr();
+
+       CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc);
+
+       __enable_dcache_nomsr();
+       local_irq_restore(flags);
+}
+
+static void __flush_dcache_all_wb(void)
+{
+       pr_debug("%s\n", __func__);
+       CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length,
+                               wdc.flush);
 }
 
-void __invalidate_dcache_user_range(struct vm_area_struct *vma,
-                               struct page *page, unsigned long adr,
-                               int len)
+static void __flush_dcache_range_wb(unsigned long start, unsigned long end)
 {
-       __invalidate_dcache_all();
+       pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
+                               (unsigned int)start, (unsigned int) end);
+
+       CACHE_LOOP_LIMITS(start, end,
+                       cpuinfo.dcache_line_length, cpuinfo.dcache_size);
+       CACHE_RANGE_LOOP_2(start, end, cpuinfo.dcache_line_length, wdc.flush);
+}
+
+/* struct for wb caches and for wt caches */
+struct scache *mbc;
+
+/* new wb cache model */
+const struct scache wb_msr = {
+       .ie = __enable_icache_msr,
+       .id = __disable_icache_msr,
+       .ifl = __flush_icache_all_noirq,
+       .iflr = __flush_icache_range_noirq,
+       .iin = __flush_icache_all_noirq,
+       .iinr = __flush_icache_range_noirq,
+       .de = __enable_dcache_msr,
+       .dd = __disable_dcache_msr,
+       .dfl = __flush_dcache_all_wb,
+       .dflr = __flush_dcache_range_wb,
+       .din = __invalidate_dcache_all_wb,
+       .dinr = __invalidate_dcache_range_wb,
+};
+
+/* There is only difference in ie, id, de, dd functions */
+const struct scache wb_nomsr = {
+       .ie = __enable_icache_nomsr,
+       .id = __disable_icache_nomsr,
+       .ifl = __flush_icache_all_noirq,
+       .iflr = __flush_icache_range_noirq,
+       .iin = __flush_icache_all_noirq,
+       .iinr = __flush_icache_range_noirq,
+       .de = __enable_dcache_nomsr,
+       .dd = __disable_dcache_nomsr,
+       .dfl = __flush_dcache_all_wb,
+       .dflr = __flush_dcache_range_wb,
+       .din = __invalidate_dcache_all_wb,
+       .dinr = __invalidate_dcache_range_wb,
+};
+
+/* Old wt cache model with disabling irq and turn off cache */
+const struct scache wt_msr = {
+       .ie = __enable_icache_msr,
+       .id = __disable_icache_msr,
+       .ifl = __flush_icache_all_msr_irq,
+       .iflr = __flush_icache_range_msr_irq,
+       .iin = __flush_icache_all_msr_irq,
+       .iinr = __flush_icache_range_msr_irq,
+       .de = __enable_dcache_msr,
+       .dd = __disable_dcache_msr,
+       .dfl = __invalidate_dcache_all_msr_irq,
+       .dflr = __invalidate_dcache_range_msr_irq_wt,
+       .din = __invalidate_dcache_all_msr_irq,
+       .dinr = __invalidate_dcache_range_msr_irq_wt,
+};
+
+const struct scache wt_nomsr = {
+       .ie = __enable_icache_nomsr,
+       .id = __disable_icache_nomsr,
+       .ifl = __flush_icache_all_nomsr_irq,
+       .iflr = __flush_icache_range_nomsr_irq,
+       .iin = __flush_icache_all_nomsr_irq,
+       .iinr = __flush_icache_range_nomsr_irq,
+       .de = __enable_dcache_nomsr,
+       .dd = __disable_dcache_nomsr,
+       .dfl = __invalidate_dcache_all_nomsr_irq,
+       .dflr = __invalidate_dcache_range_nomsr_irq,
+       .din = __invalidate_dcache_all_nomsr_irq,
+       .dinr = __invalidate_dcache_range_nomsr_irq,
+};
+
+/* New wt cache model for newer Microblaze versions */
+const struct scache wt_msr_noirq = {
+       .ie = __enable_icache_msr,
+       .id = __disable_icache_msr,
+       .ifl = __flush_icache_all_noirq,
+       .iflr = __flush_icache_range_noirq,
+       .iin = __flush_icache_all_noirq,
+       .iinr = __flush_icache_range_noirq,
+       .de = __enable_dcache_msr,
+       .dd = __disable_dcache_msr,
+       .dfl = __invalidate_dcache_all_noirq_wt,
+       .dflr = __invalidate_dcache_range_nomsr_wt,
+       .din = __invalidate_dcache_all_noirq_wt,
+       .dinr = __invalidate_dcache_range_nomsr_wt,
+};
+
+const struct scache wt_nomsr_noirq = {
+       .ie = __enable_icache_nomsr,
+       .id = __disable_icache_nomsr,
+       .ifl = __flush_icache_all_noirq,
+       .iflr = __flush_icache_range_noirq,
+       .iin = __flush_icache_all_noirq,
+       .iinr = __flush_icache_range_noirq,
+       .de = __enable_dcache_nomsr,
+       .dd = __disable_dcache_nomsr,
+       .dfl = __invalidate_dcache_all_noirq_wt,
+       .dflr = __invalidate_dcache_range_nomsr_wt,
+       .din = __invalidate_dcache_all_noirq_wt,
+       .dinr = __invalidate_dcache_range_nomsr_wt,
+};
+
+/* CPU version code for 7.20.c - see arch/microblaze/kernel/cpu/cpuinfo.c */
+#define CPUVER_7_20_A  0x0c
+#define CPUVER_7_20_D  0x0f
+
+#define INFO(s)        printk(KERN_INFO "cache: " s " \n");
+
+void microblaze_cache_init(void)
+{
+       if (cpuinfo.use_instr & PVR2_USE_MSR_INSTR) {
+               if (cpuinfo.dcache_wb) {
+                       INFO("wb_msr");
+                       mbc = (struct scache *)&wb_msr;
+                       if (cpuinfo.ver_code < CPUVER_7_20_D) {
+                               /* MS: problem with signal handling - hw bug */
+                               INFO("WB won't work properly");
+                       }
+               } else {
+                       if (cpuinfo.ver_code >= CPUVER_7_20_A) {
+                               INFO("wt_msr_noirq");
+                               mbc = (struct scache *)&wt_msr_noirq;
+                       } else {
+                               INFO("wt_msr");
+                               mbc = (struct scache *)&wt_msr;
+                       }
+               }
+       } else {
+               if (cpuinfo.dcache_wb) {
+                       INFO("wb_nomsr");
+                       mbc = (struct scache *)&wb_nomsr;
+                       if (cpuinfo.ver_code < CPUVER_7_20_D) {
+                               /* MS: problem with signal handling - hw bug */
+                               INFO("WB won't work properly");
+                       }
+               } else {
+                       if (cpuinfo.ver_code >= CPUVER_7_20_A) {
+                               INFO("wt_nomsr_noirq");
+                               mbc = (struct scache *)&wt_nomsr_noirq;
+                       } else {
+                               INFO("wt_nomsr");
+                               mbc = (struct scache *)&wt_nomsr;
+                       }
+               }
+       }
 }
index c259786e7faa1c51853d3a0e31621ea1ddd154c7..f72dbd66c84411041c59705f72d253ee896af574 100644 (file)
  */
 
 #define CI(c, p) { ci->c = PVR_##p(pvr); }
+
+#if defined(CONFIG_EARLY_PRINTK) && defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
 #define err_printk(x) \
        early_printk("ERROR: Microblaze " x "-different for PVR and DTS\n");
+#else
+#define err_printk(x) \
+       printk(KERN_INFO "ERROR: Microblaze " x "-different for PVR and DTS\n");
+#endif
 
 void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu)
 {
@@ -70,7 +76,7 @@ void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu)
        CI(use_icache, USE_ICACHE);
        CI(icache_tagbits, ICACHE_ADDR_TAG_BITS);
        CI(icache_write, ICACHE_ALLOW_WR);
-       CI(icache_line, ICACHE_LINE_LEN);
+       ci->icache_line_length = PVR_ICACHE_LINE_LEN(pvr) << 2;
        CI(icache_size, ICACHE_BYTE_SIZE);
        CI(icache_base, ICACHE_BASEADDR);
        CI(icache_high, ICACHE_HIGHADDR);
@@ -78,11 +84,16 @@ void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu)
        CI(use_dcache, USE_DCACHE);
        CI(dcache_tagbits, DCACHE_ADDR_TAG_BITS);
        CI(dcache_write, DCACHE_ALLOW_WR);
-       CI(dcache_line, DCACHE_LINE_LEN);
+       ci->dcache_line_length = PVR_DCACHE_LINE_LEN(pvr) << 2;
        CI(dcache_size, DCACHE_BYTE_SIZE);
        CI(dcache_base, DCACHE_BASEADDR);
        CI(dcache_high, DCACHE_HIGHADDR);
 
+       temp = PVR_DCACHE_USE_WRITEBACK(pvr);
+       if (ci->dcache_wb != temp)
+               err_printk("DCACHE WB");
+       ci->dcache_wb = temp;
+
        CI(use_dopb, D_OPB);
        CI(use_iopb, I_OPB);
        CI(use_dlmb, D_LMB);
index adb448f93d5fd3157c89b2336ca52488da6ecb42..6095aa6b5c88ef17d6cdab7d7393d49dfd0ee286 100644 (file)
@@ -72,12 +72,12 @@ void __init set_cpuinfo_static(struct cpuinfo *ci, struct device_node *cpu)
        ci->use_icache = fcpu(cpu, "xlnx,use-icache");
        ci->icache_tagbits = fcpu(cpu, "xlnx,addr-tag-bits");
        ci->icache_write = fcpu(cpu, "xlnx,allow-icache-wr");
-       ci->icache_line = fcpu(cpu, "xlnx,icache-line-len") << 2;
-       if (!ci->icache_line) {
+       ci->icache_line_length = fcpu(cpu, "xlnx,icache-line-len") << 2;
+       if (!ci->icache_line_length) {
                if (fcpu(cpu, "xlnx,icache-use-fsl"))
-                       ci->icache_line = 4 << 2;
+                       ci->icache_line_length = 4 << 2;
                else
-                       ci->icache_line = 1 << 2;
+                       ci->icache_line_length = 1 << 2;
        }
        ci->icache_size = fcpu(cpu, "i-cache-size");
        ci->icache_base = fcpu(cpu, "i-cache-baseaddr");
@@ -86,16 +86,17 @@ void __init set_cpuinfo_static(struct cpuinfo *ci, struct device_node *cpu)
        ci->use_dcache = fcpu(cpu, "xlnx,use-dcache");
        ci->dcache_tagbits = fcpu(cpu, "xlnx,dcache-addr-tag");
        ci->dcache_write = fcpu(cpu, "xlnx,allow-dcache-wr");
-       ci->dcache_line = fcpu(cpu, "xlnx,dcache-line-len") << 2;
-       if (!ci->dcache_line) {
+       ci->dcache_line_length = fcpu(cpu, "xlnx,dcache-line-len") << 2;
+       if (!ci->dcache_line_length) {
                if (fcpu(cpu, "xlnx,dcache-use-fsl"))
-                       ci->dcache_line = 4 << 2;
+                       ci->dcache_line_length = 4 << 2;
                else
-                       ci->dcache_line = 1 << 2;
+                       ci->dcache_line_length = 1 << 2;
        }
        ci->dcache_size = fcpu(cpu, "d-cache-size");
        ci->dcache_base = fcpu(cpu, "d-cache-baseaddr");
        ci->dcache_high = fcpu(cpu, "d-cache-highaddr");
+       ci->dcache_wb = fcpu(cpu, "xlnx,dcache-use-writeback");
 
        ci->use_dopb = fcpu(cpu, "xlnx,d-opb");
        ci->use_iopb = fcpu(cpu, "xlnx,i-opb");
index 3539babc1c18ddb2ef59c3ae3e4c5ee2b571ca12..991d71311b0ebaad156a03e03f9f4f2cce277d30 100644 (file)
@@ -29,11 +29,8 @@ const struct cpu_ver_key cpu_ver_lookup[] = {
        {"7.20.a", 0x0c},
        {"7.20.b", 0x0d},
        {"7.20.c", 0x0e},
-       /* FIXME There is no keycode defined in MBV for these versions */
-       {"2.10.a", 0x10},
-       {"3.00.a", 0x20},
-       {"4.00.a", 0x30},
-       {"4.00.b", 0x40},
+       {"7.20.d", 0x0f},
+       {"7.30.a", 0x10},
        {NULL, 0},
 };
 
index 4dcfccdbc36480beec86d4fd24c31ccf0d8cdc6d..0c912b2a8e03ae72c1073ff94185595f18a3ab68 100644 (file)
@@ -103,11 +103,15 @@ static int show_cpuinfo(struct seq_file *m, void *v)
        else
                count += seq_printf(m, "Icache:\t\tno\n");
 
-       if (cpuinfo.use_dcache)
+       if (cpuinfo.use_dcache) {
                count += seq_printf(m,
                                "Dcache:\t\t%ukB\n",
                                cpuinfo.dcache_size >> 10);
-       else
+               if (cpuinfo.dcache_wb)
+                       count += seq_printf(m, "\t\twrite-back\n");
+               else
+                       count += seq_printf(m, "\t\twrite-through\n");
+       } else
                count += seq_printf(m, "Dcache:\t\tno\n");
 
        count += seq_printf(m,
index c9a4340ddd53d65a4cd171ea2d5622154208a72f..9bee9382bf74587031e01fde8e828f243683d147 100644 (file)
@@ -45,7 +45,7 @@
 
 int cpu_has_pvr(void)
 {
-       unsigned flags;
+       unsigned long flags;
        unsigned pvr0;
 
        local_save_flags(flags);
index 9083d85376a4dc57b6e7c535869eb4b3f11570f5..95b0855802dff0b342d77cfe279f1eaa23bf6828 100644 (file)
@@ -208,8 +208,6 @@ ENTRY(_user_exception)
        lwi     r1, r1, TS_THREAD_INFO          /* get the thread info */
        /* calculate kernel stack pointer */
        addik   r1, r1, THREAD_SIZE - PT_SIZE
-       swi     r11, r0, PER_CPU(R11_SAVE)      /* temporarily save r11 */
-       lwi     r11, r0, PER_CPU(KM)            /* load mode indicator */
 2:
        swi     r11, r1, PT_MODE                /* store the mode */
        lwi     r11, r0, PER_CPU(R11_SAVE)      /* reload r11 */
index e3ecb36dd554ebc3504e08ac369a29359e8c304f..3bad4ff494711c205b3536a686e4aa36d9913b94 100644 (file)
@@ -31,6 +31,8 @@
 #include <linux/errno.h>
 #include <asm/signal.h>
 
+#undef DEBUG
+
 /* The size of a state save frame. */
 #define STATE_SAVE_SIZE                (PT_SIZE + STATE_SAVE_ARG_SPACE)
 
@@ -352,10 +354,12 @@ C_ENTRY(_user_exception):
        add     r12, r12, r12;                  /* convert num -> ptr */
        add     r12, r12, r12;
 
+#ifdef DEBUG
        /* Trac syscalls and stored them to r0_ram */
        lwi     r3, r12, 0x400 + r0_ram
        addi    r3, r3, 1
        swi     r3, r12, 0x400 + r0_ram
+#endif
 
        # Find and jump into the syscall handler.
        lwi     r12, r12, sys_call_table
@@ -496,17 +500,6 @@ C_ENTRY(sys_execve):
        brid    microblaze_execve;      /* Do real work (tail-call).*/
        nop;
 
-C_ENTRY(sys_rt_sigsuspend_wrapper):
-       swi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
-       swi     r4, r1, PTO+PT_R4;
-       la      r7, r1, PTO;            /* add user context as 3rd arg */
-       brlid   r15, sys_rt_sigsuspend; /* Do real work.*/
-       nop;
-       lwi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
-       lwi     r4, r1, PTO+PT_R4;
-       bri ret_from_trap /* fall through will not work here due to align */
-       nop;
-
 C_ENTRY(sys_rt_sigreturn_wrapper):
        swi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
        swi     r4, r1, PTO+PT_R4;
@@ -711,15 +704,11 @@ C_ENTRY(ret_from_exc):
         * (in a possibly modified form) after do_signal returns.
         * store return registers separately because this macros is use
         * for others exceptions */
-       swi     r3, r1, PTO + PT_R3;
-       swi     r4, r1, PTO + PT_R4;
        la      r5, r1, PTO;            /* Arg 1: struct pt_regs *regs */
        add     r6, r0, r0;             /* Arg 2: sigset_t *oldset */
        addi    r7, r0, 0;              /* Arg 3: int in_syscall */
        bralid  r15, do_signal; /* Handle any signals */
        nop;
-       lwi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
-       lwi     r4, r1, PTO+PT_R4;
 
 /* Finally, return to user state.  */
 1:     swi     r0, r0, PER_CPU(KM);    /* Now officially in user state. */
diff --git a/arch/microblaze/kernel/ftrace.c b/arch/microblaze/kernel/ftrace.c
new file mode 100644 (file)
index 0000000..388b31c
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * Ftrace support for Microblaze.
+ *
+ * Copyright (C) 2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2009 PetaLogix
+ *
+ * Based on MIPS and PowerPC ftrace code
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <asm/cacheflush.h>
+#include <linux/ftrace.h>
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+/*
+ * Hook the return address and push it in the stack of return addrs
+ * in current thread info.
+ */
+void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
+{
+       unsigned long old;
+       int faulted, err;
+       struct ftrace_graph_ent trace;
+       unsigned long return_hooker = (unsigned long)
+                               &return_to_handler;
+
+       if (unlikely(atomic_read(&current->tracing_graph_pause)))
+               return;
+
+       /*
+        * Protect against fault, even if it shouldn't
+        * happen. This tool is too much intrusive to
+        * ignore such a protection.
+        */
+       asm volatile("  1:      lwi     %0, %2, 0;              \
+                       2:      swi     %3, %2, 0;              \
+                               addik   %1, r0, 0;              \
+                       3:                                      \
+                               .section .fixup, \"ax\";        \
+                       4:      brid    3b;                     \
+                               addik   %1, r0, 1;              \
+                               .previous;                      \
+                               .section __ex_table,\"a\";      \
+                               .word   1b,4b;                  \
+                               .word   2b,4b;                  \
+                               .previous;"                     \
+                       : "=&r" (old), "=r" (faulted)
+                       : "r" (parent), "r" (return_hooker)
+       );
+
+       if (unlikely(faulted)) {
+               ftrace_graph_stop();
+               WARN_ON(1);
+               return;
+       }
+
+       err = ftrace_push_return_trace(old, self_addr, &trace.depth, 0);
+       if (err == -EBUSY) {
+               *parent = old;
+               return;
+       }
+
+       trace.func = self_addr;
+       /* Only trace if the calling function expects to */
+       if (!ftrace_graph_entry(&trace)) {
+               current->curr_ret_stack--;
+               *parent = old;
+       }
+}
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+/* save value to addr - it is save to do it in asm */
+static int ftrace_modify_code(unsigned long addr, unsigned int value)
+{
+       int faulted = 0;
+
+       __asm__ __volatile__("  1:      swi     %2, %1, 0;              \
+                                       addik   %0, r0, 0;              \
+                               2:                                      \
+                                       .section .fixup, \"ax\";        \
+                               3:      brid    2b;                     \
+                                       addik   %0, r0, 1;              \
+                                       .previous;                      \
+                                       .section __ex_table,\"a\";      \
+                                       .word   1b,3b;                  \
+                                       .previous;"                     \
+                               : "=r" (faulted)
+                               : "r" (addr), "r" (value)
+       );
+
+       if (unlikely(faulted))
+               return -EFAULT;
+
+       return 0;
+}
+
+#define MICROBLAZE_NOP 0x80000000
+#define MICROBLAZE_BRI 0xb800000C
+
+static unsigned int recorded; /* if save was or not */
+static unsigned int imm; /* saving whole imm instruction */
+
+/* There are two approaches howto solve ftrace_make nop function - look below */
+#undef USE_FTRACE_NOP
+
+#ifdef USE_FTRACE_NOP
+static unsigned int bralid; /* saving whole bralid instruction */
+#endif
+
+int ftrace_make_nop(struct module *mod,
+                       struct dyn_ftrace *rec, unsigned long addr)
+{
+       /* we have this part of code which we are working with
+        * b000c000        imm     -16384
+        * b9fc8e30        bralid  r15, -29136     // c0008e30 <_mcount>
+        * 80000000        or      r0, r0, r0
+        *
+        * The first solution (!USE_FTRACE_NOP-could be called branch solution)
+        * b000c000        bri  12 (0xC - jump to any other instruction)
+        * b9fc8e30        bralid  r15, -29136     // c0008e30 <_mcount>
+        * 80000000        or      r0, r0, r0
+        * any other instruction
+        *
+        * The second solution (USE_FTRACE_NOP) - no jump just nops
+        * 80000000        or      r0, r0, r0
+        * 80000000        or      r0, r0, r0
+        * 80000000        or      r0, r0, r0
+        */
+       int ret = 0;
+
+       if (recorded == 0) {
+               recorded = 1;
+               imm = *(unsigned int *)rec->ip;
+               pr_debug("%s: imm:0x%x\n", __func__, imm);
+#ifdef USE_FTRACE_NOP
+               bralid = *(unsigned int *)(rec->ip + 4);
+               pr_debug("%s: bralid 0x%x\n", __func__, bralid);
+#endif /* USE_FTRACE_NOP */
+       }
+
+#ifdef USE_FTRACE_NOP
+       ret = ftrace_modify_code(rec->ip, MICROBLAZE_NOP);
+       ret += ftrace_modify_code(rec->ip + 4, MICROBLAZE_NOP);
+#else /* USE_FTRACE_NOP */
+       ret = ftrace_modify_code(rec->ip, MICROBLAZE_BRI);
+#endif /* USE_FTRACE_NOP */
+       return ret;
+}
+
+static int ret_addr; /* initialized as 0 by default */
+
+/* I believe that first is called ftrace_make_nop before this function */
+int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+{
+       int ret;
+       ret_addr = addr; /* saving where the barrier jump is */
+       pr_debug("%s: addr:0x%x, rec->ip: 0x%x, imm:0x%x\n",
+               __func__, (unsigned int)addr, (unsigned int)rec->ip, imm);
+       ret = ftrace_modify_code(rec->ip, imm);
+#ifdef USE_FTRACE_NOP
+       pr_debug("%s: bralid:0x%x\n", __func__, bralid);
+       ret += ftrace_modify_code(rec->ip + 4, bralid);
+#endif /* USE_FTRACE_NOP */
+       return ret;
+}
+
+int __init ftrace_dyn_arch_init(void *data)
+{
+       /* The return code is retured via data */
+       *(unsigned long *)data = 0;
+
+       return 0;
+}
+
+int ftrace_update_ftrace_func(ftrace_func_t func)
+{
+       unsigned long ip = (unsigned long)(&ftrace_call);
+       unsigned int upper = (unsigned int)func;
+       unsigned int lower = (unsigned int)func;
+       int ret = 0;
+
+       /* create proper saving to ftrace_call poll */
+       upper = 0xb0000000 + (upper >> 16); /* imm func_upper */
+       lower = 0x32800000 + (lower & 0xFFFF); /* addik r20, r0, func_lower */
+
+       pr_debug("%s: func=0x%x, ip=0x%x, upper=0x%x, lower=0x%x\n",
+               __func__, (unsigned int)func, (unsigned int)ip, upper, lower);
+
+       /* save upper and lower code */
+       ret = ftrace_modify_code(ip, upper);
+       ret += ftrace_modify_code(ip + 4, lower);
+
+       /* We just need to remove the rtsd r15, 8 by NOP */
+       BUG_ON(!ret_addr);
+       if (ret_addr)
+               ret += ftrace_modify_code(ret_addr, MICROBLAZE_NOP);
+       else
+               ret = 1; /* fault */
+
+       /* All changes are done - lets do caches consistent */
+       flush_icache();
+       return ret;
+}
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+unsigned int old_jump; /* saving place for jump instruction */
+
+int ftrace_enable_ftrace_graph_caller(void)
+{
+       unsigned int ret;
+       unsigned long ip = (unsigned long)(&ftrace_call_graph);
+
+       old_jump = *(unsigned int *)ip; /* save jump over instruction */
+       ret = ftrace_modify_code(ip, MICROBLAZE_NOP);
+       flush_icache();
+
+       pr_debug("%s: Replace instruction: 0x%x\n", __func__, old_jump);
+       return ret;
+}
+
+int ftrace_disable_ftrace_graph_caller(void)
+{
+       unsigned int ret;
+       unsigned long ip = (unsigned long)(&ftrace_call_graph);
+
+       ret = ftrace_modify_code(ip, old_jump);
+       flush_icache();
+
+       pr_debug("%s\n", __func__);
+       return ret;
+}
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+#endif /* CONFIG_DYNAMIC_FTRACE */
index 1bdf20222b92ba0ecdb0fe8b35488f7653ab6909..522751737cfad936fe5193a93fd0105c874c04cc 100644 (file)
@@ -45,6 +45,7 @@ void heartbeat(void)
 void setup_heartbeat(void)
 {
        struct device_node *gpio = NULL;
+       int *prop;
        int j;
        char *gpio_list[] = {
                                "xlnx,xps-gpio-1.00.a",
@@ -58,10 +59,14 @@ void setup_heartbeat(void)
                        break;
        }
 
-       base_addr = *(int *) of_get_property(gpio, "reg", NULL);
-       base_addr = (unsigned long) ioremap(base_addr, PAGE_SIZE);
-       printk(KERN_NOTICE "Heartbeat GPIO at 0x%x\n", base_addr);
+       if (gpio) {
+               base_addr = *(int *) of_get_property(gpio, "reg", NULL);
+               base_addr = (unsigned long) ioremap(base_addr, PAGE_SIZE);
+               printk(KERN_NOTICE "Heartbeat GPIO at 0x%x\n", base_addr);
 
-       if (*(int *) of_get_property(gpio, "xlnx,is-bidir", NULL))
-               out_be32(base_addr + 4, 0); /* GPIO is configured as output */
+               /* GPIO is configured as output */
+               prop = (int *) of_get_property(gpio, "xlnx,is-bidir", NULL);
+               if (prop)
+                       out_be32(base_addr + 4, 0);
+       }
 }
index 6eea6f92b84e19780b781bdad3da277fed57a4bb..03172c1da770c69eda75e8c72aca7a648c7ada53 100644 (file)
@@ -42,8 +42,16 @@ unsigned int nr_irq;
 
 static void intc_enable_or_unmask(unsigned int irq)
 {
+       unsigned long mask = 1 << irq;
        pr_debug("enable_or_unmask: %d\n", irq);
-       out_be32(INTC_BASE + SIE, 1 << irq);
+       out_be32(INTC_BASE + SIE, mask);
+
+       /* ack level irqs because they can't be acked during
+        * ack function since the handle_level_irq function
+        * acks the irq before calling the interrupt handler
+        */
+       if (irq_desc[irq].status & IRQ_LEVEL)
+               out_be32(INTC_BASE + IAR, mask);
 }
 
 static void intc_disable_or_mask(unsigned int irq)
diff --git a/arch/microblaze/kernel/mcount.S b/arch/microblaze/kernel/mcount.S
new file mode 100644 (file)
index 0000000..e7eaa7a
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Low-level ftrace handling
+ *
+ * Copyright (C) 2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2009 PetaLogix
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
+ */
+
+#include <linux/linkage.h>
+
+#define NOALIGN_ENTRY(name)    .globl name; name:
+
+/* FIXME MS: I think that I don't need to save all regs */
+#define SAVE_REGS              \
+       addik   r1, r1, -120;   \
+       swi     r2, r1, 4;      \
+       swi     r3, r1, 8;      \
+       swi     r4, r1, 12;     \
+       swi     r5, r1, 116;    \
+       swi     r6, r1, 16;     \
+       swi     r7, r1, 20;     \
+       swi     r8, r1, 24;     \
+       swi     r9, r1, 28;     \
+       swi     r10, r1, 32;    \
+       swi     r11, r1, 36;    \
+       swi     r12, r1, 40;    \
+       swi     r13, r1, 44;    \
+       swi     r14, r1, 48;    \
+       swi     r16, r1, 52;    \
+       swi     r17, r1, 56;    \
+       swi     r18, r1, 60;    \
+       swi     r19, r1, 64;    \
+       swi     r20, r1, 68;    \
+       swi     r21, r1, 72;    \
+       swi     r22, r1, 76;    \
+       swi     r23, r1, 80;    \
+       swi     r24, r1, 84;    \
+       swi     r25, r1, 88;    \
+       swi     r26, r1, 92;    \
+       swi     r27, r1, 96;    \
+       swi     r28, r1, 100;   \
+       swi     r29, r1, 104;   \
+       swi     r30, r1, 108;   \
+       swi     r31, r1, 112;
+
+#define RESTORE_REGS           \
+       lwi     r2, r1, 4;      \
+       lwi     r3, r1, 8;      \
+       lwi     r4, r1, 12;     \
+       lwi     r5, r1, 116;    \
+       lwi     r6, r1, 16;     \
+       lwi     r7, r1, 20;     \
+       lwi     r8, r1, 24;     \
+       lwi     r9, r1, 28;     \
+       lwi     r10, r1, 32;    \
+       lwi     r11, r1, 36;    \
+       lwi     r12, r1, 40;    \
+       lwi     r13, r1, 44;    \
+       lwi     r14, r1, 48;    \
+       lwi     r16, r1, 52;    \
+       lwi     r17, r1, 56;    \
+       lwi     r18, r1, 60;    \
+       lwi     r19, r1, 64;    \
+       lwi     r20, r1, 68;    \
+       lwi     r21, r1, 72;    \
+       lwi     r22, r1, 76;    \
+       lwi     r23, r1, 80;    \
+       lwi     r24, r1, 84;    \
+       lwi     r25, r1, 88;    \
+       lwi     r26, r1, 92;    \
+       lwi     r27, r1, 96;    \
+       lwi     r28, r1, 100;   \
+       lwi     r29, r1, 104;   \
+       lwi     r30, r1, 108;   \
+       lwi     r31, r1, 112;   \
+       addik   r1, r1, 120;
+
+ENTRY(ftrace_stub)
+       rtsd    r15, 8;
+       nop;
+
+ENTRY(_mcount)
+#ifdef CONFIG_DYNAMIC_FTRACE
+ENTRY(ftrace_caller)
+       /* MS: It is just barrier which is removed from C code */
+       rtsd    r15, 8
+       nop
+#endif /* CONFIG_DYNAMIC_FTRACE */
+       SAVE_REGS
+       swi     r15, r1, 0;
+       /* MS: HAVE_FUNCTION_TRACE_MCOUNT_TEST begin of checking */
+       lwi     r5, r0, function_trace_stop;
+       bneid   r5, end;
+       nop;
+       /* MS: HAVE_FUNCTION_TRACE_MCOUNT_TEST end of checking */
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+#ifndef CONFIG_DYNAMIC_FTRACE
+       lwi     r5, r0, ftrace_graph_return;
+       addik   r6, r0, ftrace_stub; /* asm implementation */
+       cmpu    r5, r5, r6; /* ftrace_graph_return != ftrace_stub */
+       beqid   r5, end_graph_tracer;
+       nop;
+
+       lwi     r6, r0, ftrace_graph_entry;
+       addik   r5, r0, ftrace_graph_entry_stub; /* implemented in C */
+       cmpu    r5, r5, r6; /* ftrace_graph_entry != ftrace_graph_entry_stub */
+       beqid   r5, end_graph_tracer;
+       nop;
+#else /* CONFIG_DYNAMIC_FTRACE */
+NOALIGN_ENTRY(ftrace_call_graph)
+       /* MS: jump over graph function - replaced from C code */
+       bri     end_graph_tracer
+#endif /* CONFIG_DYNAMIC_FTRACE */
+       addik   r5, r1, 120; /* MS: load parent addr */
+       addik   r6, r15, 0; /* MS: load current function addr */
+       bralid  r15, prepare_ftrace_return;
+       nop;
+       /* MS: graph was taken that's why - can jump over function trace */
+       brid    end;
+       nop;
+end_graph_tracer:
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+#ifndef CONFIG_DYNAMIC_FTRACE
+       /* MS: test function trace if is taken or not */
+       lwi     r20, r0, ftrace_trace_function;
+       addik   r6, r0, ftrace_stub;
+       cmpu    r5, r20, r6; /* ftrace_trace_function != ftrace_stub */
+       beqid   r5, end; /* MS: not taken -> jump over */
+       nop;
+#else /* CONFIG_DYNAMIC_FTRACE */
+NOALIGN_ENTRY(ftrace_call)
+/* instruction for setup imm FUNC_part1, addik r20, r0, FUNC_part2 */
+       nop
+       nop
+#endif /* CONFIG_DYNAMIC_FTRACE */
+/* static normal trace */
+       lwi     r6, r1, 120; /* MS: load parent addr */
+       addik   r5, r15, 0; /* MS: load current function addr */
+       /* MS: here is dependency on previous code */
+       brald   r15, r20; /* MS: jump to ftrace handler */
+       nop;
+end:
+       lwi     r15, r1, 0;
+       RESTORE_REGS
+
+       rtsd    r15, 8; /* MS: jump back */
+       nop;
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ENTRY(return_to_handler)
+       nop; /* MS: just barrier for rtsd r15, 8 */
+       nop;
+       SAVE_REGS
+       swi     r15, r1, 0;
+
+       /* MS: find out returning address */
+       bralid  r15, ftrace_return_to_handler;
+       nop;
+
+       /* MS: return value from ftrace_return_to_handler is my returning addr
+        * must be before restore regs because I have to restore r3 content */
+       addik   r15, r3, 0;
+       RESTORE_REGS
+
+       rtsd    r15, 8; /* MS: jump back */
+       nop;
+#endif /* CONFIG_FUNCTION_TRACER */
index 59ff20e33e0cde5b22b7f95fb0517323066c4440..bc4dcb7d3861c50aff24b152f37655c80c937d95 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/io.h>
 #include <asm/page.h>
 #include <asm/system.h>
+#include <linux/ftrace.h>
 #include <linux/uaccess.h>
 
 /*
@@ -47,3 +48,7 @@ extern void __umodsi3(void);
 EXPORT_SYMBOL(__umodsi3);
 extern char *_ebss;
 EXPORT_SYMBOL_GPL(_ebss);
+#ifdef CONFIG_FUNCTION_TRACER
+extern void _mcount(void);
+EXPORT_SYMBOL(_mcount);
+#endif
index c592d475b3d890a50061f8f3b265c4516457d749..812f1bf06c9e5cbfb2a88222974e2931d20f9a24 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/bitops.h>
 #include <asm/system.h>
 #include <asm/pgalloc.h>
+#include <asm/cacheflush.h>
 
 void show_regs(struct pt_regs *regs)
 {
diff --git a/arch/microblaze/kernel/reset.c b/arch/microblaze/kernel/reset.c
new file mode 100644 (file)
index 0000000..a1721a3
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2009 PetaLogix
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/of_platform.h>
+#include <asm/prom.h>
+
+/* Trigger specific functions */
+#ifdef CONFIG_GPIOLIB
+
+#include <linux/of_gpio.h>
+
+static int handle; /* reset pin handle */
+static unsigned int reset_val;
+
+static int of_reset_gpio_handle(void)
+{
+       int ret; /* variable which stored handle reset gpio pin */
+       struct device_node *root; /* root node */
+       struct device_node *gpio; /* gpio node */
+       struct of_gpio_chip *of_gc = NULL;
+       enum of_gpio_flags flags ;
+       const void *gpio_spec;
+
+       /* find out root node */
+       root = of_find_node_by_path("/");
+
+       /* give me handle for gpio node to be possible allocate pin */
+       ret = of_parse_phandles_with_args(root, "hard-reset-gpios",
+                               "#gpio-cells", 0, &gpio, &gpio_spec);
+       if (ret) {
+               pr_debug("%s: can't parse gpios property\n", __func__);
+               goto err0;
+       }
+
+       of_gc = gpio->data;
+       if (!of_gc) {
+               pr_debug("%s: gpio controller %s isn't registered\n",
+                        root->full_name, gpio->full_name);
+               ret = -ENODEV;
+               goto err1;
+       }
+
+       ret = of_gc->xlate(of_gc, root, gpio_spec, &flags);
+       if (ret < 0)
+               goto err1;
+
+       ret += of_gc->gc.base;
+err1:
+       of_node_put(gpio);
+err0:
+       pr_debug("%s exited with status %d\n", __func__, ret);
+       return ret;
+}
+
+void of_platform_reset_gpio_probe(void)
+{
+       int ret;
+       handle = of_reset_gpio_handle();
+
+       if (!gpio_is_valid(handle)) {
+               printk(KERN_INFO "Skipping unavailable RESET gpio %d (%s)\n",
+                               handle, "reset");
+       }
+
+       ret = gpio_request(handle, "reset");
+       if (ret < 0) {
+               printk(KERN_INFO "GPIO pin is already allocated\n");
+               return;
+       }
+
+       /* get current setup value */
+       reset_val = gpio_get_value(handle);
+       /* FIXME maybe worth to perform any action */
+       pr_debug("Reset: Gpio output state: 0x%x\n", reset_val);
+
+       /* Setup GPIO as output */
+       ret = gpio_direction_output(handle, 0);
+       if (ret < 0)
+               goto err;
+
+       /* Setup output direction */
+       gpio_set_value(handle, 0);
+
+       printk(KERN_INFO "RESET: Registered gpio device: %d, current val: %d\n",
+                                                       handle, reset_val);
+       return;
+err:
+       gpio_free(handle);
+       return;
+}
+
+
+static void gpio_system_reset(void)
+{
+       gpio_set_value(handle, 1 - reset_val);
+}
+#else
+#define gpio_system_reset() do {} while (0)
+void of_platform_reset_gpio_probe(void)
+{
+       return;
+}
+#endif
+
+void machine_restart(char *cmd)
+{
+       printk(KERN_NOTICE "Machine restart...\n");
+       gpio_system_reset();
+       dump_stack();
+       while (1)
+               ;
+}
+
+void machine_shutdown(void)
+{
+       printk(KERN_NOTICE "Machine shutdown...\n");
+       while (1)
+               ;
+}
+
+void machine_halt(void)
+{
+       printk(KERN_NOTICE "Machine halt...\n");
+       while (1)
+               ;
+}
+
+void machine_power_off(void)
+{
+       printk(KERN_NOTICE "Machine power off...\n");
+       while (1)
+               ;
+}
index 8c1e0f4dcf18b63c6323a3b8042c68c3774621e0..5372b24ad049cf92cfd881927c21f5e559a54089 100644 (file)
@@ -52,13 +52,12 @@ void __init setup_arch(char **cmdline_p)
        /* irq_early_init(); */
        setup_cpuinfo();
 
-       __invalidate_icache_all();
-       __enable_icache();
+       microblaze_cache_init();
 
-       __invalidate_dcache_all();
-       __enable_dcache();
+       enable_dcache();
 
-       panic_timeout = 120;
+       invalidate_icache();
+       enable_icache();
 
        setup_memory();
 
@@ -131,6 +130,8 @@ void __init machine_early_init(const char *cmdline, unsigned int ram,
                strlcpy(cmd_line, cmdline, COMMAND_LINE_SIZE);
 #endif
 
+       lockdep_init();
+
 /* initialize device tree for usage in early_printk */
        early_init_devtree((void *)_fdt_start);
 
@@ -186,32 +187,3 @@ static int microblaze_debugfs_init(void)
 }
 arch_initcall(microblaze_debugfs_init);
 #endif
-
-void machine_restart(char *cmd)
-{
-       printk(KERN_NOTICE "Machine restart...\n");
-       dump_stack();
-       while (1)
-               ;
-}
-
-void machine_shutdown(void)
-{
-       printk(KERN_NOTICE "Machine shutdown...\n");
-       while (1)
-               ;
-}
-
-void machine_halt(void)
-{
-       printk(KERN_NOTICE "Machine halt...\n");
-       while (1)
-               ;
-}
-
-void machine_power_off(void)
-{
-       printk(KERN_NOTICE "Machine power off...\n");
-       while (1)
-               ;
-}
index 1c80e4fc40cef1fc0513951c449452ff23139c96..d8d3bb396cd6d7e4b0d82d52fa62960222662ab3 100644 (file)
@@ -44,7 +44,6 @@
 
 asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_sycall);
 
-
 asmlinkage long
 sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
                struct pt_regs *regs)
@@ -176,6 +175,11 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        struct rt_sigframe __user *frame;
        int err = 0;
        int signal;
+       unsigned long address = 0;
+#ifdef CONFIG_MMU
+       pmd_t *pmdp;
+       pte_t *ptep;
+#endif
 
        frame = get_sigframe(ka, regs, sizeof(*frame));
 
@@ -216,8 +220,29 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
         Negative 8 offset because return is rtsd r15, 8 */
        regs->r15 = ((unsigned long)frame->tramp)-8;
 
-       __invalidate_cache_sigtramp((unsigned long)frame->tramp);
-
+       address = ((unsigned long)frame->tramp);
+#ifdef CONFIG_MMU
+       pmdp = pmd_offset(pud_offset(
+                       pgd_offset(current->mm, address),
+                                       address), address);
+
+       preempt_disable();
+       ptep = pte_offset_map(pmdp, address);
+       if (pte_present(*ptep)) {
+               address = (unsigned long) page_address(pte_page(*ptep));
+               /* MS: I need add offset in page */
+               address += ((unsigned long)frame->tramp) & ~PAGE_MASK;
+               /* MS address is virtual */
+               address = virt_to_phys(address);
+               invalidate_icache_range(address, address + 8);
+               flush_dcache_range(address, address + 8);
+       }
+       pte_unmap(ptep);
+       preempt_enable();
+#else
+       flush_icache_range(address, address + 8);
+       flush_dcache_range(address, address + 8);
+#endif
        if (err)
                goto give_sigsegv;
 
@@ -233,6 +258,10 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 
        set_fs(USER_DS);
 
+       /* the tracer may want to single-step inside the handler */
+       if (test_thread_flag(TIF_SINGLESTEP))
+               ptrace_notify(SIGTRAP);
+
 #ifdef DEBUG_SIG
        printk(KERN_INFO "SIG deliver (%s:%d): sp=%p pc=%08lx\n",
                current->comm, current->pid, frame, regs->pc);
diff --git a/arch/microblaze/kernel/stacktrace.c b/arch/microblaze/kernel/stacktrace.c
new file mode 100644 (file)
index 0000000..123692f
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Stack trace support for Microblaze.
+ *
+ * Copyright (C) 2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2009 PetaLogix
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/sched.h>
+#include <linux/stacktrace.h>
+#include <linux/thread_info.h>
+#include <linux/ptrace.h>
+#include <linux/module.h>
+
+/* FIXME initial support */
+void save_stack_trace(struct stack_trace *trace)
+{
+       unsigned long *sp;
+       unsigned long addr;
+       asm("addik %0, r1, 0" : "=r" (sp));
+
+       while (!kstack_end(sp)) {
+               addr = *sp++;
+               if (__kernel_text_address(addr)) {
+                       if (trace->skip > 0)
+                               trace->skip--;
+                       else
+                               trace->entries[trace->nr_entries++] = addr;
+
+                       if (trace->nr_entries >= trace->max_entries)
+                               break;
+               }
+       }
+}
+EXPORT_SYMBOL_GPL(save_stack_trace);
+
+void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
+{
+       unsigned int *sp;
+       unsigned long addr;
+
+       struct thread_info *ti = task_thread_info(tsk);
+
+       if (tsk == current)
+               asm("addik %0, r1, 0" : "=r" (sp));
+       else
+               sp = (unsigned int *)ti->cpu_context.r1;
+
+       while (!kstack_end(sp)) {
+               addr = *sp++;
+               if (__kernel_text_address(addr)) {
+                       if (trace->skip > 0)
+                               trace->skip--;
+                       else
+                               trace->entries[trace->nr_entries++] = addr;
+
+                       if (trace->nr_entries >= trace->max_entries)
+                               break;
+               }
+       }
+}
+EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
index b96f365ea6b1aaf46d5d9c1026f8ae9fbac7afa1..4088be7d4e292ed307cdf4539df4f2b5adfc06be 100644 (file)
@@ -183,7 +183,7 @@ ENTRY(sys_call_table)
        .long sys_rt_sigpending
        .long sys_rt_sigtimedwait
        .long sys_rt_sigqueueinfo
-       .long sys_rt_sigsuspend_wrapper
+       .long sys_rt_sigsuspend
        .long sys_pread64               /* 180 */
        .long sys_pwrite64
        .long sys_chown
@@ -303,7 +303,7 @@ ENTRY(sys_call_table)
        .long sys_mkdirat
        .long sys_mknodat
        .long sys_fchownat
-       .long sys_ni_syscall
+       .long sys_futimesat
        .long sys_fstatat64             /* 300 */
        .long sys_unlinkat
        .long sys_renameat
index 5499deae7fa68cb155e4e6aefe9b53c0da8c7298..ed61b2f177192e79921fae4e95092374309a3c0f 100644 (file)
@@ -183,6 +183,31 @@ static cycle_t microblaze_read(struct clocksource *cs)
        return (cycle_t) (in_be32(TIMER_BASE + TCR1));
 }
 
+static struct timecounter microblaze_tc = {
+       .cc = NULL,
+};
+
+static cycle_t microblaze_cc_read(const struct cyclecounter *cc)
+{
+       return microblaze_read(NULL);
+}
+
+static struct cyclecounter microblaze_cc = {
+       .read = microblaze_cc_read,
+       .mask = CLOCKSOURCE_MASK(32),
+       .shift = 24,
+};
+
+int __init init_microblaze_timecounter(void)
+{
+       microblaze_cc.mult = div_sc(cpuinfo.cpu_clock_freq, NSEC_PER_SEC,
+                               microblaze_cc.shift);
+
+       timecounter_init(&microblaze_tc, &microblaze_cc, sched_clock());
+
+       return 0;
+}
+
 static struct clocksource clocksource_microblaze = {
        .name           = "microblaze_clocksource",
        .rating         = 300,
@@ -204,6 +229,9 @@ static int __init microblaze_clocksource_init(void)
        out_be32(TIMER_BASE + TCSR1, in_be32(TIMER_BASE + TCSR1) & ~TCSR_ENT);
        /* start timer1 - up counting without interrupt */
        out_be32(TIMER_BASE + TCSR1, TCSR_TINT|TCSR_ENT|TCSR_ARHT);
+
+       /* register timecounter - for ftrace support */
+       init_microblaze_timecounter();
        return 0;
 }
 
index e704188d7855ec6115ddef659505ffba6b6d5578..5ef619aad6341b8ecd6ca021c03dd4b74d418653 100644 (file)
@@ -26,11 +26,12 @@ SECTIONS {
                _stext = . ;
                *(.text .text.*)
                *(.fixup)
-               EXIT_TEXT
-               EXIT_CALL
+               EXIT_TEXT
+               EXIT_CALL
                SCHED_TEXT
                LOCK_TEXT
                KPROBES_TEXT
+               IRQENTRY_TEXT
                . = ALIGN (4) ;
                _etext = . ;
        }
@@ -86,6 +87,7 @@ SECTIONS {
                _KERNEL_SDA_BASE_ = _ssro + (_ssro_size / 2) ;
        }
 
+       . = ALIGN(PAGE_SIZE);
        __init_begin = .;
 
        INIT_TEXT_SECTION(PAGE_SIZE)
index 8eb9df5a26c9f53ad53a298330039e1e88898295..a853fe089c44a402c4e53e41b65792ebca5c2f09 100644 (file)
@@ -39,3 +39,10 @@ long strncpy_from_user(char *dst, const char __user *src, long count)
                __do_strncpy_from_user(dst, src, count, res);
        return res;
 }
+
+unsigned long __copy_tofrom_user(void __user *to,
+               const void __user *from, unsigned long size)
+{
+       memcpy(to, from, size);
+       return 0;
+}
index a44892e7cd5b7e2839976585e69bc8c274c21509..a57cedf36715f7511395b3066878731b107edb1e 100644 (file)
@@ -41,6 +41,7 @@ char *klimit = _end;
  * have available.
  */
 unsigned long memory_start;
+EXPORT_SYMBOL(memory_start);
 unsigned long memory_end; /* due to mm/nommu.c */
 unsigned long memory_size;
 
index 46c4ca5d15c55f4d573ad9248c2eec1a9ab65478..2820081b21ab8bc4a9b87c5147f3516cfb674c4a 100644 (file)
@@ -144,7 +144,6 @@ int map_page(unsigned long va, phys_addr_t pa, int flags)
        pmd_t *pd;
        pte_t *pg;
        int err = -ENOMEM;
-       /* spin_lock(&init_mm.page_table_lock); */
        /* Use upper 10 bits of VA to index the first level map */
        pd = pmd_offset(pgd_offset_k(va), va);
        /* Use middle 10 bits of VA to index the second-level map */
@@ -158,9 +157,7 @@ int map_page(unsigned long va, phys_addr_t pa, int flags)
                if (mem_init_done)
                        flush_HPTE(0, va, pmd_val(*pd));
                        /* flush_HPTE(0, va, pg); */
-
        }
-       /* spin_unlock(&init_mm.page_table_lock); */
        return err;
 }
 
@@ -182,12 +179,6 @@ void __init adjust_total_lowmem(void)
 #endif
 }
 
-static void show_tmem(unsigned long tmem)
-{
-       volatile unsigned long a;
-       a = a + tmem;
-}
-
 /*
  * Map in all of physical memory starting at CONFIG_KERNEL_START.
  */
@@ -197,7 +188,6 @@ void __init mapin_ram(void)
 
        v = CONFIG_KERNEL_START;
        p = memory_start;
-       show_tmem(memory_size);
        for (s = 0; s < memory_size; s += PAGE_SIZE) {
                f = _PAGE_PRESENT | _PAGE_ACCESSED |
                                _PAGE_SHARED | _PAGE_HWEXEC;
diff --git a/arch/microblaze/oprofile/Makefile b/arch/microblaze/oprofile/Makefile
new file mode 100644 (file)
index 0000000..0d0348c
--- /dev/null
@@ -0,0 +1,13 @@
+#
+# arch/microblaze/oprofile/Makefile
+#
+
+obj-$(CONFIG_OPROFILE) += oprofile.o
+
+DRIVER_OBJS := $(addprefix ../../../drivers/oprofile/, \
+               oprof.o cpu_buffer.o buffer_sync.o \
+               event_buffer.o oprofile_files.o \
+               oprofilefs.o oprofile_stats.o \
+               timer_int.o )
+
+oprofile-y := $(DRIVER_OBJS) microblaze_oprofile.o
diff --git a/arch/microblaze/oprofile/microblaze_oprofile.c b/arch/microblaze/oprofile/microblaze_oprofile.c
new file mode 100644 (file)
index 0000000..def17e5
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Microblaze oprofile code
+ *
+ * Copyright (C) 2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2009 PetaLogix
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/oprofile.h>
+#include <linux/init.h>
+
+int __init oprofile_arch_init(struct oprofile_operations *ops)
+{
+       return -1;
+}
+
+void oprofile_arch_exit(void)
+{
+}
index 8e9b4752d3ff1def57e29b91a587f404e077928f..669c7eec293eb921689ba618a11d9e701ee626a3 100644 (file)
@@ -53,31 +53,12 @@ config OPT_LIB_FUNCTION
 
 config OPT_LIB_ASM
        bool "Optimalized lib function ASM"
-       depends on OPT_LIB_FUNCTION
+       depends on OPT_LIB_FUNCTION && (XILINX_MICROBLAZE0_USE_BARREL = 1)
        default n
        help
          Allows turn on optimalized library function (memcpy and memmove).
          Function are written in asm code.
 
-# This is still a bit broken - disabling for now JW 20070504
-config ALLOW_EDIT_AUTO
-       bool "Permit Display/edit of Kconfig.auto platform settings"
-       default n
-       help
-         Allows the editing of auto-generated platform settings from
-         the Kconfig.auto file. Obviously this does not change the
-         underlying hardware, so be very careful if you go editing
-         these settings.
-
-         Also, if you enable this, and edit various Kconfig.auto
-         settings, YOUR CHANGES WILL BE LOST if you then disable it
-         again. You have been warned!
-
-         If unsure, say no.
-
-comment "Automatic platform settings from Kconfig.auto"
-       depends on ALLOW_EDIT_AUTO
-
 if PLATFORM_GENERIC=y
        source "arch/microblaze/platform/generic/Kconfig.auto"
 endif
index fbca22d9c8b9bac47767f1b2f0e5fd1c48d1f8f1..5d86fc19029d412ed068ecff73c4010dde9841d0 100644 (file)
@@ -21,7 +21,6 @@
 
 # Definitions for MICROBLAZE0
 comment "Definitions for MICROBLAZE0"
-       depends on ALLOW_EDIT_AUTO
 
 config KERNEL_BASE_ADDR
        hex "Physical address where Linux Kernel is"
@@ -30,33 +29,33 @@ config KERNEL_BASE_ADDR
          BASE Address for kernel
 
 config XILINX_MICROBLAZE0_FAMILY
-       string "Targetted FPGA family" if ALLOW_EDIT_AUTO
+       string "Targetted FPGA family"
        default "virtex5"
 
 config XILINX_MICROBLAZE0_USE_MSR_INSTR
-       int "USE_MSR_INSTR range (0:1)" if ALLOW_EDIT_AUTO
-       default 1
+       int "USE_MSR_INSTR range (0:1)"
+       default 0
 
 config XILINX_MICROBLAZE0_USE_PCMP_INSTR
-       int "USE_PCMP_INSTR range (0:1)" if ALLOW_EDIT_AUTO
-       default 1
+       int "USE_PCMP_INSTR range (0:1)"
+       default 0
 
 config XILINX_MICROBLAZE0_USE_BARREL
-       int "USE_BARREL range (0:1)" if ALLOW_EDIT_AUTO
-       default 1
+       int "USE_BARREL range (0:1)"
+       default 0
 
 config XILINX_MICROBLAZE0_USE_DIV
-       int "USE_DIV range (0:1)" if ALLOW_EDIT_AUTO
-       default 1
+       int "USE_DIV range (0:1)"
+       default 0
 
 config XILINX_MICROBLAZE0_USE_HW_MUL
-       int "USE_HW_MUL values (0=NONE, 1=MUL32, 2=MUL64)" if ALLOW_EDIT_AUTO
-       default 2
+       int "USE_HW_MUL values (0=NONE, 1=MUL32, 2=MUL64)"
+       default 0
 
 config XILINX_MICROBLAZE0_USE_FPU
-       int "USE_FPU values (0=NONE, 1=BASIC, 2=EXTENDED)" if ALLOW_EDIT_AUTO
-       default 2
+       int "USE_FPU values (0=NONE, 1=BASIC, 2=EXTENDED)"
+       default 0
 
 config XILINX_MICROBLAZE0_HW_VER
-       string "Core version number" if ALLOW_EDIT_AUTO
+       string "Core version number"
        default 7.10.d
index 29993f62b30a2c47abfb7c24a3ab5677c9142dc5..2d5c41767cd06ca146e0192df79e9fd9f06ef441 100644 (file)
        #address-cells = <1>;
        #size-cells = <1>;
        compatible = "xlnx,microblaze";
+       hard-reset-gpios = <&LEDs_8Bit 2 1>;
        model = "testing";
        DDR2_SDRAM: memory@90000000 {
                device_type = "memory";
                reg = < 0x90000000 0x10000000 >;
        } ;
+       aliases {
+               ethernet0 = &Hard_Ethernet_MAC;
+               serial0 = &RS232_Uart_1;
+       } ;
        chosen {
                bootargs = "console=ttyUL0,115200 highres=on";
                linux,stdout-path = "/plb@0/serial@84000000";
        mb_plb: plb@0 {
                #address-cells = <1>;
                #size-cells = <1>;
-               compatible = "xlnx,plb-v46-1.03.a", "simple-bus";
+               compatible = "xlnx,plb-v46-1.03.a", "xlnx,plb-v46-1.00.a", "simple-bus";
                ranges ;
                FLASH: flash@a0000000 {
                        bank-width = <2>;
                        #size-cells = <1>;
                        compatible = "xlnx,compound";
                        ethernet@81c00000 {
-                               compatible = "xlnx,xps-ll-temac-1.01.b";
+                               compatible = "xlnx,xps-ll-temac-1.01.b", "xlnx,xps-ll-temac-1.00.a";
                                device_type = "network";
                                interrupt-parent = <&xps_intc_0>;
                                interrupts = < 5 2 >;
                                llink-connected = <&PIM3>;
-                               local-mac-address = [ 02 00 00 00 00 00 ];
+                               local-mac-address = [ 00 0a 35 00 00 00 ];
                                reg = < 0x81c00000 0x40 >;
                                xlnx,bus2core-clk-ratio = <0x1>;
                                xlnx,phy-type = <0x1>;
                        xlnx,is-dual = <0x0>;
                        xlnx,tri-default = <0xffffffff>;
                        xlnx,tri-default-2 = <0xffffffff>;
+                       #gpio-cells = <2>;
+                       gpio-controller;
+               } ;
+
+               gpio-leds {
+                       compatible = "gpio-leds";
+
+                       heartbeat {
+                               label = "Heartbeat";
+                               gpios = <&LEDs_8Bit 4 1>;
+                               linux,default-trigger = "heartbeat";
+                       };
+
+                       yellow {
+                               label = "Yellow";
+                               gpios = <&LEDs_8Bit 5 1>;
+                       };
+
+                       red {
+                               label = "Red";
+                               gpios = <&LEDs_8Bit 6 1>;
+                       };
+
+                       green {
+                               label = "Green";
+                               gpios = <&LEDs_8Bit 7 1>;
+                       };
                } ;
                RS232_Uart_1: serial@84000000 {
                        clock-frequency = <125000000>;
index 56e0234fa34b444a235bd4b812861f3c9c3e96ad..5b89b58c5aedbc9d9f12aa5d6b2e541134101f6f 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/of_platform.h>
 #include <asm/prom.h>
+#include <asm/setup.h>
 
 static struct of_device_id xilinx_of_bus_ids[] __initdata = {
        { .compatible = "simple-bus", },
@@ -26,6 +27,7 @@ static struct of_device_id xilinx_of_bus_ids[] __initdata = {
 static int __init microblaze_device_probe(void)
 {
        of_platform_bus_probe(NULL, xilinx_of_bus_ids, NULL);
+       of_platform_reset_gpio_probe();
        return 0;
 }
 device_initcall(microblaze_device_probe);
index dacafab00eb25c4645ffd787b0fc77730cf25859..67e6389d625a43a7cf62d4d1f5358233b5fef3d7 100644 (file)
@@ -31,13 +31,13 @@ const int kretprobe_blacklist_size = ARRAY_SIZE(kretprobe_blacklist);
 #define KPROBE_HIT_ACTIVE      0x00000001
 #define KPROBE_HIT_SS          0x00000002
 
-static struct kprobe *current_kprobe;
-static unsigned long current_kprobe_orig_pc;
-static unsigned long current_kprobe_next_pc;
-static int current_kprobe_ss_flags;
+static struct kprobe *cur_kprobe;
+static unsigned long cur_kprobe_orig_pc;
+static unsigned long cur_kprobe_next_pc;
+static int cur_kprobe_ss_flags;
 static unsigned long kprobe_status;
-static kprobe_opcode_t current_kprobe_ss_buf[MAX_INSN_SIZE + 2];
-static unsigned long current_kprobe_bp_addr;
+static kprobe_opcode_t cur_kprobe_ss_buf[MAX_INSN_SIZE + 2];
+static unsigned long cur_kprobe_bp_addr;
 
 DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
 
@@ -399,26 +399,25 @@ void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
 {
        unsigned long nextpc;
 
-       current_kprobe_orig_pc = regs->pc;
-       memcpy(current_kprobe_ss_buf, &p->ainsn.insn[0], MAX_INSN_SIZE);
-       regs->pc = (unsigned long) current_kprobe_ss_buf;
+       cur_kprobe_orig_pc = regs->pc;
+       memcpy(cur_kprobe_ss_buf, &p->ainsn.insn[0], MAX_INSN_SIZE);
+       regs->pc = (unsigned long) cur_kprobe_ss_buf;
 
-       nextpc = find_nextpc(regs, &current_kprobe_ss_flags);
-       if (current_kprobe_ss_flags & SINGLESTEP_PCREL)
-               current_kprobe_next_pc =
-                       current_kprobe_orig_pc + (nextpc - regs->pc);
+       nextpc = find_nextpc(regs, &cur_kprobe_ss_flags);
+       if (cur_kprobe_ss_flags & SINGLESTEP_PCREL)
+               cur_kprobe_next_pc = cur_kprobe_orig_pc + (nextpc - regs->pc);
        else
-               current_kprobe_next_pc = nextpc;
+               cur_kprobe_next_pc = nextpc;
 
        /* branching instructions need special handling */
-       if (current_kprobe_ss_flags & SINGLESTEP_BRANCH)
+       if (cur_kprobe_ss_flags & SINGLESTEP_BRANCH)
                nextpc = singlestep_branch_setup(regs);
 
-       current_kprobe_bp_addr = nextpc;
+       cur_kprobe_bp_addr = nextpc;
 
        *(u8 *) nextpc = BREAKPOINT_INSTRUCTION;
-       mn10300_dcache_flush_range2((unsigned) current_kprobe_ss_buf,
-                                   sizeof(current_kprobe_ss_buf));
+       mn10300_dcache_flush_range2((unsigned) cur_kprobe_ss_buf,
+                                   sizeof(cur_kprobe_ss_buf));
        mn10300_icache_inv();
 }
 
@@ -440,7 +439,7 @@ static inline int __kprobes kprobe_handler(struct pt_regs *regs)
                        disarm_kprobe(p, regs);
                        ret = 1;
                } else {
-                       p = current_kprobe;
+                       p = cur_kprobe;
                        if (p->break_handler && p->break_handler(p, regs))
                                goto ss_probe;
                }
@@ -464,7 +463,7 @@ static inline int __kprobes kprobe_handler(struct pt_regs *regs)
        }
 
        kprobe_status = KPROBE_HIT_ACTIVE;
-       current_kprobe = p;
+       cur_kprobe = p;
        if (p->pre_handler(p, regs)) {
                /* handler has already set things up, so skip ss setup */
                return 1;
@@ -491,8 +490,8 @@ no_kprobe:
 static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
 {
        /* we may need to fixup regs/stack after singlestepping a call insn */
-       if (current_kprobe_ss_flags & SINGLESTEP_BRANCH) {
-               regs->pc = current_kprobe_orig_pc;
+       if (cur_kprobe_ss_flags & SINGLESTEP_BRANCH) {
+               regs->pc = cur_kprobe_orig_pc;
                switch (p->ainsn.insn[0]) {
                case 0xcd:      /* CALL (d16,PC) */
                        *(unsigned *) regs->sp = regs->mdr = regs->pc + 5;
@@ -523,8 +522,8 @@ static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
                }
        }
 
-       regs->pc = current_kprobe_next_pc;
-       current_kprobe_bp_addr = 0;
+       regs->pc = cur_kprobe_next_pc;
+       cur_kprobe_bp_addr = 0;
 }
 
 static inline int __kprobes post_kprobe_handler(struct pt_regs *regs)
@@ -532,10 +531,10 @@ static inline int __kprobes post_kprobe_handler(struct pt_regs *regs)
        if (!kprobe_running())
                return 0;
 
-       if (current_kprobe->post_handler)
-               current_kprobe->post_handler(current_kprobe, regs, 0);
+       if (cur_kprobe->post_handler)
+               cur_kprobe->post_handler(cur_kprobe, regs, 0);
 
-       resume_execution(current_kprobe, regs);
+       resume_execution(cur_kprobe, regs);
        reset_current_kprobe();
        preempt_enable_no_resched();
        return 1;
@@ -545,12 +544,12 @@ static inline int __kprobes post_kprobe_handler(struct pt_regs *regs)
 static inline
 int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
 {
-       if (current_kprobe->fault_handler &&
-           current_kprobe->fault_handler(current_kprobe, regs, trapnr))
+       if (cur_kprobe->fault_handler &&
+           cur_kprobe->fault_handler(cur_kprobe, regs, trapnr))
                return 1;
 
        if (kprobe_status & KPROBE_HIT_SS) {
-               resume_execution(current_kprobe, regs);
+               resume_execution(cur_kprobe, regs);
                reset_current_kprobe();
                preempt_enable_no_resched();
        }
@@ -567,7 +566,7 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
 
        switch (val) {
        case DIE_BREAKPOINT:
-               if (current_kprobe_bp_addr != args->regs->pc) {
+               if (cur_kprobe_bp_addr != args->regs->pc) {
                        if (kprobe_handler(args->regs))
                                return NOTIFY_STOP;
                } else {
index d9ea8d39c3428fa88ef2c88fbab5e40d12e83fe5..1d3b270d30835c1f8d94b054b35584ad1d5c9c89 100644 (file)
@@ -37,7 +37,7 @@ extern void cpu_die(void);
 extern void smp_send_debugger_break(int cpu);
 extern void smp_message_recv(int);
 
-DECLARE_PER_CPU(unsigned int, pvr);
+DECLARE_PER_CPU(unsigned int, cpu_pvr);
 
 #ifdef CONFIG_HOTPLUG_CPU
 extern void fixup_irqs(cpumask_t map);
index 936f04dbfc6f00bd1803a643753520b34e1ae8b1..a3c11cac3d7154d1381d77a83ec513e5c6601c11 100644 (file)
@@ -487,11 +487,11 @@ static void perf_callchain_user_32(struct pt_regs *regs,
  * Since we can't get PMU interrupts inside a PMU interrupt handler,
  * we don't need separate irq and nmi entries here.
  */
-static DEFINE_PER_CPU(struct perf_callchain_entry, callchain);
+static DEFINE_PER_CPU(struct perf_callchain_entry, cpu_perf_callchain);
 
 struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
 {
-       struct perf_callchain_entry *entry = &__get_cpu_var(callchain);
+       struct perf_callchain_entry *entry = &__get_cpu_var(cpu_perf_callchain);
 
        entry->nr = 0;
 
index 845c72ab7357884c580a1c6f3f3217ed4987ee75..03dd6a248198c3247af741db5f154452b2c84f2c 100644 (file)
@@ -157,7 +157,7 @@ extern u32 cpu_temp_both(unsigned long cpu);
 #endif /* CONFIG_TAU */
 
 #ifdef CONFIG_SMP
-DEFINE_PER_CPU(unsigned int, pvr);
+DEFINE_PER_CPU(unsigned int, cpu_pvr);
 #endif
 
 static int show_cpuinfo(struct seq_file *m, void *v)
@@ -209,7 +209,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
        }
 
 #ifdef CONFIG_SMP
-       pvr = per_cpu(pvr, cpu_id);
+       pvr = per_cpu(cpu_pvr, cpu_id);
 #else
        pvr = mfspr(SPRN_PVR);
 #endif
index 97196eefef3edccba66bfd7398b9d75962e1d5c4..a521fb8a40ee2fcb206397cf490aab9550cf9c96 100644 (file)
@@ -235,7 +235,7 @@ struct thread_info *current_set[NR_CPUS];
 
 static void __devinit smp_store_cpu_info(int id)
 {
-       per_cpu(pvr, id) = mfspr(SPRN_PVR);
+       per_cpu(cpu_pvr, id) = mfspr(SPRN_PVR);
 }
 
 static void __init smp_create_idle(unsigned int cpu)
index f9dbf76a763f74fea41d2af522a23123f6880250..7267effc8078b53265e43898a7551f6adf2523d8 100644 (file)
@@ -54,7 +54,7 @@ struct iic {
        struct device_node *node;
 };
 
-static DEFINE_PER_CPU(struct iic, iic);
+static DEFINE_PER_CPU(struct iic, cpu_iic);
 #define IIC_NODE_COUNT 2
 static struct irq_host *iic_host;
 
@@ -82,7 +82,7 @@ static void iic_unmask(unsigned int irq)
 
 static void iic_eoi(unsigned int irq)
 {
-       struct iic *iic = &__get_cpu_var(iic);
+       struct iic *iic = &__get_cpu_var(cpu_iic);
        out_be64(&iic->regs->prio, iic->eoi_stack[--iic->eoi_ptr]);
        BUG_ON(iic->eoi_ptr < 0);
 }
@@ -146,7 +146,7 @@ static unsigned int iic_get_irq(void)
        struct iic *iic;
        unsigned int virq;
 
-       iic = &__get_cpu_var(iic);
+       iic = &__get_cpu_var(cpu_iic);
        *(unsigned long *) &pending =
                in_be64((u64 __iomem *) &iic->regs->pending_destr);
        if (!(pending.flags & CBE_IIC_IRQ_VALID))
@@ -161,12 +161,12 @@ static unsigned int iic_get_irq(void)
 
 void iic_setup_cpu(void)
 {
-       out_be64(&__get_cpu_var(iic).regs->prio, 0xff);
+       out_be64(&__get_cpu_var(cpu_iic).regs->prio, 0xff);
 }
 
 u8 iic_get_target_id(int cpu)
 {
-       return per_cpu(iic, cpu).target_id;
+       return per_cpu(cpu_iic, cpu).target_id;
 }
 
 EXPORT_SYMBOL_GPL(iic_get_target_id);
@@ -181,7 +181,7 @@ static inline int iic_ipi_to_irq(int ipi)
 
 void iic_cause_IPI(int cpu, int mesg)
 {
-       out_be64(&per_cpu(iic, cpu).regs->generate, (0xf - mesg) << 4);
+       out_be64(&per_cpu(cpu_iic, cpu).regs->generate, (0xf - mesg) << 4);
 }
 
 struct irq_host *iic_get_irq_host(int node)
@@ -348,7 +348,7 @@ static void __init init_one_iic(unsigned int hw_cpu, unsigned long addr,
        /* XXX FIXME: should locate the linux CPU number from the HW cpu
         * number properly. We are lucky for now
         */
-       struct iic *iic = &per_cpu(iic, hw_cpu);
+       struct iic *iic = &per_cpu(cpu_iic, hw_cpu);
 
        iic->regs = ioremap(addr, sizeof(struct cbe_iic_thread_regs));
        BUG_ON(iic->regs == NULL);
index 937a544a236d5e1a58be64b821d23bb20e965c63..c5f3116b6ca524e8b08aff7193ca796ccd089e00 100644 (file)
@@ -54,7 +54,7 @@ struct dtl {
        int                     buf_entries;
        u64                     last_idx;
 };
-static DEFINE_PER_CPU(struct dtl, dtl);
+static DEFINE_PER_CPU(struct dtl, cpu_dtl);
 
 /*
  * Dispatch trace log event mask:
@@ -261,7 +261,7 @@ static int dtl_init(void)
 
        /* set up the per-cpu log structures */
        for_each_possible_cpu(i) {
-               struct dtl *dtl = &per_cpu(dtl, i);
+               struct dtl *dtl = &per_cpu(cpu_dtl, i);
                dtl->cpu = i;
 
                rc = dtl_setup_file(dtl);
index b129611590a449f61de21fdcaa803eefbf7eb6fe..f30f4a1ead23d373afb51161f3303dfeae9fbe17 100644 (file)
@@ -47,7 +47,7 @@ static DEFINE_PER_CPU(short, wd_enabled);
 static int endflag __initdata;
 
 static DEFINE_PER_CPU(unsigned int, last_irq_sum);
-static DEFINE_PER_CPU(local_t, alert_counter);
+static DEFINE_PER_CPU(long, alert_counter);
 static DEFINE_PER_CPU(int, nmi_touch);
 
 void touch_nmi_watchdog(void)
@@ -112,13 +112,13 @@ notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs)
                touched = 1;
        }
        if (!touched && __get_cpu_var(last_irq_sum) == sum) {
-               local_inc(&__get_cpu_var(alert_counter));
-               if (local_read(&__get_cpu_var(alert_counter)) == 30 * nmi_hz)
+               __this_cpu_inc(per_cpu_var(alert_counter));
+               if (__this_cpu_read(per_cpu_var(alert_counter)) == 30 * nmi_hz)
                        die_nmi("BUG: NMI Watchdog detected LOCKUP",
                                regs, panic_on_timeout);
        } else {
                __get_cpu_var(last_irq_sum) = sum;
-               local_set(&__get_cpu_var(alert_counter), 0);
+               __this_cpu_write(per_cpu_var(alert_counter), 0);
        }
        if (__get_cpu_var(wd_enabled)) {
                write_pic(picl_value(nmi_hz));
index 6a635bd39867bd8c996229790bf3197b8b3b9d5f..4611f085cd4304ce18a2ebdf3cb1c09778f03fa8 100644 (file)
  */
 #define LOCAL_PENDING_VECTOR           0xec
 
-#define UV_BAU_MESSAGE                 0xec
+#define UV_BAU_MESSAGE                 0xea
 
 /*
  * Self IPI vector for machine checks
index 5bef931f8b1410f535e71faa1cdb64092390d593..2d228fc9b4b7642958e963e464b2b924435bebc4 100644 (file)
@@ -244,6 +244,9 @@ do {                                                            \
 
 #define write_rdtscp_aux(val) wrmsr(0xc0000103, (val), 0)
 
+struct msr *msrs_alloc(void);
+void msrs_free(struct msr *msrs);
+
 #ifdef CONFIG_SMP
 int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h);
 int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h);
index b65a36defeb737434f8823c21c625f14db8e6347..0c44196b78ac82ec706220182acfc485b6d8fb87 100644 (file)
@@ -74,31 +74,31 @@ extern void __bad_percpu_size(void);
 
 #define percpu_to_op(op, var, val)                     \
 do {                                                   \
-       typedef typeof(var) T__;                        \
+       typedef typeof(var) pto_T__;                    \
        if (0) {                                        \
-               T__ tmp__;                              \
-               tmp__ = (val);                          \
+               pto_T__ pto_tmp__;                      \
+               pto_tmp__ = (val);                      \
        }                                               \
        switch (sizeof(var)) {                          \
        case 1:                                         \
                asm(op "b %1,"__percpu_arg(0)           \
                    : "+m" (var)                        \
-                   : "qi" ((T__)(val)));               \
+                   : "qi" ((pto_T__)(val)));           \
                break;                                  \
        case 2:                                         \
                asm(op "w %1,"__percpu_arg(0)           \
                    : "+m" (var)                        \
-                   : "ri" ((T__)(val)));               \
+                   : "ri" ((pto_T__)(val)));           \
                break;                                  \
        case 4:                                         \
                asm(op "l %1,"__percpu_arg(0)           \
                    : "+m" (var)                        \
-                   : "ri" ((T__)(val)));               \
+                   : "ri" ((pto_T__)(val)));           \
                break;                                  \
        case 8:                                         \
                asm(op "q %1,"__percpu_arg(0)           \
                    : "+m" (var)                        \
-                   : "re" ((T__)(val)));               \
+                   : "re" ((pto_T__)(val)));           \
                break;                                  \
        default: __bad_percpu_size();                   \
        }                                               \
@@ -106,31 +106,31 @@ do {                                                      \
 
 #define percpu_from_op(op, var, constraint)            \
 ({                                                     \
-       typeof(var) ret__;                              \
+       typeof(var) pfo_ret__;                          \
        switch (sizeof(var)) {                          \
        case 1:                                         \
                asm(op "b "__percpu_arg(1)",%0"         \
-                   : "=q" (ret__)                      \
+                   : "=q" (pfo_ret__)                  \
                    : constraint);                      \
                break;                                  \
        case 2:                                         \
                asm(op "w "__percpu_arg(1)",%0"         \
-                   : "=r" (ret__)                      \
+                   : "=r" (pfo_ret__)                  \
                    : constraint);                      \
                break;                                  \
        case 4:                                         \
                asm(op "l "__percpu_arg(1)",%0"         \
-                   : "=r" (ret__)                      \
+                   : "=r" (pfo_ret__)                  \
                    : constraint);                      \
                break;                                  \
        case 8:                                         \
                asm(op "q "__percpu_arg(1)",%0"         \
-                   : "=r" (ret__)                      \
+                   : "=r" (pfo_ret__)                  \
                    : constraint);                      \
                break;                                  \
        default: __bad_percpu_size();                   \
        }                                               \
-       ret__;                                          \
+       pfo_ret__;                                      \
 })
 
 /*
@@ -153,6 +153,84 @@ do {                                                       \
 #define percpu_or(var, val)    percpu_to_op("or", per_cpu__##var, val)
 #define percpu_xor(var, val)   percpu_to_op("xor", per_cpu__##var, val)
 
+#define __this_cpu_read_1(pcp)         percpu_from_op("mov", (pcp), "m"(pcp))
+#define __this_cpu_read_2(pcp)         percpu_from_op("mov", (pcp), "m"(pcp))
+#define __this_cpu_read_4(pcp)         percpu_from_op("mov", (pcp), "m"(pcp))
+
+#define __this_cpu_write_1(pcp, val)   percpu_to_op("mov", (pcp), val)
+#define __this_cpu_write_2(pcp, val)   percpu_to_op("mov", (pcp), val)
+#define __this_cpu_write_4(pcp, val)   percpu_to_op("mov", (pcp), val)
+#define __this_cpu_add_1(pcp, val)     percpu_to_op("add", (pcp), val)
+#define __this_cpu_add_2(pcp, val)     percpu_to_op("add", (pcp), val)
+#define __this_cpu_add_4(pcp, val)     percpu_to_op("add", (pcp), val)
+#define __this_cpu_and_1(pcp, val)     percpu_to_op("and", (pcp), val)
+#define __this_cpu_and_2(pcp, val)     percpu_to_op("and", (pcp), val)
+#define __this_cpu_and_4(pcp, val)     percpu_to_op("and", (pcp), val)
+#define __this_cpu_or_1(pcp, val)      percpu_to_op("or", (pcp), val)
+#define __this_cpu_or_2(pcp, val)      percpu_to_op("or", (pcp), val)
+#define __this_cpu_or_4(pcp, val)      percpu_to_op("or", (pcp), val)
+#define __this_cpu_xor_1(pcp, val)     percpu_to_op("xor", (pcp), val)
+#define __this_cpu_xor_2(pcp, val)     percpu_to_op("xor", (pcp), val)
+#define __this_cpu_xor_4(pcp, val)     percpu_to_op("xor", (pcp), val)
+
+#define this_cpu_read_1(pcp)           percpu_from_op("mov", (pcp), "m"(pcp))
+#define this_cpu_read_2(pcp)           percpu_from_op("mov", (pcp), "m"(pcp))
+#define this_cpu_read_4(pcp)           percpu_from_op("mov", (pcp), "m"(pcp))
+#define this_cpu_write_1(pcp, val)     percpu_to_op("mov", (pcp), val)
+#define this_cpu_write_2(pcp, val)     percpu_to_op("mov", (pcp), val)
+#define this_cpu_write_4(pcp, val)     percpu_to_op("mov", (pcp), val)
+#define this_cpu_add_1(pcp, val)       percpu_to_op("add", (pcp), val)
+#define this_cpu_add_2(pcp, val)       percpu_to_op("add", (pcp), val)
+#define this_cpu_add_4(pcp, val)       percpu_to_op("add", (pcp), val)
+#define this_cpu_and_1(pcp, val)       percpu_to_op("and", (pcp), val)
+#define this_cpu_and_2(pcp, val)       percpu_to_op("and", (pcp), val)
+#define this_cpu_and_4(pcp, val)       percpu_to_op("and", (pcp), val)
+#define this_cpu_or_1(pcp, val)                percpu_to_op("or", (pcp), val)
+#define this_cpu_or_2(pcp, val)                percpu_to_op("or", (pcp), val)
+#define this_cpu_or_4(pcp, val)                percpu_to_op("or", (pcp), val)
+#define this_cpu_xor_1(pcp, val)       percpu_to_op("xor", (pcp), val)
+#define this_cpu_xor_2(pcp, val)       percpu_to_op("xor", (pcp), val)
+#define this_cpu_xor_4(pcp, val)       percpu_to_op("xor", (pcp), val)
+
+#define irqsafe_cpu_add_1(pcp, val)    percpu_to_op("add", (pcp), val)
+#define irqsafe_cpu_add_2(pcp, val)    percpu_to_op("add", (pcp), val)
+#define irqsafe_cpu_add_4(pcp, val)    percpu_to_op("add", (pcp), val)
+#define irqsafe_cpu_and_1(pcp, val)    percpu_to_op("and", (pcp), val)
+#define irqsafe_cpu_and_2(pcp, val)    percpu_to_op("and", (pcp), val)
+#define irqsafe_cpu_and_4(pcp, val)    percpu_to_op("and", (pcp), val)
+#define irqsafe_cpu_or_1(pcp, val)     percpu_to_op("or", (pcp), val)
+#define irqsafe_cpu_or_2(pcp, val)     percpu_to_op("or", (pcp), val)
+#define irqsafe_cpu_or_4(pcp, val)     percpu_to_op("or", (pcp), val)
+#define irqsafe_cpu_xor_1(pcp, val)    percpu_to_op("xor", (pcp), val)
+#define irqsafe_cpu_xor_2(pcp, val)    percpu_to_op("xor", (pcp), val)
+#define irqsafe_cpu_xor_4(pcp, val)    percpu_to_op("xor", (pcp), val)
+
+/*
+ * Per cpu atomic 64 bit operations are only available under 64 bit.
+ * 32 bit must fall back to generic operations.
+ */
+#ifdef CONFIG_X86_64
+#define __this_cpu_read_8(pcp)         percpu_from_op("mov", (pcp), "m"(pcp))
+#define __this_cpu_write_8(pcp, val)   percpu_to_op("mov", (pcp), val)
+#define __this_cpu_add_8(pcp, val)     percpu_to_op("add", (pcp), val)
+#define __this_cpu_and_8(pcp, val)     percpu_to_op("and", (pcp), val)
+#define __this_cpu_or_8(pcp, val)      percpu_to_op("or", (pcp), val)
+#define __this_cpu_xor_8(pcp, val)     percpu_to_op("xor", (pcp), val)
+
+#define this_cpu_read_8(pcp)           percpu_from_op("mov", (pcp), "m"(pcp))
+#define this_cpu_write_8(pcp, val)     percpu_to_op("mov", (pcp), val)
+#define this_cpu_add_8(pcp, val)       percpu_to_op("add", (pcp), val)
+#define this_cpu_and_8(pcp, val)       percpu_to_op("and", (pcp), val)
+#define this_cpu_or_8(pcp, val)                percpu_to_op("or", (pcp), val)
+#define this_cpu_xor_8(pcp, val)       percpu_to_op("xor", (pcp), val)
+
+#define irqsafe_cpu_add_8(pcp, val)    percpu_to_op("add", (pcp), val)
+#define irqsafe_cpu_and_8(pcp, val)    percpu_to_op("and", (pcp), val)
+#define irqsafe_cpu_or_8(pcp, val)     percpu_to_op("or", (pcp), val)
+#define irqsafe_cpu_xor_8(pcp, val)    percpu_to_op("xor", (pcp), val)
+
+#endif
+
 /* This is not atomic against other CPUs -- CPU preemption needs to be off */
 #define x86_test_and_clear_bit_percpu(bit, var)                                \
 ({                                                                     \
index 90f06c25221d792dab33f662c25012b7d0c39f59..cb507bb05d7923a32d9134e61a938fdba184a2c9 100644 (file)
@@ -16,7 +16,6 @@ extern unsigned long initial_code;
 extern unsigned long initial_gs;
 
 #define TRAMPOLINE_SIZE roundup(trampoline_end - trampoline_data, PAGE_SIZE)
-#define TRAMPOLINE_BASE 0x6000
 
 extern unsigned long setup_trampoline(void);
 extern void __init reserve_trampoline_memory(void);
index e0dfb6856aa297ef9349dc36c3b5cef93b5abbf0..3704997e8b2573bda630720f4c47bd4a7ec3b8c5 100644 (file)
@@ -280,7 +280,8 @@ void __init early_gart_iommu_check(void)
         * or BIOS forget to put that in reserved.
         * try to update e820 to make that region as reserved.
         */
-       int i, fix, slot;
+       u32 agp_aper_base = 0, agp_aper_order = 0;
+       int i, fix, slot, valid_agp = 0;
        u32 ctl;
        u32 aper_size = 0, aper_order = 0, last_aper_order = 0;
        u64 aper_base = 0, last_aper_base = 0;
@@ -290,6 +291,8 @@ void __init early_gart_iommu_check(void)
                return;
 
        /* This is mostly duplicate of iommu_hole_init */
+       agp_aper_base = search_agp_bridge(&agp_aper_order, &valid_agp);
+
        fix = 0;
        for (i = 0; i < ARRAY_SIZE(bus_dev_ranges); i++) {
                int bus;
@@ -342,10 +345,10 @@ void __init early_gart_iommu_check(void)
                }
        }
 
-       if (!fix)
+       if (valid_agp)
                return;
 
-       /* different nodes have different setting, disable them all at first*/
+       /* disable them all at first */
        for (i = 0; i < ARRAY_SIZE(bus_dev_ranges); i++) {
                int bus;
                int dev_base, dev_limit;
@@ -458,8 +461,6 @@ out:
 
        if (aper_alloc) {
                /* Got the aperture from the AGP bridge */
-       } else if (!valid_agp) {
-               /* Do nothing */
        } else if ((!no_iommu && max_pfn > MAX_DMA32_PFN) ||
                   force_iommu ||
                   valid_agp ||
index efb2b9cd132c79f4c8a60f8973ae2995d3c3ccb8..aa57c079c98f6c345e91313e37f3f52e8d3f26bb 100644 (file)
@@ -1341,7 +1341,7 @@ void enable_x2apic(void)
 
        rdmsr(MSR_IA32_APICBASE, msr, msr2);
        if (!(msr & X2APIC_ENABLE)) {
-               pr_info("Enabling x2apic\n");
+               printk_once(KERN_INFO "Enabling x2apic\n");
                wrmsr(MSR_IA32_APICBASE, msr | X2APIC_ENABLE, 0);
        }
 }
index 6389432a9dbf7f07a0dd08b4e67857c6ec899d6d..0159a69396cba449a424190459a02d83a3f417d8 100644 (file)
@@ -361,7 +361,7 @@ void stop_apic_nmi_watchdog(void *unused)
  */
 
 static DEFINE_PER_CPU(unsigned, last_irq_sum);
-static DEFINE_PER_CPU(local_t, alert_counter);
+static DEFINE_PER_CPU(long, alert_counter);
 static DEFINE_PER_CPU(int, nmi_touch);
 
 void touch_nmi_watchdog(void)
@@ -438,8 +438,8 @@ nmi_watchdog_tick(struct pt_regs *regs, unsigned reason)
                 * Ayiee, looks like this CPU is stuck ...
                 * wait a few IRQs (5 seconds) before doing the oops ...
                 */
-               local_inc(&__get_cpu_var(alert_counter));
-               if (local_read(&__get_cpu_var(alert_counter)) == 5 * nmi_hz)
+               __this_cpu_inc(per_cpu_var(alert_counter));
+               if (__this_cpu_read(per_cpu_var(alert_counter)) == 5 * nmi_hz)
                        /*
                         * die_nmi will return ONLY if NOTIFY_STOP happens..
                         */
@@ -447,7 +447,7 @@ nmi_watchdog_tick(struct pt_regs *regs, unsigned reason)
                                regs, panic_on_timeout);
        } else {
                __get_cpu_var(last_irq_sum) = sum;
-               local_set(&__get_cpu_var(alert_counter), 0);
+               __this_cpu_write(per_cpu_var(alert_counter), 0);
        }
 
        /* see if the nmi watchdog went off */
index c965e5212714ee66cfe04e847544e213f44a7b2d..468489b57aae6d8d3eefabc0a27358f6e9553112 100644 (file)
@@ -74,6 +74,7 @@ void __cpuinit detect_extended_topology(struct cpuinfo_x86 *c)
        unsigned int eax, ebx, ecx, edx, sub_index;
        unsigned int ht_mask_width, core_plus_mask_width;
        unsigned int core_select_mask, core_level_siblings;
+       static bool printed;
 
        if (c->cpuid_level < 0xb)
                return;
@@ -127,12 +128,14 @@ void __cpuinit detect_extended_topology(struct cpuinfo_x86 *c)
 
        c->x86_max_cores = (core_level_siblings / smp_num_siblings);
 
-
-       printk(KERN_INFO  "CPU: Physical Processor ID: %d\n",
-              c->phys_proc_id);
-       if (c->x86_max_cores > 1)
-               printk(KERN_INFO  "CPU: Processor Core ID: %d\n",
-                      c->cpu_core_id);
+       if (!printed) {
+               printk(KERN_INFO  "CPU: Physical Processor ID: %d\n",
+                      c->phys_proc_id);
+               if (c->x86_max_cores > 1)
+                       printk(KERN_INFO  "CPU: Processor Core ID: %d\n",
+                              c->cpu_core_id);
+               printed = 1;
+       }
        return;
 #endif
 }
index 7128b3799cecdd8c2f708124e1939c0686224511..8dc3ea145c975a3eebfbb1510f30c9ffa7b48e06 100644 (file)
@@ -375,8 +375,6 @@ static void __cpuinit srat_detect_node(struct cpuinfo_x86 *c)
                        node = nearby_node(apicid);
        }
        numa_set_node(cpu, node);
-
-       printk(KERN_INFO "CPU %d/0x%x -> Node %d\n", cpu, apicid, node);
 #endif
 }
 
index c1afa990a6c84bf49229a9c50052b063b9731236..4868e4a951eeec310c10d06428d60c49e2fe79b5 100644 (file)
@@ -427,6 +427,7 @@ void __cpuinit detect_ht(struct cpuinfo_x86 *c)
 #ifdef CONFIG_X86_HT
        u32 eax, ebx, ecx, edx;
        int index_msb, core_bits;
+       static bool printed;
 
        if (!cpu_has(c, X86_FEATURE_HT))
                return;
@@ -442,7 +443,7 @@ void __cpuinit detect_ht(struct cpuinfo_x86 *c)
        smp_num_siblings = (ebx & 0xff0000) >> 16;
 
        if (smp_num_siblings == 1) {
-               printk(KERN_INFO  "CPU: Hyper-Threading is disabled\n");
+               printk_once(KERN_INFO "CPU0: Hyper-Threading is disabled\n");
                goto out;
        }
 
@@ -469,11 +470,12 @@ void __cpuinit detect_ht(struct cpuinfo_x86 *c)
                                       ((1 << core_bits) - 1);
 
 out:
-       if ((c->x86_max_cores * smp_num_siblings) > 1) {
+       if (!printed && (c->x86_max_cores * smp_num_siblings) > 1) {
                printk(KERN_INFO  "CPU: Physical Processor ID: %d\n",
                       c->phys_proc_id);
                printk(KERN_INFO  "CPU: Processor Core ID: %d\n",
                       c->cpu_core_id);
+               printed = 1;
        }
 #endif
 }
@@ -1093,7 +1095,7 @@ static void clear_all_debug_regs(void)
 
 void __cpuinit cpu_init(void)
 {
-       struct orig_ist *orig_ist;
+       struct orig_ist *oist;
        struct task_struct *me;
        struct tss_struct *t;
        unsigned long v;
@@ -1102,7 +1104,7 @@ void __cpuinit cpu_init(void)
 
        cpu = stack_smp_processor_id();
        t = &per_cpu(init_tss, cpu);
-       orig_ist = &per_cpu(orig_ist, cpu);
+       oist = &per_cpu(orig_ist, cpu);
 
 #ifdef CONFIG_NUMA
        if (cpu != 0 && percpu_read(node_number) == 0 &&
@@ -1115,7 +1117,7 @@ void __cpuinit cpu_init(void)
        if (cpumask_test_and_set_cpu(cpu, cpu_initialized_mask))
                panic("CPU#%d already initialized!\n", cpu);
 
-       printk(KERN_INFO "Initializing CPU#%d\n", cpu);
+       pr_debug("Initializing CPU#%d\n", cpu);
 
        clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);
 
@@ -1143,12 +1145,12 @@ void __cpuinit cpu_init(void)
        /*
         * set up and load the per-CPU TSS
         */
-       if (!orig_ist->ist[0]) {
+       if (!oist->ist[0]) {
                char *estacks = per_cpu(exception_stacks, cpu);
 
                for (v = 0; v < N_EXCEPTION_STACKS; v++) {
                        estacks += exception_stack_sizes[v];
-                       orig_ist->ist[v] = t->x86_tss.ist[v] =
+                       oist->ist[v] = t->x86_tss.ist[v] =
                                        (unsigned long)estacks;
                }
        }
index dca325c0399960c4bdacc7659d3f04dbfbbdd541..b368cd862997d7cbcfb0b425fb9f1d45e136e9d0 100644 (file)
@@ -30,9 +30,9 @@
 #include <asm/apic.h>
 #include <asm/desc.h>
 
-static DEFINE_PER_CPU(struct cpu_cpuX_base [CPU_REG_ALL_BIT], cpu_arr);
-static DEFINE_PER_CPU(struct cpu_private * [MAX_CPU_FILES], priv_arr);
-static DEFINE_PER_CPU(int, cpu_priv_count);
+static DEFINE_PER_CPU(struct cpu_cpuX_base [CPU_REG_ALL_BIT], cpud_arr);
+static DEFINE_PER_CPU(struct cpu_private * [MAX_CPU_FILES], cpud_priv_arr);
+static DEFINE_PER_CPU(int, cpud_priv_count);
 
 static DEFINE_MUTEX(cpu_debug_lock);
 
@@ -531,7 +531,7 @@ static int cpu_create_file(unsigned cpu, unsigned type, unsigned reg,
 
        /* Already intialized */
        if (file == CPU_INDEX_BIT)
-               if (per_cpu(cpu_arr[type].init, cpu))
+               if (per_cpu(cpud_arr[type].init, cpu))
                        return 0;
 
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
@@ -543,8 +543,8 @@ static int cpu_create_file(unsigned cpu, unsigned type, unsigned reg,
        priv->reg = reg;
        priv->file = file;
        mutex_lock(&cpu_debug_lock);
-       per_cpu(priv_arr[type], cpu) = priv;
-       per_cpu(cpu_priv_count, cpu)++;
+       per_cpu(cpud_priv_arr[type], cpu) = priv;
+       per_cpu(cpud_priv_count, cpu)++;
        mutex_unlock(&cpu_debug_lock);
 
        if (file)
@@ -552,10 +552,10 @@ static int cpu_create_file(unsigned cpu, unsigned type, unsigned reg,
                                    dentry, (void *)priv, &cpu_fops);
        else {
                debugfs_create_file(cpu_base[type].name, S_IRUGO,
-                                   per_cpu(cpu_arr[type].dentry, cpu),
+                                   per_cpu(cpud_arr[type].dentry, cpu),
                                    (void *)priv, &cpu_fops);
                mutex_lock(&cpu_debug_lock);
-               per_cpu(cpu_arr[type].init, cpu) = 1;
+               per_cpu(cpud_arr[type].init, cpu) = 1;
                mutex_unlock(&cpu_debug_lock);
        }
 
@@ -615,7 +615,7 @@ static int cpu_init_allreg(unsigned cpu, struct dentry *dentry)
                if (!is_typeflag_valid(cpu, cpu_base[type].flag))
                        continue;
                cpu_dentry = debugfs_create_dir(cpu_base[type].name, dentry);
-               per_cpu(cpu_arr[type].dentry, cpu) = cpu_dentry;
+               per_cpu(cpud_arr[type].dentry, cpu) = cpu_dentry;
 
                if (type < CPU_TSS_BIT)
                        err = cpu_init_msr(cpu, type, cpu_dentry);
@@ -647,11 +647,11 @@ static int cpu_init_cpu(void)
                err = cpu_init_allreg(cpu, cpu_dentry);
 
                pr_info("cpu%d(%d) debug files %d\n",
-                       cpu, nr_cpu_ids, per_cpu(cpu_priv_count, cpu));
-               if (per_cpu(cpu_priv_count, cpu) > MAX_CPU_FILES) {
+                       cpu, nr_cpu_ids, per_cpu(cpud_priv_count, cpu));
+               if (per_cpu(cpud_priv_count, cpu) > MAX_CPU_FILES) {
                        pr_err("Register files count %d exceeds limit %d\n",
-                               per_cpu(cpu_priv_count, cpu), MAX_CPU_FILES);
-                       per_cpu(cpu_priv_count, cpu) = MAX_CPU_FILES;
+                               per_cpu(cpud_priv_count, cpu), MAX_CPU_FILES);
+                       per_cpu(cpud_priv_count, cpu) = MAX_CPU_FILES;
                        err = -ENFILE;
                }
                if (err)
@@ -676,8 +676,8 @@ static void __exit cpu_debug_exit(void)
                debugfs_remove_recursive(cpu_debugfs_dir);
 
        for (cpu = 0; cpu <  nr_cpu_ids; cpu++)
-               for (i = 0; i < per_cpu(cpu_priv_count, cpu); i++)
-                       kfree(per_cpu(priv_arr[i], cpu));
+               for (i = 0; i < per_cpu(cpud_priv_count, cpu); i++)
+                       kfree(per_cpu(cpud_priv_arr[i], cpu));
 }
 
 module_init(cpu_debug_init);
index d2e7c77c1ea4901a8e3e6b2a70c99b5c991132f3..f28decf8dde3990626f493e5d962bfea9d48e59f 100644 (file)
@@ -68,9 +68,9 @@ struct acpi_cpufreq_data {
        unsigned int cpu_feature;
 };
 
-static DEFINE_PER_CPU(struct acpi_cpufreq_data *, drv_data);
+static DEFINE_PER_CPU(struct acpi_cpufreq_data *, acfreq_data);
 
-static DEFINE_PER_CPU(struct aperfmperf, old_perf);
+static DEFINE_PER_CPU(struct aperfmperf, acfreq_old_perf);
 
 /* acpi_perf_data is a pointer to percpu data. */
 static struct acpi_processor_performance *acpi_perf_data;
@@ -214,14 +214,14 @@ static u32 get_cur_val(const struct cpumask *mask)
        if (unlikely(cpumask_empty(mask)))
                return 0;
 
-       switch (per_cpu(drv_data, cpumask_first(mask))->cpu_feature) {
+       switch (per_cpu(acfreq_data, cpumask_first(mask))->cpu_feature) {
        case SYSTEM_INTEL_MSR_CAPABLE:
                cmd.type = SYSTEM_INTEL_MSR_CAPABLE;
                cmd.addr.msr.reg = MSR_IA32_PERF_STATUS;
                break;
        case SYSTEM_IO_CAPABLE:
                cmd.type = SYSTEM_IO_CAPABLE;
-               perf = per_cpu(drv_data, cpumask_first(mask))->acpi_data;
+               perf = per_cpu(acfreq_data, cpumask_first(mask))->acpi_data;
                cmd.addr.io.port = perf->control_register.address;
                cmd.addr.io.bit_width = perf->control_register.bit_width;
                break;
@@ -268,8 +268,8 @@ static unsigned int get_measured_perf(struct cpufreq_policy *policy,
        if (smp_call_function_single(cpu, read_measured_perf_ctrs, &perf, 1))
                return 0;
 
-       ratio = calc_aperfmperf_ratio(&per_cpu(old_perf, cpu), &perf);
-       per_cpu(old_perf, cpu) = perf;
+       ratio = calc_aperfmperf_ratio(&per_cpu(acfreq_old_perf, cpu), &perf);
+       per_cpu(acfreq_old_perf, cpu) = perf;
 
        retval = (policy->cpuinfo.max_freq * ratio) >> APERFMPERF_SHIFT;
 
@@ -278,7 +278,7 @@ static unsigned int get_measured_perf(struct cpufreq_policy *policy,
 
 static unsigned int get_cur_freq_on_cpu(unsigned int cpu)
 {
-       struct acpi_cpufreq_data *data = per_cpu(drv_data, cpu);
+       struct acpi_cpufreq_data *data = per_cpu(acfreq_data, cpu);
        unsigned int freq;
        unsigned int cached_freq;
 
@@ -322,7 +322,7 @@ static unsigned int check_freqs(const struct cpumask *mask, unsigned int freq,
 static int acpi_cpufreq_target(struct cpufreq_policy *policy,
                               unsigned int target_freq, unsigned int relation)
 {
-       struct acpi_cpufreq_data *data = per_cpu(drv_data, policy->cpu);
+       struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
        struct acpi_processor_performance *perf;
        struct cpufreq_freqs freqs;
        struct drv_cmd cmd;
@@ -416,7 +416,7 @@ out:
 
 static int acpi_cpufreq_verify(struct cpufreq_policy *policy)
 {
-       struct acpi_cpufreq_data *data = per_cpu(drv_data, policy->cpu);
+       struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
 
        dprintk("acpi_cpufreq_verify\n");
 
@@ -574,7 +574,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
                return -ENOMEM;
 
        data->acpi_data = per_cpu_ptr(acpi_perf_data, cpu);
-       per_cpu(drv_data, cpu) = data;
+       per_cpu(acfreq_data, cpu) = data;
 
        if (cpu_has(c, X86_FEATURE_CONSTANT_TSC))
                acpi_cpufreq_driver.flags |= CPUFREQ_CONST_LOOPS;
@@ -725,20 +725,20 @@ err_unreg:
        acpi_processor_unregister_performance(perf, cpu);
 err_free:
        kfree(data);
-       per_cpu(drv_data, cpu) = NULL;
+       per_cpu(acfreq_data, cpu) = NULL;
 
        return result;
 }
 
 static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy)
 {
-       struct acpi_cpufreq_data *data = per_cpu(drv_data, policy->cpu);
+       struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
 
        dprintk("acpi_cpufreq_cpu_exit\n");
 
        if (data) {
                cpufreq_frequency_table_put_attr(policy->cpu);
-               per_cpu(drv_data, policy->cpu) = NULL;
+               per_cpu(acfreq_data, policy->cpu) = NULL;
                acpi_processor_unregister_performance(data->acpi_data,
                                                      policy->cpu);
                kfree(data);
@@ -749,7 +749,7 @@ static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy)
 
 static int acpi_cpufreq_resume(struct cpufreq_policy *policy)
 {
-       struct acpi_cpufreq_data *data = per_cpu(drv_data, policy->cpu);
+       struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
 
        dprintk("acpi_cpufreq_resume\n");
 
index c900b73f92246d77cac96de3f9bd77685cf5d167..9c31e8b09d2c2676c29f87a68442e56878d6bece 100644 (file)
@@ -270,8 +270,6 @@ static void __cpuinit srat_detect_node(struct cpuinfo_x86 *c)
                node = cpu_to_node(cpu);
        }
        numa_set_node(cpu, node);
-
-       printk(KERN_INFO "CPU %d/0x%x -> Node %d\n", cpu, apicid, node);
 #endif
 }
 
index 6c40f6b5b340b031192232bdc946d62c7076d0cc..fc6c8ef92dcc5f0bd9c846b2597f0463e50209af 100644 (file)
@@ -499,26 +499,27 @@ unsigned int __cpuinit init_intel_cacheinfo(struct cpuinfo_x86 *c)
 #ifdef CONFIG_SYSFS
 
 /* pointer to _cpuid4_info array (for each cache leaf) */
-static DEFINE_PER_CPU(struct _cpuid4_info *, cpuid4_info);
-#define CPUID4_INFO_IDX(x, y)  (&((per_cpu(cpuid4_info, x))[y]))
+static DEFINE_PER_CPU(struct _cpuid4_info *, ici_cpuid4_info);
+#define CPUID4_INFO_IDX(x, y)  (&((per_cpu(ici_cpuid4_info, x))[y]))
 
 #ifdef CONFIG_SMP
 static void __cpuinit cache_shared_cpu_map_setup(unsigned int cpu, int index)
 {
        struct _cpuid4_info     *this_leaf, *sibling_leaf;
        unsigned long num_threads_sharing;
-       int index_msb, i;
+       int index_msb, i, sibling;
        struct cpuinfo_x86 *c = &cpu_data(cpu);
 
        if ((index == 3) && (c->x86_vendor == X86_VENDOR_AMD)) {
-               struct cpuinfo_x86 *d;
-               for_each_online_cpu(i) {
-                       if (!per_cpu(cpuid4_info, i))
+               for_each_cpu(i, c->llc_shared_map) {
+                       if (!per_cpu(ici_cpuid4_info, i))
                                continue;
-                       d = &cpu_data(i);
                        this_leaf = CPUID4_INFO_IDX(i, index);
-                       cpumask_copy(to_cpumask(this_leaf->shared_cpu_map),
-                                    d->llc_shared_map);
+                       for_each_cpu(sibling, c->llc_shared_map) {
+                               if (!cpu_online(sibling))
+                                       continue;
+                               set_bit(sibling, this_leaf->shared_cpu_map);
+                       }
                }
                return;
        }
@@ -535,7 +536,7 @@ static void __cpuinit cache_shared_cpu_map_setup(unsigned int cpu, int index)
                            c->apicid >> index_msb) {
                                cpumask_set_cpu(i,
                                        to_cpumask(this_leaf->shared_cpu_map));
-                               if (i != cpu && per_cpu(cpuid4_info, i))  {
+                               if (i != cpu && per_cpu(ici_cpuid4_info, i))  {
                                        sibling_leaf =
                                                CPUID4_INFO_IDX(i, index);
                                        cpumask_set_cpu(cpu, to_cpumask(
@@ -574,8 +575,8 @@ static void __cpuinit free_cache_attributes(unsigned int cpu)
        for (i = 0; i < num_cache_leaves; i++)
                cache_remove_shared_cpu_map(cpu, i);
 
-       kfree(per_cpu(cpuid4_info, cpu));
-       per_cpu(cpuid4_info, cpu) = NULL;
+       kfree(per_cpu(ici_cpuid4_info, cpu));
+       per_cpu(ici_cpuid4_info, cpu) = NULL;
 }
 
 static int
@@ -614,15 +615,15 @@ static int __cpuinit detect_cache_attributes(unsigned int cpu)
        if (num_cache_leaves == 0)
                return -ENOENT;
 
-       per_cpu(cpuid4_info, cpu) = kzalloc(
+       per_cpu(ici_cpuid4_info, cpu) = kzalloc(
            sizeof(struct _cpuid4_info) * num_cache_leaves, GFP_KERNEL);
-       if (per_cpu(cpuid4_info, cpu) == NULL)
+       if (per_cpu(ici_cpuid4_info, cpu) == NULL)
                return -ENOMEM;
 
        smp_call_function_single(cpu, get_cpu_leaves, &retval, true);
        if (retval) {
-               kfree(per_cpu(cpuid4_info, cpu));
-               per_cpu(cpuid4_info, cpu) = NULL;
+               kfree(per_cpu(ici_cpuid4_info, cpu));
+               per_cpu(ici_cpuid4_info, cpu) = NULL;
        }
 
        return retval;
@@ -634,7 +635,7 @@ static int __cpuinit detect_cache_attributes(unsigned int cpu)
 extern struct sysdev_class cpu_sysdev_class; /* from drivers/base/cpu.c */
 
 /* pointer to kobject for cpuX/cache */
-static DEFINE_PER_CPU(struct kobject *, cache_kobject);
+static DEFINE_PER_CPU(struct kobject *, ici_cache_kobject);
 
 struct _index_kobject {
        struct kobject kobj;
@@ -643,8 +644,8 @@ struct _index_kobject {
 };
 
 /* pointer to array of kobjects for cpuX/cache/indexY */
-static DEFINE_PER_CPU(struct _index_kobject *, index_kobject);
-#define INDEX_KOBJECT_PTR(x, y)                (&((per_cpu(index_kobject, x))[y]))
+static DEFINE_PER_CPU(struct _index_kobject *, ici_index_kobject);
+#define INDEX_KOBJECT_PTR(x, y)                (&((per_cpu(ici_index_kobject, x))[y]))
 
 #define show_one_plus(file_name, object, val)                          \
 static ssize_t show_##file_name                                                \
@@ -863,10 +864,10 @@ static struct kobj_type ktype_percpu_entry = {
 
 static void __cpuinit cpuid4_cache_sysfs_exit(unsigned int cpu)
 {
-       kfree(per_cpu(cache_kobject, cpu));
-       kfree(per_cpu(index_kobject, cpu));
-       per_cpu(cache_kobject, cpu) = NULL;
-       per_cpu(index_kobject, cpu) = NULL;
+       kfree(per_cpu(ici_cache_kobject, cpu));
+       kfree(per_cpu(ici_index_kobject, cpu));
+       per_cpu(ici_cache_kobject, cpu) = NULL;
+       per_cpu(ici_index_kobject, cpu) = NULL;
        free_cache_attributes(cpu);
 }
 
@@ -882,14 +883,14 @@ static int __cpuinit cpuid4_cache_sysfs_init(unsigned int cpu)
                return err;
 
        /* Allocate all required memory */
-       per_cpu(cache_kobject, cpu) =
+       per_cpu(ici_cache_kobject, cpu) =
                kzalloc(sizeof(struct kobject), GFP_KERNEL);
-       if (unlikely(per_cpu(cache_kobject, cpu) == NULL))
+       if (unlikely(per_cpu(ici_cache_kobject, cpu) == NULL))
                goto err_out;
 
-       per_cpu(index_kobject, cpu) = kzalloc(
+       per_cpu(ici_index_kobject, cpu) = kzalloc(
            sizeof(struct _index_kobject) * num_cache_leaves, GFP_KERNEL);
-       if (unlikely(per_cpu(index_kobject, cpu) == NULL))
+       if (unlikely(per_cpu(ici_index_kobject, cpu) == NULL))
                goto err_out;
 
        return 0;
@@ -913,7 +914,7 @@ static int __cpuinit cache_add_dev(struct sys_device * sys_dev)
        if (unlikely(retval < 0))
                return retval;
 
-       retval = kobject_init_and_add(per_cpu(cache_kobject, cpu),
+       retval = kobject_init_and_add(per_cpu(ici_cache_kobject, cpu),
                                      &ktype_percpu_entry,
                                      &sys_dev->kobj, "%s", "cache");
        if (retval < 0) {
@@ -927,12 +928,12 @@ static int __cpuinit cache_add_dev(struct sys_device * sys_dev)
                this_object->index = i;
                retval = kobject_init_and_add(&(this_object->kobj),
                                              &ktype_cache,
-                                             per_cpu(cache_kobject, cpu),
+                                             per_cpu(ici_cache_kobject, cpu),
                                              "index%1lu", i);
                if (unlikely(retval)) {
                        for (j = 0; j < i; j++)
                                kobject_put(&(INDEX_KOBJECT_PTR(cpu, j)->kobj));
-                       kobject_put(per_cpu(cache_kobject, cpu));
+                       kobject_put(per_cpu(ici_cache_kobject, cpu));
                        cpuid4_cache_sysfs_exit(cpu);
                        return retval;
                }
@@ -940,7 +941,7 @@ static int __cpuinit cache_add_dev(struct sys_device * sys_dev)
        }
        cpumask_set_cpu(cpu, to_cpumask(cache_dev_map));
 
-       kobject_uevent(per_cpu(cache_kobject, cpu), KOBJ_ADD);
+       kobject_uevent(per_cpu(ici_cache_kobject, cpu), KOBJ_ADD);
        return 0;
 }
 
@@ -949,7 +950,7 @@ static void __cpuinit cache_remove_dev(struct sys_device * sys_dev)
        unsigned int cpu = sys_dev->id;
        unsigned long i;
 
-       if (per_cpu(cpuid4_info, cpu) == NULL)
+       if (per_cpu(ici_cpuid4_info, cpu) == NULL)
                return;
        if (!cpumask_test_cpu(cpu, to_cpumask(cache_dev_map)))
                return;
@@ -957,7 +958,7 @@ static void __cpuinit cache_remove_dev(struct sys_device * sys_dev)
 
        for (i = 0; i < num_cache_leaves; i++)
                kobject_put(&(INDEX_KOBJECT_PTR(cpu, i)->kobj));
-       kobject_put(per_cpu(cache_kobject, cpu));
+       kobject_put(per_cpu(ici_cache_kobject, cpu));
        cpuid4_cache_sysfs_exit(cpu);
 }
 
index 4fef985fc221622623473c25e9abadda053095c9..81c499eceb21d88f62499a86cb9b0034d8519858 100644 (file)
@@ -256,6 +256,16 @@ asmlinkage void smp_thermal_interrupt(struct pt_regs *regs)
        ack_APIC_irq();
 }
 
+/* Thermal monitoring depends on APIC, ACPI and clock modulation */
+static int intel_thermal_supported(struct cpuinfo_x86 *c)
+{
+       if (!cpu_has_apic)
+               return 0;
+       if (!cpu_has(c, X86_FEATURE_ACPI) || !cpu_has(c, X86_FEATURE_ACC))
+               return 0;
+       return 1;
+}
+
 void __init mcheck_intel_therm_init(void)
 {
        /*
@@ -263,8 +273,7 @@ void __init mcheck_intel_therm_init(void)
         * LVT value on BSP and use that value to restore APs' thermal LVT
         * entry BIOS programmed later
         */
-       if (cpu_has(&boot_cpu_data, X86_FEATURE_ACPI) &&
-               cpu_has(&boot_cpu_data, X86_FEATURE_ACC))
+       if (intel_thermal_supported(&boot_cpu_data))
                lvtthmr_init = apic_read(APIC_LVTTHMR);
 }
 
@@ -274,8 +283,7 @@ void intel_init_thermal(struct cpuinfo_x86 *c)
        int tm2 = 0;
        u32 l, h;
 
-       /* Thermal monitoring depends on ACPI and clock modulation*/
-       if (!cpu_has(c, X86_FEATURE_ACPI) || !cpu_has(c, X86_FEATURE_ACC))
+       if (!intel_thermal_supported(c))
                return;
 
        /*
@@ -339,8 +347,8 @@ void intel_init_thermal(struct cpuinfo_x86 *c)
        l = apic_read(APIC_LVTTHMR);
        apic_write(APIC_LVTTHMR, l & ~APIC_LVT_MASKED);
 
-       printk(KERN_INFO "CPU%d: Thermal monitoring enabled (%s)\n",
-              cpu, tm2 ? "TM2" : "TM1");
+       printk_once(KERN_INFO "CPU0: Thermal monitoring enabled (%s)\n",
+                      tm2 ? "TM2" : "TM1");
 
        /* enable thermal throttle processing */
        atomic_set(&therm_throt_en, 1);
index ef42a038f1a640ed43231e9a3bad1c6e741eff29..1c47390dd0e51ef7ccbd4698302a2b19bcf7ee20 100644 (file)
@@ -265,13 +265,13 @@ struct ds_context {
        int                     cpu;
 };
 
-static DEFINE_PER_CPU(struct ds_context *, cpu_context);
+static DEFINE_PER_CPU(struct ds_context *, cpu_ds_context);
 
 
 static struct ds_context *ds_get_context(struct task_struct *task, int cpu)
 {
        struct ds_context **p_context =
-               (task ? &task->thread.ds_ctx : &per_cpu(cpu_context, cpu));
+               (task ? &task->thread.ds_ctx : &per_cpu(cpu_ds_context, cpu));
        struct ds_context *context = NULL;
        struct ds_context *new_context = NULL;
 
index d17d482a04f4c84edd4e87229372b52621e5d1c8..f50447d961c0fc1b1ff3a8e7e7283663863c558f 100644 (file)
@@ -732,7 +732,16 @@ struct early_res {
        char overlap_ok;
 };
 static struct early_res early_res[MAX_EARLY_RES] __initdata = {
-       { 0, PAGE_SIZE, "BIOS data page" },     /* BIOS data page */
+       { 0, PAGE_SIZE, "BIOS data page", 1 },  /* BIOS data page */
+#ifdef CONFIG_X86_32
+       /*
+        * But first pinch a few for the stack/trampoline stuff
+        * FIXME: Don't need the extra page at 4K, but need to fix
+        * trampoline before removing it. (see the GDT stuff)
+        */
+       { PAGE_SIZE, PAGE_SIZE, "EX TRAMPOLINE", 1 },
+#endif
+
        {}
 };
 
index 4f8e2507e8f3cad33a71d5fdb98f068d977c6aae..5051b94c906986b80bc0c4ff62394fd5d2f3a962 100644 (file)
@@ -29,8 +29,6 @@ static void __init i386_default_early_setup(void)
 
 void __init i386_start_kernel(void)
 {
-       reserve_trampoline_memory();
-
        reserve_early(__pa_symbol(&_text), __pa_symbol(&__bss_stop), "TEXT DATA BSS");
 
 #ifdef CONFIG_BLK_DEV_INITRD
index 0b06cd778fd9c73884f8c1cffc5a359ec4f9c425..b5a9896ca1e74be8805c4f5384ffc8d50f6589b6 100644 (file)
@@ -98,8 +98,6 @@ void __init x86_64_start_reservations(char *real_mode_data)
 {
        copy_bootdata(__va(real_mode_data));
 
-       reserve_trampoline_memory();
-
        reserve_early(__pa_symbol(&_text), __pa_symbol(&__bss_stop), "TEXT DATA BSS");
 
 #ifdef CONFIG_BLK_DEV_INITRD
index 35a57c963df94ecd34cea14601edb81b5c780038..40b54ceb68b560dc61ec81b5d7222298057bb133 100644 (file)
@@ -945,9 +945,6 @@ void __init early_reserve_e820_mpc_new(void)
 {
        if (enable_update_mptable && alloc_mptable) {
                u64 startt = 0;
-#ifdef CONFIG_X86_TRAMPOLINE
-               startt = TRAMPOLINE_BASE;
-#endif
                mpc_new_phys = early_reserve_e820(startt, mpc_new_length, 4);
        }
 }
index afcc58b69c7c8579c11f08405621b85919f88663..fcc2f2bfa39ca17e608fb2c395472494f45a91eb 100644 (file)
@@ -120,11 +120,14 @@ static void __init dma32_free_bootmem(void)
 
 void __init pci_iommu_alloc(void)
 {
+       int use_swiotlb;
+
+       use_swiotlb = pci_swiotlb_init();
 #ifdef CONFIG_X86_64
        /* free the range so iommu could get some range less than 4G */
        dma32_free_bootmem();
 #endif
-       if (pci_swiotlb_init())
+       if (use_swiotlb)
                return;
 
        gart_iommu_hole_init();
index e6a0d402f1714dec4aff2e160b0eff255ea5307b..56c0e730d3fe7bd09913d092c01f009f94f53974 100644 (file)
@@ -710,7 +710,8 @@ static void gart_iommu_shutdown(void)
        struct pci_dev *dev;
        int i;
 
-       if (no_agp)
+       /* don't shutdown it if there is AGP installed */
+       if (!no_agp)
                return;
 
        for (i = 0; i < num_k8_northbridges; i++) {
index 946a311a25c9f894a152e2feba14935dfb5a1bbf..f7b8b9894b226fd8498ab5f886381f68be2541c2 100644 (file)
@@ -73,6 +73,7 @@
 
 #include <asm/mtrr.h>
 #include <asm/apic.h>
+#include <asm/trampoline.h>
 #include <asm/e820.h>
 #include <asm/mpspec.h>
 #include <asm/setup.h>
@@ -875,6 +876,13 @@ void __init setup_arch(char **cmdline_p)
 
        reserve_brk();
 
+       /*
+        * Find and reserve possible boot-time SMP configuration:
+        */
+       find_smp_config();
+
+       reserve_trampoline_memory();
+
 #ifdef CONFIG_ACPI_SLEEP
        /*
         * Reserve low memory region for sleep support.
@@ -921,11 +929,6 @@ void __init setup_arch(char **cmdline_p)
 
        early_acpi_boot_init();
 
-       /*
-        * Find and reserve possible boot-time SMP configuration:
-        */
-       find_smp_config();
-
 #ifdef CONFIG_ACPI_NUMA
        /*
         * Parse SRAT to discover nodes.
index 29e6744f51e3a3eae22409725dd76f1f7f2ceddc..678d0b8c26f3152c67a833f3e782cb15c9d0a61b 100644 (file)
@@ -671,6 +671,26 @@ static void __cpuinit do_fork_idle(struct work_struct *work)
        complete(&c_idle->done);
 }
 
+/* reduce the number of lines printed when booting a large cpu count system */
+static void __cpuinit announce_cpu(int cpu, int apicid)
+{
+       static int current_node = -1;
+       int node = cpu_to_node(cpu);
+
+       if (system_state == SYSTEM_BOOTING) {
+               if (node != current_node) {
+                       if (current_node > (-1))
+                               pr_cont(" Ok.\n");
+                       current_node = node;
+                       pr_info("Booting Node %3d, Processors ", node);
+               }
+               pr_cont(" #%d%s", cpu, cpu == (nr_cpu_ids - 1) ? " Ok.\n" : "");
+               return;
+       } else
+               pr_info("Booting Node %d Processor %d APIC 0x%x\n",
+                       node, cpu, apicid);
+}
+
 /*
  * NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad
  * (ie clustered apic addressing mode), this is a LOGICAL apic ID.
@@ -737,9 +757,8 @@ do_rest:
        /* start_ip had better be page-aligned! */
        start_ip = setup_trampoline();
 
-       /* So we see what's up   */
-       printk(KERN_INFO "Booting processor %d APIC 0x%x ip 0x%lx\n",
-                         cpu, apicid, start_ip);
+       /* So we see what's up */
+       announce_cpu(cpu, apicid);
 
        /*
         * This grunge runs the startup process for
@@ -788,21 +807,17 @@ do_rest:
                        udelay(100);
                }
 
-               if (cpumask_test_cpu(cpu, cpu_callin_mask)) {
-                       /* number CPUs logically, starting from 1 (BSP is 0) */
-                       pr_debug("OK.\n");
-                       printk(KERN_INFO "CPU%d: ", cpu);
-                       print_cpu_info(&cpu_data(cpu));
-                       pr_debug("CPU has booted.\n");
-               } else {
+               if (cpumask_test_cpu(cpu, cpu_callin_mask))
+                       pr_debug("CPU%d: has booted.\n", cpu);
+               else {
                        boot_error = 1;
                        if (*((volatile unsigned char *)trampoline_base)
                                        == 0xA5)
                                /* trampoline started but...? */
-                               printk(KERN_ERR "Stuck ??\n");
+                               pr_err("CPU%d: Stuck ??\n", cpu);
                        else
                                /* trampoline code not run */
-                               printk(KERN_ERR "Not responding.\n");
+                               pr_err("CPU%d: Not responding.\n", cpu);
                        if (apic->inquire_remote_apic)
                                apic->inquire_remote_apic(apicid);
                }
@@ -1293,14 +1308,16 @@ void native_cpu_die(unsigned int cpu)
        for (i = 0; i < 10; i++) {
                /* They ack this in play_dead by setting CPU_DEAD */
                if (per_cpu(cpu_state, cpu) == CPU_DEAD) {
-                       printk(KERN_INFO "CPU %d is now offline\n", cpu);
+                       if (system_state == SYSTEM_RUNNING)
+                               pr_info("CPU %u is now offline\n", cpu);
+
                        if (1 == num_online_cpus())
                                alternatives_smp_switch(0);
                        return;
                }
                msleep(100);
        }
-       printk(KERN_ERR "CPU %u didn't die...\n", cpu);
+       pr_err("CPU %u didn't die...\n", cpu);
 }
 
 void play_dead_common(void)
index cd022121cab611629ec9b04de51677e44bef3567..c652ef62742df62340d03465231e88885c8d5329 100644 (file)
 #endif
 
 /* ready for x86_64 and x86 */
-unsigned char *__trampinitdata trampoline_base = __va(TRAMPOLINE_BASE);
+unsigned char *__trampinitdata trampoline_base;
 
 void __init reserve_trampoline_memory(void)
 {
-#ifdef CONFIG_X86_32
-       /*
-        * But first pinch a few for the stack/trampoline stuff
-        * FIXME: Don't need the extra page at 4K, but need to fix
-        * trampoline before removing it. (see the GDT stuff)
-        */
-       reserve_early(PAGE_SIZE, PAGE_SIZE + PAGE_SIZE, "EX TRAMPOLINE");
-#endif
+       unsigned long mem;
+
        /* Has to be in very low memory so we can execute real-mode AP code. */
-       reserve_early(TRAMPOLINE_BASE, TRAMPOLINE_BASE + TRAMPOLINE_SIZE,
-                       "TRAMPOLINE");
+       mem = find_e820_area(0, 1<<20, TRAMPOLINE_SIZE, PAGE_SIZE);
+       if (mem == -1L)
+               panic("Cannot allocate trampoline\n");
+
+       trampoline_base = __va(mem);
+       reserve_early(mem, mem + TRAMPOLINE_SIZE, "TRAMPOLINE");
 }
 
 /*
index 3de0b37ec038673c3a70b4f14be7dcd5656dfcfe..1d9b33843c80ef521dc059697285cfed06cfd7d7 100644 (file)
@@ -316,7 +316,7 @@ static void svm_hardware_disable(void *garbage)
 static int svm_hardware_enable(void *garbage)
 {
 
-       struct svm_cpu_data *svm_data;
+       struct svm_cpu_data *sd;
        uint64_t efer;
        struct descriptor_table gdt_descr;
        struct desc_struct *gdt;
@@ -331,63 +331,61 @@ static int svm_hardware_enable(void *garbage)
                       me);
                return -EINVAL;
        }
-       svm_data = per_cpu(svm_data, me);
+       sd = per_cpu(svm_data, me);
 
-       if (!svm_data) {
+       if (!sd) {
                printk(KERN_ERR "svm_hardware_enable: svm_data is NULL on %d\n",
                       me);
                return -EINVAL;
        }
 
-       svm_data->asid_generation = 1;
-       svm_data->max_asid = cpuid_ebx(SVM_CPUID_FUNC) - 1;
-       svm_data->next_asid = svm_data->max_asid + 1;
+       sd->asid_generation = 1;
+       sd->max_asid = cpuid_ebx(SVM_CPUID_FUNC) - 1;
+       sd->next_asid = sd->max_asid + 1;
 
        kvm_get_gdt(&gdt_descr);
        gdt = (struct desc_struct *)gdt_descr.base;
-       svm_data->tss_desc = (struct kvm_ldttss_desc *)(gdt + GDT_ENTRY_TSS);
+       sd->tss_desc = (struct kvm_ldttss_desc *)(gdt + GDT_ENTRY_TSS);
 
        wrmsrl(MSR_EFER, efer | EFER_SVME);
 
-       wrmsrl(MSR_VM_HSAVE_PA,
-              page_to_pfn(svm_data->save_area) << PAGE_SHIFT);
+       wrmsrl(MSR_VM_HSAVE_PA, page_to_pfn(sd->save_area) << PAGE_SHIFT);
 
        return 0;
 }
 
 static void svm_cpu_uninit(int cpu)
 {
-       struct svm_cpu_data *svm_data
-               = per_cpu(svm_data, raw_smp_processor_id());
+       struct svm_cpu_data *sd = per_cpu(svm_data, raw_smp_processor_id());
 
-       if (!svm_data)
+       if (!sd)
                return;
 
        per_cpu(svm_data, raw_smp_processor_id()) = NULL;
-       __free_page(svm_data->save_area);
-       kfree(svm_data);
+       __free_page(sd->save_area);
+       kfree(sd);
 }
 
 static int svm_cpu_init(int cpu)
 {
-       struct svm_cpu_data *svm_data;
+       struct svm_cpu_data *sd;
        int r;
 
-       svm_data = kzalloc(sizeof(struct svm_cpu_data), GFP_KERNEL);
-       if (!svm_data)
+       sd = kzalloc(sizeof(struct svm_cpu_data), GFP_KERNEL);
+       if (!sd)
                return -ENOMEM;
-       svm_data->cpu = cpu;
-       svm_data->save_area = alloc_page(GFP_KERNEL);
+       sd->cpu = cpu;
+       sd->save_area = alloc_page(GFP_KERNEL);
        r = -ENOMEM;
-       if (!svm_data->save_area)
+       if (!sd->save_area)
                goto err_1;
 
-       per_cpu(svm_data, cpu) = svm_data;
+       per_cpu(svm_data, cpu) = sd;
 
        return 0;
 
 err_1:
-       kfree(svm_data);
+       kfree(sd);
        return r;
 
 }
@@ -1092,16 +1090,16 @@ static void save_host_msrs(struct kvm_vcpu *vcpu)
 #endif
 }
 
-static void new_asid(struct vcpu_svm *svm, struct svm_cpu_data *svm_data)
+static void new_asid(struct vcpu_svm *svm, struct svm_cpu_data *sd)
 {
-       if (svm_data->next_asid > svm_data->max_asid) {
-               ++svm_data->asid_generation;
-               svm_data->next_asid = 1;
+       if (sd->next_asid > sd->max_asid) {
+               ++sd->asid_generation;
+               sd->next_asid = 1;
                svm->vmcb->control.tlb_ctl = TLB_CONTROL_FLUSH_ALL_ASID;
        }
 
-       svm->asid_generation = svm_data->asid_generation;
-       svm->vmcb->control.asid = svm_data->next_asid++;
+       svm->asid_generation = sd->asid_generation;
+       svm->vmcb->control.asid = sd->next_asid++;
 }
 
 static unsigned long svm_get_dr(struct kvm_vcpu *vcpu, int dr)
@@ -2429,8 +2427,8 @@ static void reload_tss(struct kvm_vcpu *vcpu)
 {
        int cpu = raw_smp_processor_id();
 
-       struct svm_cpu_data *svm_data = per_cpu(svm_data, cpu);
-       svm_data->tss_desc->type = 9; /* available 32/64-bit TSS */
+       struct svm_cpu_data *sd = per_cpu(svm_data, cpu);
+       sd->tss_desc->type = 9; /* available 32/64-bit TSS */
        load_TR_desc();
 }
 
@@ -2438,12 +2436,12 @@ static void pre_svm_run(struct vcpu_svm *svm)
 {
        int cpu = raw_smp_processor_id();
 
-       struct svm_cpu_data *svm_data = per_cpu(svm_data, cpu);
+       struct svm_cpu_data *sd = per_cpu(svm_data, cpu);
 
        svm->vmcb->control.tlb_ctl = TLB_CONTROL_DO_NOTHING;
        /* FIXME: handle wraparound of asid_generation */
-       if (svm->asid_generation != svm_data->asid_generation)
-               new_asid(svm, svm_data);
+       if (svm->asid_generation != sd->asid_generation)
+               new_asid(svm, sd);
 }
 
 static void svm_inject_nmi(struct kvm_vcpu *vcpu)
index 41628b104b9e9ed0bd59724de5ef7d1d131f7aef..872834177937231b5ff9c55965e77929b0d55b98 100644 (file)
@@ -7,7 +7,6 @@ struct msr_info {
        u32 msr_no;
        struct msr reg;
        struct msr *msrs;
-       int off;
        int err;
 };
 
@@ -18,7 +17,7 @@ static void __rdmsr_on_cpu(void *info)
        int this_cpu = raw_smp_processor_id();
 
        if (rv->msrs)
-               reg = &rv->msrs[this_cpu - rv->off];
+               reg = per_cpu_ptr(rv->msrs, this_cpu);
        else
                reg = &rv->reg;
 
@@ -32,7 +31,7 @@ static void __wrmsr_on_cpu(void *info)
        int this_cpu = raw_smp_processor_id();
 
        if (rv->msrs)
-               reg = &rv->msrs[this_cpu - rv->off];
+               reg = per_cpu_ptr(rv->msrs, this_cpu);
        else
                reg = &rv->reg;
 
@@ -80,7 +79,6 @@ static void __rwmsr_on_cpus(const struct cpumask *mask, u32 msr_no,
 
        memset(&rv, 0, sizeof(rv));
 
-       rv.off    = cpumask_first(mask);
        rv.msrs   = msrs;
        rv.msr_no = msr_no;
 
@@ -120,6 +118,26 @@ void wrmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs)
 }
 EXPORT_SYMBOL(wrmsr_on_cpus);
 
+struct msr *msrs_alloc(void)
+{
+       struct msr *msrs = NULL;
+
+       msrs = alloc_percpu(struct msr);
+       if (!msrs) {
+               pr_warning("%s: error allocating msrs\n", __func__);
+               return NULL;
+       }
+
+       return msrs;
+}
+EXPORT_SYMBOL(msrs_alloc);
+
+void msrs_free(struct msr *msrs)
+{
+       free_percpu(msrs);
+}
+EXPORT_SYMBOL(msrs_free);
+
 /* These "safe" variants are slower and should be used when the target MSR
    may not actually exist. */
 static void __rdmsr_safe_on_cpu(void *info)
index 4c765e9c466461f2d50aed098adb522acd5bd0b6..34a3291ca1038969be2657ce8cc7e49fd64a4381 100644 (file)
@@ -20,7 +20,7 @@
  * Derived from the read-mod example from relay-examples by Tom Zanussi.
  */
 
-#define pr_fmt(fmt) "mmiotrace: "
+#define pr_fmt(fmt) "mmiotrace: " fmt
 
 #define DEBUG 1
 
index 64757c0ba5fc2255a4d9188b3a68636832a73a1f..563d20504988ef7671cf600cdc2762f00418a4c8 100644 (file)
 
 cpumask_var_t xen_cpu_initialized_map;
 
-static DEFINE_PER_CPU(int, resched_irq);
-static DEFINE_PER_CPU(int, callfunc_irq);
-static DEFINE_PER_CPU(int, callfuncsingle_irq);
-static DEFINE_PER_CPU(int, debug_irq) = -1;
+static DEFINE_PER_CPU(int, xen_resched_irq);
+static DEFINE_PER_CPU(int, xen_callfunc_irq);
+static DEFINE_PER_CPU(int, xen_callfuncsingle_irq);
+static DEFINE_PER_CPU(int, xen_debug_irq) = -1;
 
 static irqreturn_t xen_call_function_interrupt(int irq, void *dev_id);
 static irqreturn_t xen_call_function_single_interrupt(int irq, void *dev_id);
@@ -103,7 +103,7 @@ static int xen_smp_intr_init(unsigned int cpu)
                                    NULL);
        if (rc < 0)
                goto fail;
-       per_cpu(resched_irq, cpu) = rc;
+       per_cpu(xen_resched_irq, cpu) = rc;
 
        callfunc_name = kasprintf(GFP_KERNEL, "callfunc%d", cpu);
        rc = bind_ipi_to_irqhandler(XEN_CALL_FUNCTION_VECTOR,
@@ -114,7 +114,7 @@ static int xen_smp_intr_init(unsigned int cpu)
                                    NULL);
        if (rc < 0)
                goto fail;
-       per_cpu(callfunc_irq, cpu) = rc;
+       per_cpu(xen_callfunc_irq, cpu) = rc;
 
        debug_name = kasprintf(GFP_KERNEL, "debug%d", cpu);
        rc = bind_virq_to_irqhandler(VIRQ_DEBUG, cpu, xen_debug_interrupt,
@@ -122,7 +122,7 @@ static int xen_smp_intr_init(unsigned int cpu)
                                     debug_name, NULL);
        if (rc < 0)
                goto fail;
-       per_cpu(debug_irq, cpu) = rc;
+       per_cpu(xen_debug_irq, cpu) = rc;
 
        callfunc_name = kasprintf(GFP_KERNEL, "callfuncsingle%d", cpu);
        rc = bind_ipi_to_irqhandler(XEN_CALL_FUNCTION_SINGLE_VECTOR,
@@ -133,19 +133,20 @@ static int xen_smp_intr_init(unsigned int cpu)
                                    NULL);
        if (rc < 0)
                goto fail;
-       per_cpu(callfuncsingle_irq, cpu) = rc;
+       per_cpu(xen_callfuncsingle_irq, cpu) = rc;
 
        return 0;
 
  fail:
-       if (per_cpu(resched_irq, cpu) >= 0)
-               unbind_from_irqhandler(per_cpu(resched_irq, cpu), NULL);
-       if (per_cpu(callfunc_irq, cpu) >= 0)
-               unbind_from_irqhandler(per_cpu(callfunc_irq, cpu), NULL);
-       if (per_cpu(debug_irq, cpu) >= 0)
-               unbind_from_irqhandler(per_cpu(debug_irq, cpu), NULL);
-       if (per_cpu(callfuncsingle_irq, cpu) >= 0)
-               unbind_from_irqhandler(per_cpu(callfuncsingle_irq, cpu), NULL);
+       if (per_cpu(xen_resched_irq, cpu) >= 0)
+               unbind_from_irqhandler(per_cpu(xen_resched_irq, cpu), NULL);
+       if (per_cpu(xen_callfunc_irq, cpu) >= 0)
+               unbind_from_irqhandler(per_cpu(xen_callfunc_irq, cpu), NULL);
+       if (per_cpu(xen_debug_irq, cpu) >= 0)
+               unbind_from_irqhandler(per_cpu(xen_debug_irq, cpu), NULL);
+       if (per_cpu(xen_callfuncsingle_irq, cpu) >= 0)
+               unbind_from_irqhandler(per_cpu(xen_callfuncsingle_irq, cpu),
+                                      NULL);
 
        return rc;
 }
@@ -349,10 +350,10 @@ static void xen_cpu_die(unsigned int cpu)
                current->state = TASK_UNINTERRUPTIBLE;
                schedule_timeout(HZ/10);
        }
-       unbind_from_irqhandler(per_cpu(resched_irq, cpu), NULL);
-       unbind_from_irqhandler(per_cpu(callfunc_irq, cpu), NULL);
-       unbind_from_irqhandler(per_cpu(debug_irq, cpu), NULL);
-       unbind_from_irqhandler(per_cpu(callfuncsingle_irq, cpu), NULL);
+       unbind_from_irqhandler(per_cpu(xen_resched_irq, cpu), NULL);
+       unbind_from_irqhandler(per_cpu(xen_callfunc_irq, cpu), NULL);
+       unbind_from_irqhandler(per_cpu(xen_debug_irq, cpu), NULL);
+       unbind_from_irqhandler(per_cpu(xen_callfuncsingle_irq, cpu), NULL);
        xen_uninit_lock_cpu(cpu);
        xen_teardown_timer(cpu);
 
index 9d1f853120d859cfc814e0f2eaa2e01b3f1575e8..0d3f07cd1b5fe9aee977674b11b0beb311e25eb0 100644 (file)
 #define NS_PER_TICK    (1000000000LL / HZ)
 
 /* runstate info updated by Xen */
-static DEFINE_PER_CPU(struct vcpu_runstate_info, runstate);
+static DEFINE_PER_CPU(struct vcpu_runstate_info, xen_runstate);
 
 /* snapshots of runstate info */
-static DEFINE_PER_CPU(struct vcpu_runstate_info, runstate_snapshot);
+static DEFINE_PER_CPU(struct vcpu_runstate_info, xen_runstate_snapshot);
 
 /* unused ns of stolen and blocked time */
-static DEFINE_PER_CPU(u64, residual_stolen);
-static DEFINE_PER_CPU(u64, residual_blocked);
+static DEFINE_PER_CPU(u64, xen_residual_stolen);
+static DEFINE_PER_CPU(u64, xen_residual_blocked);
 
 /* return an consistent snapshot of 64-bit time/counter value */
 static u64 get64(const u64 *p)
@@ -79,7 +79,7 @@ static void get_runstate_snapshot(struct vcpu_runstate_info *res)
 
        BUG_ON(preemptible());
 
-       state = &__get_cpu_var(runstate);
+       state = &__get_cpu_var(xen_runstate);
 
        /*
         * The runstate info is always updated by the hypervisor on
@@ -97,14 +97,14 @@ static void get_runstate_snapshot(struct vcpu_runstate_info *res)
 /* return true when a vcpu could run but has no real cpu to run on */
 bool xen_vcpu_stolen(int vcpu)
 {
-       return per_cpu(runstate, vcpu).state == RUNSTATE_runnable;
+       return per_cpu(xen_runstate, vcpu).state == RUNSTATE_runnable;
 }
 
 void xen_setup_runstate_info(int cpu)
 {
        struct vcpu_register_runstate_memory_area area;
 
-       area.addr.v = &per_cpu(runstate, cpu);
+       area.addr.v = &per_cpu(xen_runstate, cpu);
 
        if (HYPERVISOR_vcpu_op(VCPUOP_register_runstate_memory_area,
                               cpu, &area))
@@ -122,7 +122,7 @@ static void do_stolen_accounting(void)
 
        WARN_ON(state.state != RUNSTATE_running);
 
-       snap = &__get_cpu_var(runstate_snapshot);
+       snap = &__get_cpu_var(xen_runstate_snapshot);
 
        /* work out how much time the VCPU has not been runn*ing*  */
        blocked = state.time[RUNSTATE_blocked] - snap->time[RUNSTATE_blocked];
@@ -133,24 +133,24 @@ static void do_stolen_accounting(void)
 
        /* Add the appropriate number of ticks of stolen time,
           including any left-overs from last time. */
-       stolen = runnable + offline + __get_cpu_var(residual_stolen);
+       stolen = runnable + offline + __get_cpu_var(xen_residual_stolen);
 
        if (stolen < 0)
                stolen = 0;
 
        ticks = iter_div_u64_rem(stolen, NS_PER_TICK, &stolen);
-       __get_cpu_var(residual_stolen) = stolen;
+       __get_cpu_var(xen_residual_stolen) = stolen;
        account_steal_ticks(ticks);
 
        /* Add the appropriate number of ticks of blocked time,
           including any left-overs from last time. */
-       blocked += __get_cpu_var(residual_blocked);
+       blocked += __get_cpu_var(xen_residual_blocked);
 
        if (blocked < 0)
                blocked = 0;
 
        ticks = iter_div_u64_rem(blocked, NS_PER_TICK, &blocked);
-       __get_cpu_var(residual_blocked) = blocked;
+       __get_cpu_var(xen_residual_blocked) = blocked;
        account_idle_ticks(ticks);
 }
 
index f8ae0d94a6471e0703bfc24900f88dfeb1fc8be7..704c141153236917288ee7a09c12ce8b037754d8 100644 (file)
@@ -99,7 +99,7 @@ static int cryptd_enqueue_request(struct cryptd_queue *queue,
        struct cryptd_cpu_queue *cpu_queue;
 
        cpu = get_cpu();
-       cpu_queue = per_cpu_ptr(queue->cpu_queue, cpu);
+       cpu_queue = this_cpu_ptr(queue->cpu_queue);
        err = crypto_enqueue_request(&cpu_queue->queue, request);
        queue_work_on(cpu, kcrypto_wq, &cpu_queue->work);
        put_cpu();
index 27fd775375b04965b834d7817db43efa059a2c97..958bd1540c303d92f84cbcea016c7da4c0ce925c 100644 (file)
@@ -131,7 +131,7 @@ static ssize_t show_crash_notes(struct sys_device *dev, struct sysdev_attribute
         * boot up and this data does not change there after. Hence this
         * operation should be safe. No locking required.
         */
-       addr = __pa(per_cpu_ptr(crash_notes, cpunum));
+       addr = per_cpu_ptr_to_phys(per_cpu_ptr(crash_notes, cpunum));
        rc = sprintf(buf, "%Lx\n", addr);
        return rc;
 }
index 4008e2ce73c1a37e14ec5e8939d9b3a2ee59efde..fdbcc9fd6d3143a00810fd664d77379ee083717b 100644 (file)
@@ -264,10 +264,16 @@ static ssize_t nvram_write(struct file *file, const char __user *buf,
        unsigned char contents[NVRAM_BYTES];
        unsigned i = *ppos;
        unsigned char *tmp;
-       int len;
 
-       len = (NVRAM_BYTES - i) < count ? (NVRAM_BYTES - i) : count;
-       if (copy_from_user(contents, buf, len))
+       if (i >= NVRAM_BYTES)
+               return 0;       /* Past EOF */
+
+       if (count > NVRAM_BYTES - i)
+               count = NVRAM_BYTES - i;
+       if (count > NVRAM_BYTES)
+               return -EFAULT; /* Can't happen, but prove it to gcc */
+
+       if (copy_from_user(contents, buf, count))
                return -EFAULT;
 
        spin_lock_irq(&rtc_lock);
@@ -275,7 +281,7 @@ static ssize_t nvram_write(struct file *file, const char __user *buf,
        if (!__nvram_check_checksum())
                goto checksum_err;
 
-       for (tmp = contents; count-- > 0 && i < NVRAM_BYTES; ++i, ++tmp)
+       for (tmp = contents; count--; ++i, ++tmp)
                __nvram_write_byte(*tmp, i);
 
        __nvram_set_checksum();
index f20668c09ce0611d3da1fa8582514ccfec949347..67bc2ece7b4b508da7855937a01eb388cd33ab5b 100644 (file)
@@ -64,14 +64,14 @@ static DEFINE_SPINLOCK(cpufreq_driver_lock);
  * - Lock should not be held across
  *     __cpufreq_governor(data, CPUFREQ_GOV_STOP);
  */
-static DEFINE_PER_CPU(int, policy_cpu);
+static DEFINE_PER_CPU(int, cpufreq_policy_cpu);
 static DEFINE_PER_CPU(struct rw_semaphore, cpu_policy_rwsem);
 
 #define lock_policy_rwsem(mode, cpu)                                   \
 int lock_policy_rwsem_##mode                                           \
 (int cpu)                                                              \
 {                                                                      \
-       int policy_cpu = per_cpu(policy_cpu, cpu);                      \
+       int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu);              \
        BUG_ON(policy_cpu == -1);                                       \
        down_##mode(&per_cpu(cpu_policy_rwsem, policy_cpu));            \
        if (unlikely(!cpu_online(cpu))) {                               \
@@ -90,7 +90,7 @@ EXPORT_SYMBOL_GPL(lock_policy_rwsem_write);
 
 void unlock_policy_rwsem_read(int cpu)
 {
-       int policy_cpu = per_cpu(policy_cpu, cpu);
+       int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu);
        BUG_ON(policy_cpu == -1);
        up_read(&per_cpu(cpu_policy_rwsem, policy_cpu));
 }
@@ -98,7 +98,7 @@ EXPORT_SYMBOL_GPL(unlock_policy_rwsem_read);
 
 void unlock_policy_rwsem_write(int cpu)
 {
-       int policy_cpu = per_cpu(policy_cpu, cpu);
+       int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu);
        BUG_ON(policy_cpu == -1);
        up_write(&per_cpu(cpu_policy_rwsem, policy_cpu));
 }
@@ -818,7 +818,7 @@ static int cpufreq_add_dev_policy(unsigned int cpu,
 
                        /* Set proper policy_cpu */
                        unlock_policy_rwsem_write(cpu);
-                       per_cpu(policy_cpu, cpu) = managed_policy->cpu;
+                       per_cpu(cpufreq_policy_cpu, cpu) = managed_policy->cpu;
 
                        if (lock_policy_rwsem_write(cpu) < 0) {
                                /* Should not go through policy unlock path */
@@ -932,7 +932,7 @@ static int cpufreq_add_dev_interface(unsigned int cpu,
        if (!cpu_online(j))
                continue;
                per_cpu(cpufreq_cpu_data, j) = policy;
-               per_cpu(policy_cpu, j) = policy->cpu;
+               per_cpu(cpufreq_policy_cpu, j) = policy->cpu;
        }
        spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
 
@@ -1020,7 +1020,7 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
        cpumask_copy(policy->cpus, cpumask_of(cpu));
 
        /* Initially set CPU itself as the policy_cpu */
-       per_cpu(policy_cpu, cpu) = cpu;
+       per_cpu(cpufreq_policy_cpu, cpu) = cpu;
        ret = (lock_policy_rwsem_write(cpu) < 0);
        WARN_ON(ret);
 
@@ -2002,7 +2002,7 @@ static int __init cpufreq_core_init(void)
        int cpu;
 
        for_each_possible_cpu(cpu) {
-               per_cpu(policy_cpu, cpu) = -1;
+               per_cpu(cpufreq_policy_cpu, cpu) = -1;
                init_rwsem(&per_cpu(cpu_policy_rwsem, cpu));
        }
 
index a9bd3a05a684548cc7f36aa34fe8a1057d2bfbb3..05432216e2246ac4d4c78a665e3e63ec67370015 100644 (file)
@@ -174,7 +174,7 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
 }
 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target);
 
-static DEFINE_PER_CPU(struct cpufreq_frequency_table *, show_table);
+static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table);
 /**
  * show_available_freqs - show available frequencies for the specified CPU
  */
@@ -185,10 +185,10 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
        ssize_t count = 0;
        struct cpufreq_frequency_table *table;
 
-       if (!per_cpu(show_table, cpu))
+       if (!per_cpu(cpufreq_show_table, cpu))
                return -ENODEV;
 
-       table = per_cpu(show_table, cpu);
+       table = per_cpu(cpufreq_show_table, cpu);
 
        for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
                if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
@@ -217,20 +217,20 @@ void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table,
                                      unsigned int cpu)
 {
        dprintk("setting show_table for cpu %u to %p\n", cpu, table);
-       per_cpu(show_table, cpu) = table;
+       per_cpu(cpufreq_show_table, cpu) = table;
 }
 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_attr);
 
 void cpufreq_frequency_table_put_attr(unsigned int cpu)
 {
        dprintk("clearing show_table for cpu %u\n", cpu);
-       per_cpu(show_table, cpu) = NULL;
+       per_cpu(cpufreq_show_table, cpu) = NULL;
 }
 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_put_attr);
 
 struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu)
 {
-       return per_cpu(show_table, cpu);
+       return per_cpu(cpufreq_show_table, cpu);
 }
 EXPORT_SYMBOL_GPL(cpufreq_frequency_get_table);
 
index 84c51e17726966c196ac53ce05671e972f65b98a..8c2f3703ec855f27a6863cb964c5d58a9d01dfa2 100644 (file)
@@ -64,7 +64,7 @@ struct aes_ctx {
        u32 *D;
 };
 
-static DEFINE_PER_CPU(struct cword *, last_cword);
+static DEFINE_PER_CPU(struct cword *, paes_last_cword);
 
 /* Tells whether the ACE is capable to generate
    the extended key for a given key_len. */
@@ -152,9 +152,9 @@ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
 
 ok:
        for_each_online_cpu(cpu)
-               if (&ctx->cword.encrypt == per_cpu(last_cword, cpu) ||
-                   &ctx->cword.decrypt == per_cpu(last_cword, cpu))
-                       per_cpu(last_cword, cpu) = NULL;
+               if (&ctx->cword.encrypt == per_cpu(paes_last_cword, cpu) ||
+                   &ctx->cword.decrypt == per_cpu(paes_last_cword, cpu))
+                       per_cpu(paes_last_cword, cpu) = NULL;
 
        return 0;
 }
@@ -166,7 +166,7 @@ static inline void padlock_reset_key(struct cword *cword)
 {
        int cpu = raw_smp_processor_id();
 
-       if (cword != per_cpu(last_cword, cpu))
+       if (cword != per_cpu(paes_last_cword, cpu))
 #ifndef CONFIG_X86_64
                asm volatile ("pushfl; popfl");
 #else
@@ -176,7 +176,7 @@ static inline void padlock_reset_key(struct cword *cword)
 
 static inline void padlock_store_cword(struct cword *cword)
 {
-       per_cpu(last_cword, raw_smp_processor_id()) = cword;
+       per_cpu(paes_last_cword, raw_smp_processor_id()) = cword;
 }
 
 /*
index 8f99354082ceaa169f7ac081594bc83b0c003478..6f51a0a7a8bbdbca798f53293516e178ead5f4d2 100644 (file)
@@ -326,14 +326,7 @@ arch_initcall(dma_channel_table_init);
  */
 struct dma_chan *dma_find_channel(enum dma_transaction_type tx_type)
 {
-       struct dma_chan *chan;
-       int cpu;
-
-       cpu = get_cpu();
-       chan = per_cpu_ptr(channel_table[tx_type], cpu)->chan;
-       put_cpu();
-
-       return chan;
+       return this_cpu_read(channel_table[tx_type]->chan);
 }
 EXPORT_SYMBOL(dma_find_channel);
 
@@ -857,7 +850,6 @@ dma_async_memcpy_buf_to_buf(struct dma_chan *chan, void *dest,
        struct dma_async_tx_descriptor *tx;
        dma_addr_t dma_dest, dma_src;
        dma_cookie_t cookie;
-       int cpu;
        unsigned long flags;
 
        dma_src = dma_map_single(dev->dev, src, len, DMA_TO_DEVICE);
@@ -876,10 +868,10 @@ dma_async_memcpy_buf_to_buf(struct dma_chan *chan, void *dest,
        tx->callback = NULL;
        cookie = tx->tx_submit(tx);
 
-       cpu = get_cpu();
-       per_cpu_ptr(chan->local, cpu)->bytes_transferred += len;
-       per_cpu_ptr(chan->local, cpu)->memcpy_count++;
-       put_cpu();
+       preempt_disable();
+       __this_cpu_add(chan->local->bytes_transferred, len);
+       __this_cpu_inc(chan->local->memcpy_count);
+       preempt_enable();
 
        return cookie;
 }
@@ -906,7 +898,6 @@ dma_async_memcpy_buf_to_pg(struct dma_chan *chan, struct page *page,
        struct dma_async_tx_descriptor *tx;
        dma_addr_t dma_dest, dma_src;
        dma_cookie_t cookie;
-       int cpu;
        unsigned long flags;
 
        dma_src = dma_map_single(dev->dev, kdata, len, DMA_TO_DEVICE);
@@ -923,10 +914,10 @@ dma_async_memcpy_buf_to_pg(struct dma_chan *chan, struct page *page,
        tx->callback = NULL;
        cookie = tx->tx_submit(tx);
 
-       cpu = get_cpu();
-       per_cpu_ptr(chan->local, cpu)->bytes_transferred += len;
-       per_cpu_ptr(chan->local, cpu)->memcpy_count++;
-       put_cpu();
+       preempt_disable();
+       __this_cpu_add(chan->local->bytes_transferred, len);
+       __this_cpu_inc(chan->local->memcpy_count);
+       preempt_enable();
 
        return cookie;
 }
@@ -955,7 +946,6 @@ dma_async_memcpy_pg_to_pg(struct dma_chan *chan, struct page *dest_pg,
        struct dma_async_tx_descriptor *tx;
        dma_addr_t dma_dest, dma_src;
        dma_cookie_t cookie;
-       int cpu;
        unsigned long flags;
 
        dma_src = dma_map_page(dev->dev, src_pg, src_off, len, DMA_TO_DEVICE);
@@ -973,10 +963,10 @@ dma_async_memcpy_pg_to_pg(struct dma_chan *chan, struct page *dest_pg,
        tx->callback = NULL;
        cookie = tx->tx_submit(tx);
 
-       cpu = get_cpu();
-       per_cpu_ptr(chan->local, cpu)->bytes_transferred += len;
-       per_cpu_ptr(chan->local, cpu)->memcpy_count++;
-       put_cpu();
+       preempt_disable();
+       __this_cpu_add(chan->local->bytes_transferred, len);
+       __this_cpu_inc(chan->local->memcpy_count);
+       preempt_enable();
 
        return cookie;
 }
index 5fdd6daa40eaef5ba7b3284663d0741c592f2c01..df5b68433f3464ab4a03f4ee5453864946364275 100644 (file)
@@ -13,6 +13,8 @@ module_param(report_gart_errors, int, 0644);
 static int ecc_enable_override;
 module_param(ecc_enable_override, int, 0644);
 
+static struct msr *msrs;
+
 /* Lookup table for all possible MC control instances */
 struct amd64_pvt;
 static struct mem_ctl_info *mci_lookup[EDAC_MAX_NUMNODES];
@@ -2495,8 +2497,7 @@ static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, int nid)
 static bool amd64_nb_mce_bank_enabled_on_node(int nid)
 {
        cpumask_var_t mask;
-       struct msr *msrs;
-       int cpu, nbe, idx = 0;
+       int cpu, nbe;
        bool ret = false;
 
        if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) {
@@ -2507,32 +2508,22 @@ static bool amd64_nb_mce_bank_enabled_on_node(int nid)
 
        get_cpus_on_this_dct_cpumask(mask, nid);
 
-       msrs = kzalloc(sizeof(struct msr) * cpumask_weight(mask), GFP_KERNEL);
-       if (!msrs) {
-               amd64_printk(KERN_WARNING, "%s: error allocating msrs\n",
-                             __func__);
-               free_cpumask_var(mask);
-                return false;
-       }
-
        rdmsr_on_cpus(mask, MSR_IA32_MCG_CTL, msrs);
 
        for_each_cpu(cpu, mask) {
-               nbe = msrs[idx].l & K8_MSR_MCGCTL_NBE;
+               struct msr *reg = per_cpu_ptr(msrs, cpu);
+               nbe = reg->l & K8_MSR_MCGCTL_NBE;
 
                debugf0("core: %u, MCG_CTL: 0x%llx, NB MSR is %s\n",
-                       cpu, msrs[idx].q,
+                       cpu, reg->q,
                        (nbe ? "enabled" : "disabled"));
 
                if (!nbe)
                        goto out;
-
-               idx++;
        }
        ret = true;
 
 out:
-       kfree(msrs);
        free_cpumask_var(mask);
        return ret;
 }
@@ -2540,8 +2531,7 @@ out:
 static int amd64_toggle_ecc_err_reporting(struct amd64_pvt *pvt, bool on)
 {
        cpumask_var_t cmask;
-       struct msr *msrs = NULL;
-       int cpu, idx = 0;
+       int cpu;
 
        if (!zalloc_cpumask_var(&cmask, GFP_KERNEL)) {
                amd64_printk(KERN_WARNING, "%s: error allocating mask\n",
@@ -2551,34 +2541,27 @@ static int amd64_toggle_ecc_err_reporting(struct amd64_pvt *pvt, bool on)
 
        get_cpus_on_this_dct_cpumask(cmask, pvt->mc_node_id);
 
-       msrs = kzalloc(sizeof(struct msr) * cpumask_weight(cmask), GFP_KERNEL);
-       if (!msrs) {
-               amd64_printk(KERN_WARNING, "%s: error allocating msrs\n",
-                            __func__);
-               return -ENOMEM;
-       }
-
        rdmsr_on_cpus(cmask, MSR_IA32_MCG_CTL, msrs);
 
        for_each_cpu(cpu, cmask) {
 
+               struct msr *reg = per_cpu_ptr(msrs, cpu);
+
                if (on) {
-                       if (msrs[idx].l & K8_MSR_MCGCTL_NBE)
+                       if (reg->l & K8_MSR_MCGCTL_NBE)
                                pvt->flags.ecc_report = 1;
 
-                       msrs[idx].l |= K8_MSR_MCGCTL_NBE;
+                       reg->l |= K8_MSR_MCGCTL_NBE;
                } else {
                        /*
                         * Turn off ECC reporting only when it was off before
                         */
                        if (!pvt->flags.ecc_report)
-                               msrs[idx].l &= ~K8_MSR_MCGCTL_NBE;
+                               reg->l &= ~K8_MSR_MCGCTL_NBE;
                }
-               idx++;
        }
        wrmsr_on_cpus(cmask, MSR_IA32_MCG_CTL, msrs);
 
-       kfree(msrs);
        free_cpumask_var(cmask);
 
        return 0;
@@ -3036,6 +3019,8 @@ static int __init amd64_edac_init(void)
        if (cache_k8_northbridges() < 0)
                return err;
 
+       msrs = msrs_alloc();
+
        err = pci_register_driver(&amd64_pci_driver);
        if (err)
                return err;
@@ -3071,6 +3056,9 @@ static void __exit amd64_edac_exit(void)
                edac_pci_release_generic_ctl(amd64_ctl_pci);
 
        pci_unregister_driver(&amd64_pci_driver);
+
+       msrs_free(msrs);
+       msrs = NULL;
 }
 
 module_init(amd64_edac_init);
index ad05bbc7ffd5ad98705d8ab6c349f5004cfd7b3a..0f93105873cd263b61bb9c2af47007622e6c2f33 100644 (file)
@@ -34,9 +34,9 @@ static int adp5520_gpio_get_value(struct gpio_chip *chip, unsigned off)
         */
 
        if (test_bit(off, &dev->output))
-               adp5520_read(dev->master, GPIO_OUT, &reg_val);
+               adp5520_read(dev->master, ADP5520_GPIO_OUT, &reg_val);
        else
-               adp5520_read(dev->master, GPIO_IN, &reg_val);
+               adp5520_read(dev->master, ADP5520_GPIO_IN, &reg_val);
 
        return !!(reg_val & dev->lut[off]);
 }
@@ -48,9 +48,9 @@ static void adp5520_gpio_set_value(struct gpio_chip *chip,
        dev = container_of(chip, struct adp5520_gpio, gpio_chip);
 
        if (val)
-               adp5520_set_bits(dev->master, GPIO_OUT, dev->lut[off]);
+               adp5520_set_bits(dev->master, ADP5520_GPIO_OUT, dev->lut[off]);
        else
-               adp5520_clr_bits(dev->master, GPIO_OUT, dev->lut[off]);
+               adp5520_clr_bits(dev->master, ADP5520_GPIO_OUT, dev->lut[off]);
 }
 
 static int adp5520_gpio_direction_input(struct gpio_chip *chip, unsigned off)
@@ -60,7 +60,8 @@ static int adp5520_gpio_direction_input(struct gpio_chip *chip, unsigned off)
 
        clear_bit(off, &dev->output);
 
-       return adp5520_clr_bits(dev->master, GPIO_CFG_2, dev->lut[off]);
+       return adp5520_clr_bits(dev->master, ADP5520_GPIO_CFG_2,
+                               dev->lut[off]);
 }
 
 static int adp5520_gpio_direction_output(struct gpio_chip *chip,
@@ -73,18 +74,21 @@ static int adp5520_gpio_direction_output(struct gpio_chip *chip,
        set_bit(off, &dev->output);
 
        if (val)
-               ret |= adp5520_set_bits(dev->master, GPIO_OUT, dev->lut[off]);
+               ret |= adp5520_set_bits(dev->master, ADP5520_GPIO_OUT,
+                                       dev->lut[off]);
        else
-               ret |= adp5520_clr_bits(dev->master, GPIO_OUT, dev->lut[off]);
+               ret |= adp5520_clr_bits(dev->master, ADP5520_GPIO_OUT,
+                                       dev->lut[off]);
 
-       ret |= adp5520_set_bits(dev->master, GPIO_CFG_2, dev->lut[off]);
+       ret |= adp5520_set_bits(dev->master, ADP5520_GPIO_CFG_2,
+                                       dev->lut[off]);
 
        return ret;
 }
 
 static int __devinit adp5520_gpio_probe(struct platform_device *pdev)
 {
-       struct adp5520_gpio_platfrom_data *pdata = pdev->dev.platform_data;
+       struct adp5520_gpio_platform_data *pdata = pdev->dev.platform_data;
        struct adp5520_gpio *dev;
        struct gpio_chip *gc;
        int ret, i, gpios;
@@ -129,20 +133,20 @@ static int __devinit adp5520_gpio_probe(struct platform_device *pdev)
        gc->label = pdev->name;
        gc->owner = THIS_MODULE;
 
-       ret = adp5520_clr_bits(dev->master, GPIO_CFG_1,
+       ret = adp5520_clr_bits(dev->master, ADP5520_GPIO_CFG_1,
                pdata->gpio_en_mask);
 
-       if (pdata->gpio_en_mask & GPIO_C3)
-               ctl_mask |= C3_MODE;
+       if (pdata->gpio_en_mask & ADP5520_GPIO_C3)
+               ctl_mask |= ADP5520_C3_MODE;
 
-       if (pdata->gpio_en_mask & GPIO_R3)
-               ctl_mask |= R3_MODE;
+       if (pdata->gpio_en_mask & ADP5520_GPIO_R3)
+               ctl_mask |= ADP5520_R3_MODE;
 
        if (ctl_mask)
-               ret = adp5520_set_bits(dev->master, LED_CONTROL,
+               ret = adp5520_set_bits(dev->master, ADP5520_LED_CONTROL,
                        ctl_mask);
 
-       ret |= adp5520_set_bits(dev->master, GPIO_PULLUP,
+       ret |= adp5520_set_bits(dev->master, ADP5520_GPIO_PULLUP,
                pdata->gpio_pullup_mask);
 
        if (ret) {
index 49384a7c54920399e2d629d3e87b6986b3a964eb..7fe881e2bdfb7c4cb5044b12bb9b5160ba8d47a4 100644 (file)
@@ -34,7 +34,7 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 
-#include <linux/i2c/twl4030.h>
+#include <linux/i2c/twl.h>
 
 
 /*
@@ -80,7 +80,7 @@ static unsigned int gpio_usage_count;
  */
 static inline int gpio_twl4030_write(u8 address, u8 data)
 {
-       return twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, data, address);
+       return twl_i2c_write_u8(TWL4030_MODULE_GPIO, data, address);
 }
 
 /*----------------------------------------------------------------------*/
@@ -117,7 +117,7 @@ static inline int gpio_twl4030_read(u8 address)
        u8 data;
        int ret = 0;
 
-       ret = twl4030_i2c_read_u8(TWL4030_MODULE_GPIO, &data, address);
+       ret = twl_i2c_read_u8(TWL4030_MODULE_GPIO, &data, address);
        return (ret < 0) ? ret : data;
 }
 
@@ -142,7 +142,7 @@ static void twl4030_led_set_value(int led, int value)
                cached_leden &= ~mask;
        else
                cached_leden |= mask;
-       status = twl4030_i2c_write_u8(TWL4030_MODULE_LED, cached_leden,
+       status = twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden,
                        TWL4030_LED_LEDEN);
        mutex_unlock(&gpio_lock);
 }
@@ -223,23 +223,23 @@ static int twl_request(struct gpio_chip *chip, unsigned offset)
                }
 
                /* initialize PWM to always-drive */
-               status = twl4030_i2c_write_u8(module, 0x7f,
+               status = twl_i2c_write_u8(module, 0x7f,
                                TWL4030_PWMx_PWMxOFF);
                if (status < 0)
                        goto done;
-               status = twl4030_i2c_write_u8(module, 0x7f,
+               status = twl_i2c_write_u8(module, 0x7f,
                                TWL4030_PWMx_PWMxON);
                if (status < 0)
                        goto done;
 
                /* init LED to not-driven (high) */
                module = TWL4030_MODULE_LED;
-               status = twl4030_i2c_read_u8(module, &cached_leden,
+               status = twl_i2c_read_u8(module, &cached_leden,
                                TWL4030_LED_LEDEN);
                if (status < 0)
                        goto done;
                cached_leden &= ~ledclr_mask;
-               status = twl4030_i2c_write_u8(module, cached_leden,
+               status = twl_i2c_write_u8(module, cached_leden,
                                TWL4030_LED_LEDEN);
                if (status < 0)
                        goto done;
@@ -370,7 +370,7 @@ static int __devinit gpio_twl4030_pulls(u32 ups, u32 downs)
                message[i] = bit_mask;
        }
 
-       return twl4030_i2c_write(TWL4030_MODULE_GPIO, message,
+       return twl_i2c_write(TWL4030_MODULE_GPIO, message,
                                REG_GPIOPUPDCTR1, 5);
 }
 
@@ -387,7 +387,7 @@ static int __devinit gpio_twl4030_debounce(u32 debounce, u8 mmc_cd)
        debounce >>= 8;
        message[3] = (debounce & 0x03);
 
-       return twl4030_i2c_write(TWL4030_MODULE_GPIO, message,
+       return twl_i2c_write(TWL4030_MODULE_GPIO, message,
                                REG_GPIO_DEBEN1, 3);
 }
 
index f9c09a54ec7fb66047bed59fcb4fc5548cee9b2c..b4468b616890ea07ee7058366950047b5aebc89d 100644 (file)
@@ -22,8 +22,7 @@
 #include <linux/mfd/wm831x/core.h>
 #include <linux/mfd/wm831x/pdata.h>
 #include <linux/mfd/wm831x/gpio.h>
-
-#define WM831X_GPIO_MAX 16
+#include <linux/mfd/wm831x/irq.h>
 
 struct wm831x_gpio {
        struct wm831x *wm831x;
@@ -80,6 +79,17 @@ static void wm831x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
                        value << offset);
 }
 
+static int wm831x_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+       struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip);
+       struct wm831x *wm831x = wm831x_gpio->wm831x;
+
+       if (!wm831x->irq_base)
+               return -EINVAL;
+
+       return wm831x->irq_base + WM831X_IRQ_GPIO_1 + offset;
+}
+
 #ifdef CONFIG_DEBUG_FS
 static void wm831x_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 {
@@ -175,6 +185,7 @@ static struct gpio_chip template_chip = {
        .get                    = wm831x_gpio_get,
        .direction_output       = wm831x_gpio_direction_out,
        .set                    = wm831x_gpio_set,
+       .to_irq                 = wm831x_gpio_to_irq,
        .dbg_show               = wm831x_gpio_dbg_show,
        .can_sleep              = 1,
 };
@@ -192,7 +203,7 @@ static int __devinit wm831x_gpio_probe(struct platform_device *pdev)
 
        wm831x_gpio->wm831x = wm831x;
        wm831x_gpio->gpio_chip = template_chip;
-       wm831x_gpio->gpio_chip.ngpio = WM831X_GPIO_MAX;
+       wm831x_gpio->gpio_chip.ngpio = wm831x->num_gpio;
        wm831x_gpio->gpio_chip.dev = &pdev->dev;
        if (pdata && pdata->gpio_base)
                wm831x_gpio->gpio_chip.base = pdata->gpio_base;
index 4b89b791be6a3cf5fdb7947638778ddd4451f8ab..42be0b15084bb2445e6024eea21033d765bf7438 100644 (file)
@@ -826,8 +826,7 @@ static void __cpuinit take_over_work(struct ehca_comp_pool *pool, int cpu)
                cq = list_entry(cct->cq_list.next, struct ehca_cq, entry);
 
                list_del(&cq->entry);
-               __queue_comp_task(cq, per_cpu_ptr(pool->cpu_comp_tasks,
-                                                 smp_processor_id()));
+               __queue_comp_task(cq, this_cpu_ptr(pool->cpu_comp_tasks));
        }
 
        spin_unlock_irqrestore(&cct->task_lock, flags_cct);
index 203b88a82b5658ae28c66d915db48323bb48bf6d..02c836e11813601471de72653381584bdca9684a 100644 (file)
@@ -24,6 +24,16 @@ config KEYBOARD_AAED2000
          To compile this driver as a module, choose M here: the
          module will be called aaed2000_kbd.
 
+config KEYBOARD_ADP5520
+       tristate "Keypad Support for ADP5520 PMIC"
+       depends on PMIC_ADP5520
+       help
+         This option enables support for the keypad scan matrix
+         on Analog Devices ADP5520 PMICs.
+
+         To compile this driver as a module, choose M here: the module will
+         be called adp5520-keys.
+
 config KEYBOARD_ADP5588
        tristate "ADP5588 I2C QWERTY Keypad and IO Expander"
        depends on I2C
index 68c017235ce9c2db3633456b2ac78bf38cf92cb0..78654ef6520644c98710b6ff640acd37bc8c224d 100644 (file)
@@ -5,6 +5,7 @@
 # Each configuration option enables a list of files.
 
 obj-$(CONFIG_KEYBOARD_AAED2000)                += aaed2000_kbd.o
+obj-$(CONFIG_KEYBOARD_ADP5520)         += adp5520-keys.o
 obj-$(CONFIG_KEYBOARD_ADP5588)         += adp5588-keys.o
 obj-$(CONFIG_KEYBOARD_AMIGA)           += amikbd.o
 obj-$(CONFIG_KEYBOARD_ATARI)           += atakbd.o
diff --git a/drivers/input/keyboard/adp5520-keys.c b/drivers/input/keyboard/adp5520-keys.c
new file mode 100644 (file)
index 0000000..a7ba27f
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * Keypad driver for Analog Devices ADP5520 MFD PMICs
+ *
+ * Copyright 2009 Analog Devices Inc.
+ *
+ * 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/input.h>
+#include <linux/mfd/adp5520.h>
+
+struct adp5520_keys {
+       struct input_dev *input;
+       struct notifier_block notifier;
+       struct device *master;
+       unsigned short keycode[ADP5520_KEYMAPSIZE];
+};
+
+static void adp5520_keys_report_event(struct adp5520_keys *dev,
+                                       unsigned short keymask, int value)
+{
+       int i;
+
+       for (i = 0; i < ADP5520_MAXKEYS; i++)
+               if (keymask & (1 << i))
+                       input_report_key(dev->input, dev->keycode[i], value);
+
+       input_sync(dev->input);
+}
+
+static int adp5520_keys_notifier(struct notifier_block *nb,
+                                unsigned long event, void *data)
+{
+       struct adp5520_keys *dev;
+       uint8_t reg_val_lo, reg_val_hi;
+       unsigned short keymask;
+
+       dev = container_of(nb, struct adp5520_keys, notifier);
+
+       if (event & ADP5520_KP_INT) {
+               adp5520_read(dev->master, ADP5520_KP_INT_STAT_1, &reg_val_lo);
+               adp5520_read(dev->master, ADP5520_KP_INT_STAT_2, &reg_val_hi);
+
+               keymask = (reg_val_hi << 8) | reg_val_lo;
+               /* Read twice to clear */
+               adp5520_read(dev->master, ADP5520_KP_INT_STAT_1, &reg_val_lo);
+               adp5520_read(dev->master, ADP5520_KP_INT_STAT_2, &reg_val_hi);
+               keymask |= (reg_val_hi << 8) | reg_val_lo;
+               adp5520_keys_report_event(dev, keymask, 1);
+       }
+
+       if (event & ADP5520_KR_INT) {
+               adp5520_read(dev->master, ADP5520_KR_INT_STAT_1, &reg_val_lo);
+               adp5520_read(dev->master, ADP5520_KR_INT_STAT_2, &reg_val_hi);
+
+               keymask = (reg_val_hi << 8) | reg_val_lo;
+               /* Read twice to clear */
+               adp5520_read(dev->master, ADP5520_KR_INT_STAT_1, &reg_val_lo);
+               adp5520_read(dev->master, ADP5520_KR_INT_STAT_2, &reg_val_hi);
+               keymask |= (reg_val_hi << 8) | reg_val_lo;
+               adp5520_keys_report_event(dev, keymask, 0);
+       }
+
+       return 0;
+}
+
+static int __devinit adp5520_keys_probe(struct platform_device *pdev)
+{
+       struct adp5520_keys_platform_data *pdata = pdev->dev.platform_data;
+       struct input_dev *input;
+       struct adp5520_keys *dev;
+       int ret, i;
+       unsigned char en_mask, ctl_mask = 0;
+
+       if (pdev->id != ID_ADP5520) {
+               dev_err(&pdev->dev, "only ADP5520 supports Keypad\n");
+               return -EINVAL;
+       }
+
+       if (pdata == NULL) {
+               dev_err(&pdev->dev, "missing platform data\n");
+               return -EINVAL;
+       }
+
+       if (!(pdata->rows_en_mask && pdata->cols_en_mask))
+               return -EINVAL;
+
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (dev == NULL) {
+               dev_err(&pdev->dev, "failed to alloc memory\n");
+               return -ENOMEM;
+       }
+
+       input = input_allocate_device();
+       if (!input) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       dev->master = pdev->dev.parent;
+       dev->input = input;
+
+       input->name = pdev->name;
+       input->phys = "adp5520-keys/input0";
+       input->dev.parent = &pdev->dev;
+
+       input_set_drvdata(input, dev);
+
+       input->id.bustype = BUS_I2C;
+       input->id.vendor = 0x0001;
+       input->id.product = 0x5520;
+       input->id.version = 0x0001;
+
+       input->keycodesize = sizeof(dev->keycode[0]);
+       input->keycodemax = pdata->keymapsize;
+       input->keycode = dev->keycode;
+
+       memcpy(dev->keycode, pdata->keymap,
+               pdata->keymapsize * input->keycodesize);
+
+       /* setup input device */
+       __set_bit(EV_KEY, input->evbit);
+
+       if (pdata->repeat)
+               __set_bit(EV_REP, input->evbit);
+
+       for (i = 0; i < input->keycodemax; i++)
+               __set_bit(dev->keycode[i], input->keybit);
+       __clear_bit(KEY_RESERVED, input->keybit);
+
+       ret = input_register_device(input);
+       if (ret) {
+               dev_err(&pdev->dev, "unable to register input device\n");
+               goto err;
+       }
+
+       en_mask = pdata->rows_en_mask | pdata->cols_en_mask;
+
+       ret = adp5520_set_bits(dev->master, ADP5520_GPIO_CFG_1, en_mask);
+
+       if (en_mask & ADP5520_COL_C3)
+               ctl_mask |= ADP5520_C3_MODE;
+
+       if (en_mask & ADP5520_ROW_R3)
+               ctl_mask |= ADP5520_R3_MODE;
+
+       if (ctl_mask)
+               ret |= adp5520_set_bits(dev->master, ADP5520_LED_CONTROL,
+                       ctl_mask);
+
+       ret |= adp5520_set_bits(dev->master, ADP5520_GPIO_PULLUP,
+               pdata->rows_en_mask);
+
+       if (ret) {
+               dev_err(&pdev->dev, "failed to write\n");
+               ret = -EIO;
+               goto err1;
+       }
+
+       dev->notifier.notifier_call = adp5520_keys_notifier;
+       ret = adp5520_register_notifier(dev->master, &dev->notifier,
+                       ADP5520_KP_IEN | ADP5520_KR_IEN);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to register notifier\n");
+               goto err1;
+       }
+
+       platform_set_drvdata(pdev, dev);
+       return 0;
+
+err1:
+       input_unregister_device(input);
+       input = NULL;
+err:
+       input_free_device(input);
+       kfree(dev);
+       return ret;
+}
+
+static int __devexit adp5520_keys_remove(struct platform_device *pdev)
+{
+       struct adp5520_keys *dev = platform_get_drvdata(pdev);
+
+       adp5520_unregister_notifier(dev->master, &dev->notifier,
+                               ADP5520_KP_IEN | ADP5520_KR_IEN);
+
+       input_unregister_device(dev->input);
+       kfree(dev);
+       return 0;
+}
+
+static struct platform_driver adp5520_keys_driver = {
+       .driver = {
+               .name   = "adp5520-keys",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = adp5520_keys_probe,
+       .remove         = __devexit_p(adp5520_keys_remove),
+};
+
+static int __init adp5520_keys_init(void)
+{
+       return platform_driver_register(&adp5520_keys_driver);
+}
+module_init(adp5520_keys_init);
+
+static void __exit adp5520_keys_exit(void)
+{
+       platform_driver_unregister(&adp5520_keys_driver);
+}
+module_exit(adp5520_keys_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Keys ADP5520 Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:adp5520-keys");
index 9a2977c216967d3c7a23daca744e8f136663c213..eeaa7acb9cfcfcc4ebf847a7035874a60c169d72 100644 (file)
@@ -31,7 +31,7 @@
 #include <linux/interrupt.h>
 #include <linux/input.h>
 #include <linux/platform_device.h>
-#include <linux/i2c/twl4030.h>
+#include <linux/i2c/twl.h>
 
 
 /*
@@ -133,7 +133,7 @@ struct twl4030_keypad {
 static int twl4030_kpread(struct twl4030_keypad *kp,
                u8 *data, u32 reg, u8 num_bytes)
 {
-       int ret = twl4030_i2c_read(TWL4030_MODULE_KEYPAD, data, reg, num_bytes);
+       int ret = twl_i2c_read(TWL4030_MODULE_KEYPAD, data, reg, num_bytes);
 
        if (ret < 0)
                dev_warn(kp->dbg_dev,
@@ -145,7 +145,7 @@ static int twl4030_kpread(struct twl4030_keypad *kp,
 
 static int twl4030_kpwrite_u8(struct twl4030_keypad *kp, u8 data, u32 reg)
 {
-       int ret = twl4030_i2c_write_u8(TWL4030_MODULE_KEYPAD, data, reg);
+       int ret = twl_i2c_write_u8(TWL4030_MODULE_KEYPAD, data, reg);
 
        if (ret < 0)
                dev_warn(kp->dbg_dev,
index 039dcb00ebd96250efea2a7b5903cb4521dee60f..008de0c5834b711d5efbf2de439f0104a3019916 100644 (file)
@@ -55,7 +55,6 @@ pcf50633_input_irq(int irq, void *data)
 static int __devinit pcf50633_input_probe(struct platform_device *pdev)
 {
        struct pcf50633_input *input;
-       struct pcf50633_subdev_pdata *pdata = pdev->dev.platform_data;
        struct input_dev *input_dev;
        int ret;
 
@@ -71,7 +70,7 @@ static int __devinit pcf50633_input_probe(struct platform_device *pdev)
        }
 
        platform_set_drvdata(pdev, input);
-       input->pcf = pdata->pcf;
+       input->pcf = dev_to_pcf50633(pdev->dev.parent);
        input->input_dev = input_dev;
 
        input_dev->name = "PCF50633 PMU events";
@@ -85,9 +84,9 @@ static int __devinit pcf50633_input_probe(struct platform_device *pdev)
                kfree(input);
                return ret;
        }
-       pcf50633_register_irq(pdata->pcf, PCF50633_IRQ_ONKEYR,
+       pcf50633_register_irq(input->pcf, PCF50633_IRQ_ONKEYR,
                                pcf50633_input_irq, input);
-       pcf50633_register_irq(pdata->pcf, PCF50633_IRQ_ONKEYF,
+       pcf50633_register_irq(input->pcf, PCF50633_IRQ_ONKEYF,
                                pcf50633_input_irq, input);
 
        return 0;
index f5fc9974a111842cd18af2bfd21ef9f762cd3c05..bdde5c8890358aa9ea7025008c93501f098b370d 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/input.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
-#include <linux/i2c/twl4030.h>
+#include <linux/i2c/twl.h>
 
 #define PWR_PWRON_IRQ (1 << 0)
 
@@ -49,7 +49,7 @@ static irqreturn_t powerbutton_irq(int irq, void *_pwr)
        local_irq_enable();
 #endif
 
-       err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &value,
+       err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &value,
                                  STS_HW_CONDITIONS);
        if (!err)  {
                input_report_key(pwr, KEY_POWER, value & PWR_PWRON_IRQ);
index 5a6ae646a6363efe0e28ee0639fca7ef8263b35c..94b796d84053986aa17f58afd7a4f64cd74ab161 100644 (file)
@@ -108,8 +108,7 @@ static int avmcs_probe(struct pcmcia_device *p_dev)
     p_dev->io.NumPorts2 = 0;
 
     /* Interrupt setup */
-    p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
-    p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
+    p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
 
     /* General socket configuration */
     p_dev->conf.Attributes = CONF_ENABLE_IRQ;
index f9bdff39cf4aff3dd32e33ac2b417eb145e4fbf3..e5deb15cf40c9ec2a2354375ef174afe83e8e05f 100644 (file)
@@ -120,8 +120,7 @@ static int avma1cs_probe(struct pcmcia_device *p_dev)
     p_dev->io.IOAddrLines = 5;
 
     /* Interrupt setup */
-    p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
-    p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
+    p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
 
     /* General socket configuration */
     p_dev->conf.Attributes = CONF_ENABLE_IRQ;
index a2f709f5397413f8352e66391207875bdbd93c1d..c9a30b1c92372373a652f877dad6d62d65dbf19f 100644 (file)
@@ -137,7 +137,7 @@ static int elsa_cs_probe(struct pcmcia_device *link)
     local->cardnr = -1;
 
     /* Interrupt setup */
-    link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
+    link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
     link->irq.Handler = NULL;
 
     /*
index af5d393cc2d0afe2f099ad72ef489c411117391b..7836ec3c7f86fb723131c10185a1ef432ec12d13 100644 (file)
@@ -144,7 +144,7 @@ static int sedlbauer_probe(struct pcmcia_device *link)
     link->priv = local;
 
     /* Interrupt setup */
-    link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
+    link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
     link->irq.Handler = NULL;
 
     /*
index ea705394ce2bf4c06d7d6c49b87dd5d0c16063e4..b0c5976cbdb356c8941d77a0dfc54a166379e4d0 100644 (file)
@@ -127,7 +127,7 @@ static int teles_probe(struct pcmcia_device *link)
     link->priv = local;
 
     /* Interrupt setup */
-    link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
+    link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
     link->irq.Handler = NULL;
 
     /*
index 6ae388849a3b1c60c7b7263041c6f46552c1a7fc..fb2b7ef7868ef6e0126c932049122f729fab7cb1 100644 (file)
@@ -69,7 +69,7 @@ static struct lguest_pages *lguest_pages(unsigned int cpu)
                  (SWITCHER_ADDR + SHARED_SWITCHER_PAGES*PAGE_SIZE))[cpu]);
 }
 
-static DEFINE_PER_CPU(struct lg_cpu *, last_cpu);
+static DEFINE_PER_CPU(struct lg_cpu *, lg_last_cpu);
 
 /*S:010
  * We approach the Switcher.
@@ -90,8 +90,8 @@ static void copy_in_guest_info(struct lg_cpu *cpu, struct lguest_pages *pages)
         * meanwhile).  If that's not the case, we pretend everything in the
         * Guest has changed.
         */
-       if (__get_cpu_var(last_cpu) != cpu || cpu->last_pages != pages) {
-               __get_cpu_var(last_cpu) = cpu;
+       if (__get_cpu_var(lg_last_cpu) != cpu || cpu->last_pages != pages) {
+               __get_cpu_var(lg_last_cpu) = cpu;
                cpu->last_pages = pages;
                cpu->changed = CHANGED_ALL;
        }
index 2158377a13593a45938278ac860d5de3db8a06fa..acb3a4e404ff22b53a6c3017ee3affe2439306fc 100644 (file)
@@ -185,11 +185,10 @@ config MD_MULTIPATH
        tristate "Multipath I/O support"
        depends on BLK_DEV_MD
        help
-         Multipath-IO is the ability of certain devices to address the same
-         physical disk over multiple 'IO paths'. The code ensures that such
-         paths can be defined and handled at runtime, and ensures that a
-         transparent failover to the backup path(s) happens if a IO errors
-         arrives on the primary path.
+         MD_MULTIPATH provides a simple multi-path personality for use
+         the MD framework.  It is not under active development.  New
+         projects should consider using DM_MULTIPATH which has more
+         features and more testing.
 
          If unsure, say N.
 
index 60e2b322db110b96d52f66e4f502610b29d822fe..26ac8aad0b1993dab39cf91fc692f5dca534cdb5 100644 (file)
@@ -212,7 +212,7 @@ static void bitmap_checkfree(struct bitmap *bitmap, unsigned long page)
  */
 
 /* IO operations when bitmap is stored near all superblocks */
-static struct page *read_sb_page(mddev_t *mddev, long offset,
+static struct page *read_sb_page(mddev_t *mddev, loff_t offset,
                                 struct page *page,
                                 unsigned long index, int size)
 {
@@ -287,27 +287,36 @@ static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait)
 
        while ((rdev = next_active_rdev(rdev, mddev)) != NULL) {
                        int size = PAGE_SIZE;
+                       loff_t offset = mddev->bitmap_info.offset;
                        if (page->index == bitmap->file_pages-1)
                                size = roundup(bitmap->last_page_size,
                                               bdev_logical_block_size(rdev->bdev));
                        /* Just make sure we aren't corrupting data or
                         * metadata
                         */
-                       if (bitmap->offset < 0) {
+                       if (mddev->external) {
+                               /* Bitmap could be anywhere. */
+                               if (rdev->sb_start + offset + (page->index *(PAGE_SIZE/512)) >
+                                   rdev->data_offset &&
+                                   rdev->sb_start + offset < 
+                                   rdev->data_offset + mddev->dev_sectors +
+                                   (PAGE_SIZE/512))
+                                       goto bad_alignment;
+                       } else if (offset < 0) {
                                /* DATA  BITMAP METADATA  */
-                               if (bitmap->offset
+                               if (offset
                                    + (long)(page->index * (PAGE_SIZE/512))
                                    + size/512 > 0)
                                        /* bitmap runs in to metadata */
                                        goto bad_alignment;
                                if (rdev->data_offset + mddev->dev_sectors
-                                   > rdev->sb_start + bitmap->offset)
+                                   > rdev->sb_start + offset)
                                        /* data runs in to bitmap */
                                        goto bad_alignment;
                        } else if (rdev->sb_start < rdev->data_offset) {
                                /* METADATA BITMAP DATA */
                                if (rdev->sb_start
-                                   + bitmap->offset
+                                   + offset
                                    + page->index*(PAGE_SIZE/512) + size/512
                                    > rdev->data_offset)
                                        /* bitmap runs in to data */
@@ -316,7 +325,7 @@ static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait)
                                /* DATA METADATA BITMAP - no problems */
                        }
                        md_super_write(mddev, rdev,
-                                      rdev->sb_start + bitmap->offset
+                                      rdev->sb_start + offset
                                       + page->index * (PAGE_SIZE/512),
                                       size,
                                       page);
@@ -488,6 +497,8 @@ void bitmap_update_sb(struct bitmap *bitmap)
 
        if (!bitmap || !bitmap->mddev) /* no bitmap for this array */
                return;
+       if (bitmap->mddev->bitmap_info.external)
+               return;
        spin_lock_irqsave(&bitmap->lock, flags);
        if (!bitmap->sb_page) { /* no superblock */
                spin_unlock_irqrestore(&bitmap->lock, flags);
@@ -501,6 +512,9 @@ void bitmap_update_sb(struct bitmap *bitmap)
                bitmap->events_cleared = bitmap->mddev->events;
                sb->events_cleared = cpu_to_le64(bitmap->events_cleared);
        }
+       /* Just in case these have been changed via sysfs: */
+       sb->daemon_sleep = cpu_to_le32(bitmap->mddev->bitmap_info.daemon_sleep/HZ);
+       sb->write_behind = cpu_to_le32(bitmap->mddev->bitmap_info.max_write_behind);
        kunmap_atomic(sb, KM_USER0);
        write_page(bitmap, bitmap->sb_page, 1);
 }
@@ -550,7 +564,8 @@ static int bitmap_read_sb(struct bitmap *bitmap)
 
                bitmap->sb_page = read_page(bitmap->file, 0, bitmap, bytes);
        } else {
-               bitmap->sb_page = read_sb_page(bitmap->mddev, bitmap->offset,
+               bitmap->sb_page = read_sb_page(bitmap->mddev,
+                                              bitmap->mddev->bitmap_info.offset,
                                               NULL,
                                               0, sizeof(bitmap_super_t));
        }
@@ -563,7 +578,7 @@ static int bitmap_read_sb(struct bitmap *bitmap)
        sb = (bitmap_super_t *)kmap_atomic(bitmap->sb_page, KM_USER0);
 
        chunksize = le32_to_cpu(sb->chunksize);
-       daemon_sleep = le32_to_cpu(sb->daemon_sleep);
+       daemon_sleep = le32_to_cpu(sb->daemon_sleep) * HZ;
        write_behind = le32_to_cpu(sb->write_behind);
 
        /* verify that the bitmap-specific fields are valid */
@@ -576,7 +591,7 @@ static int bitmap_read_sb(struct bitmap *bitmap)
                reason = "bitmap chunksize too small";
        else if ((1 << ffz(~chunksize)) != chunksize)
                reason = "bitmap chunksize not a power of 2";
-       else if (daemon_sleep < 1 || daemon_sleep > MAX_SCHEDULE_TIMEOUT / HZ)
+       else if (daemon_sleep < 1 || daemon_sleep > MAX_SCHEDULE_TIMEOUT)
                reason = "daemon sleep period out of range";
        else if (write_behind > COUNTER_MAX)
                reason = "write-behind limit out of range (0 - 16383)";
@@ -610,10 +625,9 @@ static int bitmap_read_sb(struct bitmap *bitmap)
        }
 success:
        /* assign fields using values from superblock */
-       bitmap->chunksize = chunksize;
-       bitmap->daemon_sleep = daemon_sleep;
-       bitmap->daemon_lastrun = jiffies;
-       bitmap->max_write_behind = write_behind;
+       bitmap->mddev->bitmap_info.chunksize = chunksize;
+       bitmap->mddev->bitmap_info.daemon_sleep = daemon_sleep;
+       bitmap->mddev->bitmap_info.max_write_behind = write_behind;
        bitmap->flags |= le32_to_cpu(sb->state);
        if (le32_to_cpu(sb->version) == BITMAP_MAJOR_HOSTENDIAN)
                bitmap->flags |= BITMAP_HOSTENDIAN;
@@ -664,16 +678,26 @@ static int bitmap_mask_state(struct bitmap *bitmap, enum bitmap_state bits,
  * general bitmap file operations
  */
 
+/*
+ * on-disk bitmap:
+ *
+ * Use one bit per "chunk" (block set). We do the disk I/O on the bitmap
+ * file a page at a time. There's a superblock at the start of the file.
+ */
 /* calculate the index of the page that contains this bit */
-static inline unsigned long file_page_index(unsigned long chunk)
+static inline unsigned long file_page_index(struct bitmap *bitmap, unsigned long chunk)
 {
-       return CHUNK_BIT_OFFSET(chunk) >> PAGE_BIT_SHIFT;
+       if (!bitmap->mddev->bitmap_info.external)
+               chunk += sizeof(bitmap_super_t) << 3;
+       return chunk >> PAGE_BIT_SHIFT;
 }
 
 /* calculate the (bit) offset of this bit within a page */
-static inline unsigned long file_page_offset(unsigned long chunk)
+static inline unsigned long file_page_offset(struct bitmap *bitmap, unsigned long chunk)
 {
-       return CHUNK_BIT_OFFSET(chunk) & (PAGE_BITS - 1);
+       if (!bitmap->mddev->bitmap_info.external)
+               chunk += sizeof(bitmap_super_t) << 3;
+       return chunk & (PAGE_BITS - 1);
 }
 
 /*
@@ -686,8 +710,9 @@ static inline unsigned long file_page_offset(unsigned long chunk)
 static inline struct page *filemap_get_page(struct bitmap *bitmap,
                                        unsigned long chunk)
 {
-       if (file_page_index(chunk) >= bitmap->file_pages) return NULL;
-       return bitmap->filemap[file_page_index(chunk) - file_page_index(0)];
+       if (file_page_index(bitmap, chunk) >= bitmap->file_pages) return NULL;
+       return bitmap->filemap[file_page_index(bitmap, chunk)
+                              - file_page_index(bitmap, 0)];
 }
 
 
@@ -710,7 +735,7 @@ static void bitmap_file_unmap(struct bitmap *bitmap)
        spin_unlock_irqrestore(&bitmap->lock, flags);
 
        while (pages--)
-               if (map[pages]->index != 0) /* 0 is sb_page, release it below */
+               if (map[pages] != sb_page) /* 0 is sb_page, release it below */
                        free_buffers(map[pages]);
        kfree(map);
        kfree(attr);
@@ -821,7 +846,7 @@ static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block)
 
        page = filemap_get_page(bitmap, chunk);
        if (!page) return;
-       bit = file_page_offset(chunk);
+       bit = file_page_offset(bitmap, chunk);
 
        /* set the bit */
        kaddr = kmap_atomic(page, KM_USER0);
@@ -907,7 +932,7 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
        chunks = bitmap->chunks;
        file = bitmap->file;
 
-       BUG_ON(!file && !bitmap->offset);
+       BUG_ON(!file && !bitmap->mddev->bitmap_info.offset);
 
 #ifdef INJECT_FAULTS_3
        outofdate = 1;
@@ -919,14 +944,17 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
                        "recovery\n", bmname(bitmap));
 
        bytes = (chunks + 7) / 8;
+       if (!bitmap->mddev->bitmap_info.external)
+               bytes += sizeof(bitmap_super_t);
 
-       num_pages = (bytes + sizeof(bitmap_super_t) + PAGE_SIZE - 1) / PAGE_SIZE;
+       
+       num_pages = (bytes + PAGE_SIZE - 1) / PAGE_SIZE;
 
-       if (file && i_size_read(file->f_mapping->host) < bytes + sizeof(bitmap_super_t)) {
+       if (file && i_size_read(file->f_mapping->host) < bytes) {
                printk(KERN_INFO "%s: bitmap file too short %lu < %lu\n",
                        bmname(bitmap),
                        (unsigned long) i_size_read(file->f_mapping->host),
-                       bytes + sizeof(bitmap_super_t));
+                       bytes);
                goto err;
        }
 
@@ -947,17 +975,16 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
 
        for (i = 0; i < chunks; i++) {
                int b;
-               index = file_page_index(i);
-               bit = file_page_offset(i);
+               index = file_page_index(bitmap, i);
+               bit = file_page_offset(bitmap, i);
                if (index != oldindex) { /* this is a new page, read it in */
                        int count;
                        /* unmap the old page, we're done with it */
                        if (index == num_pages-1)
-                               count = bytes + sizeof(bitmap_super_t)
-                                       - index * PAGE_SIZE;
+                               count = bytes - index * PAGE_SIZE;
                        else
                                count = PAGE_SIZE;
-                       if (index == 0) {
+                       if (index == 0 && bitmap->sb_page) {
                                /*
                                 * if we're here then the superblock page
                                 * contains some bits (PAGE_SIZE != sizeof sb)
@@ -967,14 +994,15 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
                                offset = sizeof(bitmap_super_t);
                                if (!file)
                                        read_sb_page(bitmap->mddev,
-                                                    bitmap->offset,
+                                                    bitmap->mddev->bitmap_info.offset,
                                                     page,
                                                     index, count);
                        } else if (file) {
                                page = read_page(file, index, bitmap, count);
                                offset = 0;
                        } else {
-                               page = read_sb_page(bitmap->mddev, bitmap->offset,
+                               page = read_sb_page(bitmap->mddev,
+                                                   bitmap->mddev->bitmap_info.offset,
                                                    NULL,
                                                    index, count);
                                offset = 0;
@@ -1078,23 +1106,32 @@ static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap,
  *                     out to disk
  */
 
-void bitmap_daemon_work(struct bitmap *bitmap)
+void bitmap_daemon_work(mddev_t *mddev)
 {
+       struct bitmap *bitmap;
        unsigned long j;
        unsigned long flags;
        struct page *page = NULL, *lastpage = NULL;
        int blocks;
        void *paddr;
 
-       if (bitmap == NULL)
+       /* Use a mutex to guard daemon_work against
+        * bitmap_destroy.
+        */
+       mutex_lock(&mddev->bitmap_info.mutex);
+       bitmap = mddev->bitmap;
+       if (bitmap == NULL) {
+               mutex_unlock(&mddev->bitmap_info.mutex);
                return;
-       if (time_before(jiffies, bitmap->daemon_lastrun + bitmap->daemon_sleep*HZ))
+       }
+       if (time_before(jiffies, bitmap->daemon_lastrun
+                       + bitmap->mddev->bitmap_info.daemon_sleep))
                goto done;
 
        bitmap->daemon_lastrun = jiffies;
        if (bitmap->allclean) {
                bitmap->mddev->thread->timeout = MAX_SCHEDULE_TIMEOUT;
-               return;
+               goto done;
        }
        bitmap->allclean = 1;
 
@@ -1142,7 +1179,8 @@ void bitmap_daemon_work(struct bitmap *bitmap)
                        /* We are possibly going to clear some bits, so make
                         * sure that events_cleared is up-to-date.
                         */
-                       if (bitmap->need_sync) {
+                       if (bitmap->need_sync &&
+                           bitmap->mddev->bitmap_info.external == 0) {
                                bitmap_super_t *sb;
                                bitmap->need_sync = 0;
                                sb = kmap_atomic(bitmap->sb_page, KM_USER0);
@@ -1152,7 +1190,8 @@ void bitmap_daemon_work(struct bitmap *bitmap)
                                write_page(bitmap, bitmap->sb_page, 1);
                        }
                        spin_lock_irqsave(&bitmap->lock, flags);
-                       clear_page_attr(bitmap, page, BITMAP_PAGE_CLEAN);
+                       if (!bitmap->need_sync)
+                               clear_page_attr(bitmap, page, BITMAP_PAGE_CLEAN);
                }
                bmc = bitmap_get_counter(bitmap,
                                         (sector_t)j << CHUNK_BLOCK_SHIFT(bitmap),
@@ -1167,7 +1206,7 @@ void bitmap_daemon_work(struct bitmap *bitmap)
                        if (*bmc == 2) {
                                *bmc=1; /* maybe clear the bit next time */
                                set_page_attr(bitmap, page, BITMAP_PAGE_CLEAN);
-                       } else if (*bmc == 1) {
+                       } else if (*bmc == 1 && !bitmap->need_sync) {
                                /* we can clear the bit */
                                *bmc = 0;
                                bitmap_count_page(bitmap,
@@ -1177,9 +1216,11 @@ void bitmap_daemon_work(struct bitmap *bitmap)
                                /* clear the bit */
                                paddr = kmap_atomic(page, KM_USER0);
                                if (bitmap->flags & BITMAP_HOSTENDIAN)
-                                       clear_bit(file_page_offset(j), paddr);
+                                       clear_bit(file_page_offset(bitmap, j),
+                                                 paddr);
                                else
-                                       ext2_clear_bit(file_page_offset(j), paddr);
+                                       ext2_clear_bit(file_page_offset(bitmap, j),
+                                                      paddr);
                                kunmap_atomic(paddr, KM_USER0);
                        }
                } else
@@ -1202,7 +1243,9 @@ void bitmap_daemon_work(struct bitmap *bitmap)
 
  done:
        if (bitmap->allclean == 0)
-               bitmap->mddev->thread->timeout = bitmap->daemon_sleep * HZ;
+               bitmap->mddev->thread->timeout = 
+                       bitmap->mddev->bitmap_info.daemon_sleep;
+       mutex_unlock(&mddev->bitmap_info.mutex);
 }
 
 static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap,
@@ -1332,6 +1375,7 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long secto
                    bitmap->events_cleared < bitmap->mddev->events) {
                        bitmap->events_cleared = bitmap->mddev->events;
                        bitmap->need_sync = 1;
+                       sysfs_notify_dirent(bitmap->sysfs_can_clear);
                }
 
                if (!success && ! (*bmc & NEEDED_MASK))
@@ -1470,7 +1514,7 @@ void bitmap_cond_end_sync(struct bitmap *bitmap, sector_t sector)
                return;
        }
        if (time_before(jiffies, (bitmap->last_end_sync
-                                 + bitmap->daemon_sleep * HZ)))
+                                 + bitmap->mddev->bitmap_info.daemon_sleep)))
                return;
        wait_event(bitmap->mddev->recovery_wait,
                   atomic_read(&bitmap->mddev->recovery_active) == 0);
@@ -1522,6 +1566,12 @@ void bitmap_dirty_bits(struct bitmap *bitmap, unsigned long s, unsigned long e)
                sector_t sec = (sector_t)chunk << CHUNK_BLOCK_SHIFT(bitmap);
                bitmap_set_memory_bits(bitmap, sec, 1);
                bitmap_file_set_bit(bitmap, sec);
+               if (sec < bitmap->mddev->recovery_cp)
+                       /* We are asserting that the array is dirty,
+                        * so move the recovery_cp address back so
+                        * that it is obvious that it is dirty
+                        */
+                       bitmap->mddev->recovery_cp = sec;
        }
 }
 
@@ -1531,7 +1581,7 @@ void bitmap_dirty_bits(struct bitmap *bitmap, unsigned long s, unsigned long e)
 void bitmap_flush(mddev_t *mddev)
 {
        struct bitmap *bitmap = mddev->bitmap;
-       int sleep;
+       long sleep;
 
        if (!bitmap) /* there was no bitmap */
                return;
@@ -1539,12 +1589,13 @@ void bitmap_flush(mddev_t *mddev)
        /* run the daemon_work three time to ensure everything is flushed
         * that can be
         */
-       sleep = bitmap->daemon_sleep;
-       bitmap->daemon_sleep = 0;
-       bitmap_daemon_work(bitmap);
-       bitmap_daemon_work(bitmap);
-       bitmap_daemon_work(bitmap);
-       bitmap->daemon_sleep = sleep;
+       sleep = mddev->bitmap_info.daemon_sleep * 2;
+       bitmap->daemon_lastrun -= sleep;
+       bitmap_daemon_work(mddev);
+       bitmap->daemon_lastrun -= sleep;
+       bitmap_daemon_work(mddev);
+       bitmap->daemon_lastrun -= sleep;
+       bitmap_daemon_work(mddev);
        bitmap_update_sb(bitmap);
 }
 
@@ -1574,6 +1625,7 @@ static void bitmap_free(struct bitmap *bitmap)
        kfree(bp);
        kfree(bitmap);
 }
+
 void bitmap_destroy(mddev_t *mddev)
 {
        struct bitmap *bitmap = mddev->bitmap;
@@ -1581,10 +1633,15 @@ void bitmap_destroy(mddev_t *mddev)
        if (!bitmap) /* there was no bitmap */
                return;
 
+       mutex_lock(&mddev->bitmap_info.mutex);
        mddev->bitmap = NULL; /* disconnect from the md device */
+       mutex_unlock(&mddev->bitmap_info.mutex);
        if (mddev->thread)
                mddev->thread->timeout = MAX_SCHEDULE_TIMEOUT;
 
+       if (bitmap->sysfs_can_clear)
+               sysfs_put(bitmap->sysfs_can_clear);
+
        bitmap_free(bitmap);
 }
 
@@ -1598,16 +1655,17 @@ int bitmap_create(mddev_t *mddev)
        sector_t blocks = mddev->resync_max_sectors;
        unsigned long chunks;
        unsigned long pages;
-       struct file *file = mddev->bitmap_file;
+       struct file *file = mddev->bitmap_info.file;
        int err;
        sector_t start;
+       struct sysfs_dirent *bm;
 
        BUILD_BUG_ON(sizeof(bitmap_super_t) != 256);
 
-       if (!file && !mddev->bitmap_offset) /* bitmap disabled, nothing to do */
+       if (!file && !mddev->bitmap_info.offset) /* bitmap disabled, nothing to do */
                return 0;
 
-       BUG_ON(file && mddev->bitmap_offset);
+       BUG_ON(file && mddev->bitmap_info.offset);
 
        bitmap = kzalloc(sizeof(*bitmap), GFP_KERNEL);
        if (!bitmap)
@@ -1620,8 +1678,14 @@ int bitmap_create(mddev_t *mddev)
 
        bitmap->mddev = mddev;
 
+       bm = sysfs_get_dirent(mddev->kobj.sd, "bitmap");
+       if (bm) {
+               bitmap->sysfs_can_clear = sysfs_get_dirent(bm, "can_clear");
+               sysfs_put(bm);
+       } else
+               bitmap->sysfs_can_clear = NULL;
+
        bitmap->file = file;
-       bitmap->offset = mddev->bitmap_offset;
        if (file) {
                get_file(file);
                /* As future accesses to this file will use bmap,
@@ -1630,12 +1694,22 @@ int bitmap_create(mddev_t *mddev)
                 */
                vfs_fsync(file, file->f_dentry, 1);
        }
-       /* read superblock from bitmap file (this sets bitmap->chunksize) */
-       err = bitmap_read_sb(bitmap);
+       /* read superblock from bitmap file (this sets mddev->bitmap_info.chunksize) */
+       if (!mddev->bitmap_info.external)
+               err = bitmap_read_sb(bitmap);
+       else {
+               err = 0;
+               if (mddev->bitmap_info.chunksize == 0 ||
+                   mddev->bitmap_info.daemon_sleep == 0)
+                       /* chunksize and time_base need to be
+                        * set first. */
+                       err = -EINVAL;
+       }
        if (err)
                goto error;
 
-       bitmap->chunkshift = ffz(~bitmap->chunksize);
+       bitmap->daemon_lastrun = jiffies;
+       bitmap->chunkshift = ffz(~mddev->bitmap_info.chunksize);
 
        /* now that chunksize and chunkshift are set, we can use these macros */
        chunks = (blocks + CHUNK_BLOCK_RATIO(bitmap) - 1) >>
@@ -1677,7 +1751,8 @@ int bitmap_create(mddev_t *mddev)
 
        mddev->bitmap = bitmap;
 
-       mddev->thread->timeout = bitmap->daemon_sleep * HZ;
+       mddev->thread->timeout = mddev->bitmap_info.daemon_sleep;
+       md_wakeup_thread(mddev->thread);
 
        bitmap_update_sb(bitmap);
 
@@ -1688,6 +1763,264 @@ int bitmap_create(mddev_t *mddev)
        return err;
 }
 
+static ssize_t
+location_show(mddev_t *mddev, char *page)
+{
+       ssize_t len;
+       if (mddev->bitmap_info.file) {
+               len = sprintf(page, "file");
+       } else if (mddev->bitmap_info.offset) {
+               len = sprintf(page, "%+lld", (long long)mddev->bitmap_info.offset);
+       } else
+               len = sprintf(page, "none");
+       len += sprintf(page+len, "\n");
+       return len;
+}
+
+static ssize_t
+location_store(mddev_t *mddev, const char *buf, size_t len)
+{
+
+       if (mddev->pers) {
+               if (!mddev->pers->quiesce)
+                       return -EBUSY;
+               if (mddev->recovery || mddev->sync_thread)
+                       return -EBUSY;
+       }
+
+       if (mddev->bitmap || mddev->bitmap_info.file ||
+           mddev->bitmap_info.offset) {
+               /* bitmap already configured.  Only option is to clear it */
+               if (strncmp(buf, "none", 4) != 0)
+                       return -EBUSY;
+               if (mddev->pers) {
+                       mddev->pers->quiesce(mddev, 1);
+                       bitmap_destroy(mddev);
+                       mddev->pers->quiesce(mddev, 0);
+               }
+               mddev->bitmap_info.offset = 0;
+               if (mddev->bitmap_info.file) {
+                       struct file *f = mddev->bitmap_info.file;
+                       mddev->bitmap_info.file = NULL;
+                       restore_bitmap_write_access(f);
+                       fput(f);
+               }
+       } else {
+               /* No bitmap, OK to set a location */
+               long long offset;
+               if (strncmp(buf, "none", 4) == 0)
+                       /* nothing to be done */;
+               else if (strncmp(buf, "file:", 5) == 0) {
+                       /* Not supported yet */
+                       return -EINVAL;
+               } else {
+                       int rv;
+                       if (buf[0] == '+')
+                               rv = strict_strtoll(buf+1, 10, &offset);
+                       else
+                               rv = strict_strtoll(buf, 10, &offset);
+                       if (rv)
+                               return rv;
+                       if (offset == 0)
+                               return -EINVAL;
+                       if (mddev->bitmap_info.external == 0 &&
+                           mddev->major_version == 0 &&
+                           offset != mddev->bitmap_info.default_offset)
+                               return -EINVAL;
+                       mddev->bitmap_info.offset = offset;
+                       if (mddev->pers) {
+                               mddev->pers->quiesce(mddev, 1);
+                               rv = bitmap_create(mddev);
+                               if (rv) {
+                                       bitmap_destroy(mddev);
+                                       mddev->bitmap_info.offset = 0;
+                               }
+                               mddev->pers->quiesce(mddev, 0);
+                               if (rv)
+                                       return rv;
+                       }
+               }
+       }
+       if (!mddev->external) {
+               /* Ensure new bitmap info is stored in
+                * metadata promptly.
+                */
+               set_bit(MD_CHANGE_DEVS, &mddev->flags);
+               md_wakeup_thread(mddev->thread);
+       }
+       return len;
+}
+
+static struct md_sysfs_entry bitmap_location =
+__ATTR(location, S_IRUGO|S_IWUSR, location_show, location_store);
+
+static ssize_t
+timeout_show(mddev_t *mddev, char *page)
+{
+       ssize_t len;
+       unsigned long secs = mddev->bitmap_info.daemon_sleep / HZ;
+       unsigned long jifs = mddev->bitmap_info.daemon_sleep % HZ;
+       
+       len = sprintf(page, "%lu", secs);
+       if (jifs)
+               len += sprintf(page+len, ".%03u", jiffies_to_msecs(jifs));
+       len += sprintf(page+len, "\n");
+       return len;
+}
+
+static ssize_t
+timeout_store(mddev_t *mddev, const char *buf, size_t len)
+{
+       /* timeout can be set at any time */
+       unsigned long timeout;
+       int rv = strict_strtoul_scaled(buf, &timeout, 4);
+       if (rv)
+               return rv;
+
+       /* just to make sure we don't overflow... */
+       if (timeout >= LONG_MAX / HZ)
+               return -EINVAL;
+
+       timeout = timeout * HZ / 10000;
+
+       if (timeout >= MAX_SCHEDULE_TIMEOUT)
+               timeout = MAX_SCHEDULE_TIMEOUT-1;
+       if (timeout < 1)
+               timeout = 1;
+       mddev->bitmap_info.daemon_sleep = timeout;
+       if (mddev->thread) {
+               /* if thread->timeout is MAX_SCHEDULE_TIMEOUT, then
+                * the bitmap is all clean and we don't need to
+                * adjust the timeout right now
+                */
+               if (mddev->thread->timeout < MAX_SCHEDULE_TIMEOUT) {
+                       mddev->thread->timeout = timeout;
+                       md_wakeup_thread(mddev->thread);
+               }
+       }
+       return len;
+}
+
+static struct md_sysfs_entry bitmap_timeout =
+__ATTR(time_base, S_IRUGO|S_IWUSR, timeout_show, timeout_store);
+
+static ssize_t
+backlog_show(mddev_t *mddev, char *page)
+{
+       return sprintf(page, "%lu\n", mddev->bitmap_info.max_write_behind);
+}
+
+static ssize_t
+backlog_store(mddev_t *mddev, const char *buf, size_t len)
+{
+       unsigned long backlog;
+       int rv = strict_strtoul(buf, 10, &backlog);
+       if (rv)
+               return rv;
+       if (backlog > COUNTER_MAX)
+               return -EINVAL;
+       mddev->bitmap_info.max_write_behind = backlog;
+       return len;
+}
+
+static struct md_sysfs_entry bitmap_backlog =
+__ATTR(backlog, S_IRUGO|S_IWUSR, backlog_show, backlog_store);
+
+static ssize_t
+chunksize_show(mddev_t *mddev, char *page)
+{
+       return sprintf(page, "%lu\n", mddev->bitmap_info.chunksize);
+}
+
+static ssize_t
+chunksize_store(mddev_t *mddev, const char *buf, size_t len)
+{
+       /* Can only be changed when no bitmap is active */
+       int rv;
+       unsigned long csize;
+       if (mddev->bitmap)
+               return -EBUSY;
+       rv = strict_strtoul(buf, 10, &csize);
+       if (rv)
+               return rv;
+       if (csize < 512 ||
+           !is_power_of_2(csize))
+               return -EINVAL;
+       mddev->bitmap_info.chunksize = csize;
+       return len;
+}
+
+static struct md_sysfs_entry bitmap_chunksize =
+__ATTR(chunksize, S_IRUGO|S_IWUSR, chunksize_show, chunksize_store);
+
+static ssize_t metadata_show(mddev_t *mddev, char *page)
+{
+       return sprintf(page, "%s\n", (mddev->bitmap_info.external
+                                     ? "external" : "internal"));
+}
+
+static ssize_t metadata_store(mddev_t *mddev, const char *buf, size_t len)
+{
+       if (mddev->bitmap ||
+           mddev->bitmap_info.file ||
+           mddev->bitmap_info.offset)
+               return -EBUSY;
+       if (strncmp(buf, "external", 8) == 0)
+               mddev->bitmap_info.external = 1;
+       else if (strncmp(buf, "internal", 8) == 0)
+               mddev->bitmap_info.external = 0;
+       else
+               return -EINVAL;
+       return len;
+}
+
+static struct md_sysfs_entry bitmap_metadata =
+__ATTR(metadata, S_IRUGO|S_IWUSR, metadata_show, metadata_store);
+
+static ssize_t can_clear_show(mddev_t *mddev, char *page)
+{
+       int len;
+       if (mddev->bitmap)
+               len = sprintf(page, "%s\n", (mddev->bitmap->need_sync ?
+                                            "false" : "true"));
+       else
+               len = sprintf(page, "\n");
+       return len;
+}
+
+static ssize_t can_clear_store(mddev_t *mddev, const char *buf, size_t len)
+{
+       if (mddev->bitmap == NULL)
+               return -ENOENT;
+       if (strncmp(buf, "false", 5) == 0)
+               mddev->bitmap->need_sync = 1;
+       else if (strncmp(buf, "true", 4) == 0) {
+               if (mddev->degraded)
+                       return -EBUSY;
+               mddev->bitmap->need_sync = 0;
+       } else
+               return -EINVAL;
+       return len;
+}
+
+static struct md_sysfs_entry bitmap_can_clear =
+__ATTR(can_clear, S_IRUGO|S_IWUSR, can_clear_show, can_clear_store);
+
+static struct attribute *md_bitmap_attrs[] = {
+       &bitmap_location.attr,
+       &bitmap_timeout.attr,
+       &bitmap_backlog.attr,
+       &bitmap_chunksize.attr,
+       &bitmap_metadata.attr,
+       &bitmap_can_clear.attr,
+       NULL
+};
+struct attribute_group md_bitmap_group = {
+       .name = "bitmap",
+       .attrs = md_bitmap_attrs,
+};
+
+
 /* the bitmap API -- for raid personalities */
 EXPORT_SYMBOL(bitmap_startwrite);
 EXPORT_SYMBOL(bitmap_endwrite);
index e98900671ca91d7a4f76ae91ac7393f6613bd5ee..cb821d76d1b4ebe7c8ad8aa2e44ab4c10b20f6f2 100644 (file)
@@ -106,7 +106,7 @@ typedef __u16 bitmap_counter_t;
 #define BITMAP_BLOCK_SHIFT 9
 
 /* how many blocks per chunk? (this is variable) */
-#define CHUNK_BLOCK_RATIO(bitmap) ((bitmap)->chunksize >> BITMAP_BLOCK_SHIFT)
+#define CHUNK_BLOCK_RATIO(bitmap) ((bitmap)->mddev->bitmap_info.chunksize >> BITMAP_BLOCK_SHIFT)
 #define CHUNK_BLOCK_SHIFT(bitmap) ((bitmap)->chunkshift - BITMAP_BLOCK_SHIFT)
 #define CHUNK_BLOCK_MASK(bitmap) (CHUNK_BLOCK_RATIO(bitmap) - 1)
 
@@ -118,16 +118,6 @@ typedef __u16 bitmap_counter_t;
                        (CHUNK_BLOCK_SHIFT(bitmap) + PAGE_COUNTER_SHIFT - 1)
 #define PAGEPTR_BLOCK_MASK(bitmap) (PAGEPTR_BLOCK_RATIO(bitmap) - 1)
 
-/*
- * on-disk bitmap:
- *
- * Use one bit per "chunk" (block set). We do the disk I/O on the bitmap
- * file a page at a time. There's a superblock at the start of the file.
- */
-
-/* map chunks (bits) to file pages - offset by the size of the superblock */
-#define CHUNK_BIT_OFFSET(chunk) ((chunk) + (sizeof(bitmap_super_t) << 3))
-
 #endif
 
 /*
@@ -209,7 +199,6 @@ struct bitmap {
        int counter_bits; /* how many bits per block counter */
 
        /* bitmap chunksize -- how much data does each bit represent? */
-       unsigned long chunksize;
        unsigned long chunkshift; /* chunksize = 2^chunkshift (for bitops) */
        unsigned long chunks; /* total number of data chunks for the array */
 
@@ -226,7 +215,6 @@ struct bitmap {
        /* bitmap spinlock */
        spinlock_t lock;
 
-       long offset; /* offset from superblock if file is NULL */
        struct file *file; /* backing disk file */
        struct page *sb_page; /* cached copy of the bitmap file superblock */
        struct page **filemap; /* list of cache pages for the file */
@@ -238,7 +226,6 @@ struct bitmap {
 
        int allclean;
 
-       unsigned long max_write_behind; /* write-behind mode */
        atomic_t behind_writes;
 
        /*
@@ -246,7 +233,6 @@ struct bitmap {
         * file, cleaning up bits and flushing out pages to disk as necessary
         */
        unsigned long daemon_lastrun; /* jiffies of last run */
-       unsigned long daemon_sleep; /* how many seconds between updates? */
        unsigned long last_end_sync; /* when we lasted called end_sync to
                                      * update bitmap with resync progress */
 
@@ -254,6 +240,7 @@ struct bitmap {
        wait_queue_head_t write_wait;
        wait_queue_head_t overflow_wait;
 
+       struct sysfs_dirent *sysfs_can_clear;
 };
 
 /* the bitmap API */
@@ -282,7 +269,7 @@ void bitmap_close_sync(struct bitmap *bitmap);
 void bitmap_cond_end_sync(struct bitmap *bitmap, sector_t sector);
 
 void bitmap_unplug(struct bitmap *bitmap);
-void bitmap_daemon_work(struct bitmap *bitmap);
+void bitmap_daemon_work(mddev_t *mddev);
 #endif
 
 #endif
index 87d88dbb667f2abdb83190b5d1fc1ac3d19cb1ba..713acd02ab39f1cd9662b5238c6e770fcc73c00c 100644 (file)
@@ -360,6 +360,7 @@ static void raid_exit(void)
 module_init(raid_init);
 module_exit(raid_exit);
 MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Fault injection personality for MD");
 MODULE_ALIAS("md-personality-10"); /* faulty */
 MODULE_ALIAS("md-faulty");
 MODULE_ALIAS("md-level--5");
index 1ceceb334d5ebe8f5ce637d29898fc984bfcc797..00435bd206990416c21cad98b549483b123a99c8 100644 (file)
@@ -292,7 +292,7 @@ static int linear_make_request (struct request_queue *q, struct bio *bio)
        int cpu;
 
        if (unlikely(bio_rw_flagged(bio, BIO_RW_BARRIER))) {
-               bio_endio(bio, -EOPNOTSUPP);
+               md_barrier_request(mddev, bio);
                return 0;
        }
 
@@ -383,6 +383,7 @@ static void linear_exit (void)
 module_init(linear_init);
 module_exit(linear_exit);
 MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Linear device concatenation personality for MD");
 MODULE_ALIAS("md-personality-1"); /* LINEAR - deprecated*/
 MODULE_ALIAS("md-linear");
 MODULE_ALIAS("md-level--1");
index 5f154ef1e4befeeef26358d9ae37e424c62cee47..e1f3c1715cca2ae459f0a70d7229128685ee2d70 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/random.h>
 #include <linux/reboot.h>
 #include <linux/file.h>
+#include <linux/compat.h>
 #include <linux/delay.h>
 #include <linux/raid/md_p.h>
 #include <linux/raid/md_u.h>
@@ -67,6 +68,12 @@ static DECLARE_WAIT_QUEUE_HEAD(resync_wait);
 
 #define MD_BUG(x...) { printk("md: bug in file %s, line %d\n", __FILE__, __LINE__); md_print_devices(); }
 
+/*
+ * Default number of read corrections we'll attempt on an rdev
+ * before ejecting it from the array. We divide the read error
+ * count by 2 for every hour elapsed between read errors.
+ */
+#define MD_DEFAULT_MAX_CORRECTED_READ_ERRORS 20
 /*
  * Current RAID-1,4,5 parallel reconstruction 'guaranteed speed limit'
  * is 1000 KB/sec, so the extra system load does not show up that much.
@@ -213,12 +220,12 @@ static int md_make_request(struct request_queue *q, struct bio *bio)
                return 0;
        }
        rcu_read_lock();
-       if (mddev->suspended) {
+       if (mddev->suspended || mddev->barrier) {
                DEFINE_WAIT(__wait);
                for (;;) {
                        prepare_to_wait(&mddev->sb_wait, &__wait,
                                        TASK_UNINTERRUPTIBLE);
-                       if (!mddev->suspended)
+                       if (!mddev->suspended && !mddev->barrier)
                                break;
                        rcu_read_unlock();
                        schedule();
@@ -260,10 +267,110 @@ static void mddev_resume(mddev_t *mddev)
 
 int mddev_congested(mddev_t *mddev, int bits)
 {
+       if (mddev->barrier)
+               return 1;
        return mddev->suspended;
 }
 EXPORT_SYMBOL(mddev_congested);
 
+/*
+ * Generic barrier handling for md
+ */
+
+#define POST_REQUEST_BARRIER ((void*)1)
+
+static void md_end_barrier(struct bio *bio, int err)
+{
+       mdk_rdev_t *rdev = bio->bi_private;
+       mddev_t *mddev = rdev->mddev;
+       if (err == -EOPNOTSUPP && mddev->barrier != POST_REQUEST_BARRIER)
+               set_bit(BIO_EOPNOTSUPP, &mddev->barrier->bi_flags);
+
+       rdev_dec_pending(rdev, mddev);
+
+       if (atomic_dec_and_test(&mddev->flush_pending)) {
+               if (mddev->barrier == POST_REQUEST_BARRIER) {
+                       /* This was a post-request barrier */
+                       mddev->barrier = NULL;
+                       wake_up(&mddev->sb_wait);
+               } else
+                       /* The pre-request barrier has finished */
+                       schedule_work(&mddev->barrier_work);
+       }
+       bio_put(bio);
+}
+
+static void submit_barriers(mddev_t *mddev)
+{
+       mdk_rdev_t *rdev;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(rdev, &mddev->disks, same_set)
+               if (rdev->raid_disk >= 0 &&
+                   !test_bit(Faulty, &rdev->flags)) {
+                       /* Take two references, one is dropped
+                        * when request finishes, one after
+                        * we reclaim rcu_read_lock
+                        */
+                       struct bio *bi;
+                       atomic_inc(&rdev->nr_pending);
+                       atomic_inc(&rdev->nr_pending);
+                       rcu_read_unlock();
+                       bi = bio_alloc(GFP_KERNEL, 0);
+                       bi->bi_end_io = md_end_barrier;
+                       bi->bi_private = rdev;
+                       bi->bi_bdev = rdev->bdev;
+                       atomic_inc(&mddev->flush_pending);
+                       submit_bio(WRITE_BARRIER, bi);
+                       rcu_read_lock();
+                       rdev_dec_pending(rdev, mddev);
+               }
+       rcu_read_unlock();
+}
+
+static void md_submit_barrier(struct work_struct *ws)
+{
+       mddev_t *mddev = container_of(ws, mddev_t, barrier_work);
+       struct bio *bio = mddev->barrier;
+
+       atomic_set(&mddev->flush_pending, 1);
+
+       if (test_bit(BIO_EOPNOTSUPP, &bio->bi_flags))
+               bio_endio(bio, -EOPNOTSUPP);
+       else if (bio->bi_size == 0)
+               /* an empty barrier - all done */
+               bio_endio(bio, 0);
+       else {
+               bio->bi_rw &= ~(1<<BIO_RW_BARRIER);
+               if (mddev->pers->make_request(mddev->queue, bio))
+                       generic_make_request(bio);
+               mddev->barrier = POST_REQUEST_BARRIER;
+               submit_barriers(mddev);
+       }
+       if (atomic_dec_and_test(&mddev->flush_pending)) {
+               mddev->barrier = NULL;
+               wake_up(&mddev->sb_wait);
+       }
+}
+
+void md_barrier_request(mddev_t *mddev, struct bio *bio)
+{
+       spin_lock_irq(&mddev->write_lock);
+       wait_event_lock_irq(mddev->sb_wait,
+                           !mddev->barrier,
+                           mddev->write_lock, /*nothing*/);
+       mddev->barrier = bio;
+       spin_unlock_irq(&mddev->write_lock);
+
+       atomic_set(&mddev->flush_pending, 1);
+       INIT_WORK(&mddev->barrier_work, md_submit_barrier);
+
+       submit_barriers(mddev);
+
+       if (atomic_dec_and_test(&mddev->flush_pending))
+               schedule_work(&mddev->barrier_work);
+}
+EXPORT_SYMBOL(md_barrier_request);
 
 static inline mddev_t *mddev_get(mddev_t *mddev)
 {
@@ -363,6 +470,7 @@ static mddev_t * mddev_find(dev_t unit)
 
        mutex_init(&new->open_mutex);
        mutex_init(&new->reconfig_mutex);
+       mutex_init(&new->bitmap_info.mutex);
        INIT_LIST_HEAD(&new->disks);
        INIT_LIST_HEAD(&new->all_mddevs);
        init_timer(&new->safemode_timer);
@@ -370,6 +478,7 @@ static mddev_t * mddev_find(dev_t unit)
        atomic_set(&new->openers, 0);
        atomic_set(&new->active_io, 0);
        spin_lock_init(&new->write_lock);
+       atomic_set(&new->flush_pending, 0);
        init_waitqueue_head(&new->sb_wait);
        init_waitqueue_head(&new->recovery_wait);
        new->reshape_position = MaxSector;
@@ -748,7 +857,7 @@ struct super_type  {
  */
 int md_check_no_bitmap(mddev_t *mddev)
 {
-       if (!mddev->bitmap_file && !mddev->bitmap_offset)
+       if (!mddev->bitmap_info.file && !mddev->bitmap_info.offset)
                return 0;
        printk(KERN_ERR "%s: bitmaps are not supported for %s\n",
                mdname(mddev), mddev->pers->name);
@@ -876,8 +985,8 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev)
                mddev->raid_disks = sb->raid_disks;
                mddev->dev_sectors = sb->size * 2;
                mddev->events = ev1;
-               mddev->bitmap_offset = 0;
-               mddev->default_bitmap_offset = MD_SB_BYTES >> 9;
+               mddev->bitmap_info.offset = 0;
+               mddev->bitmap_info.default_offset = MD_SB_BYTES >> 9;
 
                if (mddev->minor_version >= 91) {
                        mddev->reshape_position = sb->reshape_position;
@@ -911,8 +1020,9 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev)
                mddev->max_disks = MD_SB_DISKS;
 
                if (sb->state & (1<<MD_SB_BITMAP_PRESENT) &&
-                   mddev->bitmap_file == NULL)
-                       mddev->bitmap_offset = mddev->default_bitmap_offset;
+                   mddev->bitmap_info.file == NULL)
+                       mddev->bitmap_info.offset =
+                               mddev->bitmap_info.default_offset;
 
        } else if (mddev->pers == NULL) {
                /* Insist on good event counter while assembling */
@@ -1029,7 +1139,7 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev)
        sb->layout = mddev->layout;
        sb->chunk_size = mddev->chunk_sectors << 9;
 
-       if (mddev->bitmap && mddev->bitmap_file == NULL)
+       if (mddev->bitmap && mddev->bitmap_info.file == NULL)
                sb->state |= (1<<MD_SB_BITMAP_PRESENT);
 
        sb->disks[0].state = (1<<MD_DISK_REMOVED);
@@ -1107,7 +1217,7 @@ super_90_rdev_size_change(mdk_rdev_t *rdev, sector_t num_sectors)
 {
        if (num_sectors && num_sectors < rdev->mddev->dev_sectors)
                return 0; /* component must fit device */
-       if (rdev->mddev->bitmap_offset)
+       if (rdev->mddev->bitmap_info.offset)
                return 0; /* can't move bitmap */
        rdev->sb_start = calc_dev_sboffset(rdev->bdev);
        if (!num_sectors || num_sectors > rdev->sb_start)
@@ -1286,8 +1396,8 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev)
                mddev->raid_disks = le32_to_cpu(sb->raid_disks);
                mddev->dev_sectors = le64_to_cpu(sb->size);
                mddev->events = ev1;
-               mddev->bitmap_offset = 0;
-               mddev->default_bitmap_offset = 1024 >> 9;
+               mddev->bitmap_info.offset = 0;
+               mddev->bitmap_info.default_offset = 1024 >> 9;
                
                mddev->recovery_cp = le64_to_cpu(sb->resync_offset);
                memcpy(mddev->uuid, sb->set_uuid, 16);
@@ -1295,8 +1405,9 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev)
                mddev->max_disks =  (4096-256)/2;
 
                if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_BITMAP_OFFSET) &&
-                   mddev->bitmap_file == NULL )
-                       mddev->bitmap_offset = (__s32)le32_to_cpu(sb->bitmap_offset);
+                   mddev->bitmap_info.file == NULL )
+                       mddev->bitmap_info.offset =
+                               (__s32)le32_to_cpu(sb->bitmap_offset);
 
                if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_RESHAPE_ACTIVE)) {
                        mddev->reshape_position = le64_to_cpu(sb->reshape_position);
@@ -1390,19 +1501,17 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev)
        sb->level = cpu_to_le32(mddev->level);
        sb->layout = cpu_to_le32(mddev->layout);
 
-       if (mddev->bitmap && mddev->bitmap_file == NULL) {
-               sb->bitmap_offset = cpu_to_le32((__u32)mddev->bitmap_offset);
+       if (mddev->bitmap && mddev->bitmap_info.file == NULL) {
+               sb->bitmap_offset = cpu_to_le32((__u32)mddev->bitmap_info.offset);
                sb->feature_map = cpu_to_le32(MD_FEATURE_BITMAP_OFFSET);
        }
 
        if (rdev->raid_disk >= 0 &&
            !test_bit(In_sync, &rdev->flags)) {
-               if (rdev->recovery_offset > 0) {
-                       sb->feature_map |=
-                               cpu_to_le32(MD_FEATURE_RECOVERY_OFFSET);
-                       sb->recovery_offset =
-                               cpu_to_le64(rdev->recovery_offset);
-               }
+               sb->feature_map |=
+                       cpu_to_le32(MD_FEATURE_RECOVERY_OFFSET);
+               sb->recovery_offset =
+                       cpu_to_le64(rdev->recovery_offset);
        }
 
        if (mddev->reshape_position != MaxSector) {
@@ -1436,7 +1545,7 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev)
                        sb->dev_roles[i] = cpu_to_le16(0xfffe);
                else if (test_bit(In_sync, &rdev2->flags))
                        sb->dev_roles[i] = cpu_to_le16(rdev2->raid_disk);
-               else if (rdev2->raid_disk >= 0 && rdev2->recovery_offset > 0)
+               else if (rdev2->raid_disk >= 0)
                        sb->dev_roles[i] = cpu_to_le16(rdev2->raid_disk);
                else
                        sb->dev_roles[i] = cpu_to_le16(0xffff);
@@ -1458,7 +1567,7 @@ super_1_rdev_size_change(mdk_rdev_t *rdev, sector_t num_sectors)
                max_sectors -= rdev->data_offset;
                if (!num_sectors || num_sectors > max_sectors)
                        num_sectors = max_sectors;
-       } else if (rdev->mddev->bitmap_offset) {
+       } else if (rdev->mddev->bitmap_info.offset) {
                /* minor version 0 with bitmap we can't move */
                return 0;
        } else {
@@ -2442,12 +2551,49 @@ rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len)
 static struct rdev_sysfs_entry rdev_size =
 __ATTR(size, S_IRUGO|S_IWUSR, rdev_size_show, rdev_size_store);
 
+
+static ssize_t recovery_start_show(mdk_rdev_t *rdev, char *page)
+{
+       unsigned long long recovery_start = rdev->recovery_offset;
+
+       if (test_bit(In_sync, &rdev->flags) ||
+           recovery_start == MaxSector)
+               return sprintf(page, "none\n");
+
+       return sprintf(page, "%llu\n", recovery_start);
+}
+
+static ssize_t recovery_start_store(mdk_rdev_t *rdev, const char *buf, size_t len)
+{
+       unsigned long long recovery_start;
+
+       if (cmd_match(buf, "none"))
+               recovery_start = MaxSector;
+       else if (strict_strtoull(buf, 10, &recovery_start))
+               return -EINVAL;
+
+       if (rdev->mddev->pers &&
+           rdev->raid_disk >= 0)
+               return -EBUSY;
+
+       rdev->recovery_offset = recovery_start;
+       if (recovery_start == MaxSector)
+               set_bit(In_sync, &rdev->flags);
+       else
+               clear_bit(In_sync, &rdev->flags);
+       return len;
+}
+
+static struct rdev_sysfs_entry rdev_recovery_start =
+__ATTR(recovery_start, S_IRUGO|S_IWUSR, recovery_start_show, recovery_start_store);
+
 static struct attribute *rdev_default_attrs[] = {
        &rdev_state.attr,
        &rdev_errors.attr,
        &rdev_slot.attr,
        &rdev_offset.attr,
        &rdev_size.attr,
+       &rdev_recovery_start.attr,
        NULL,
 };
 static ssize_t
@@ -2549,6 +2695,8 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi
        rdev->flags = 0;
        rdev->data_offset = 0;
        rdev->sb_events = 0;
+       rdev->last_read_error.tv_sec  = 0;
+       rdev->last_read_error.tv_nsec = 0;
        atomic_set(&rdev->nr_pending, 0);
        atomic_set(&rdev->read_errors, 0);
        atomic_set(&rdev->corrected_errors, 0);
@@ -2659,6 +2807,47 @@ static void analyze_sbs(mddev_t * mddev)
        }
 }
 
+/* Read a fixed-point number.
+ * Numbers in sysfs attributes should be in "standard" units where
+ * possible, so time should be in seconds.
+ * However we internally use a a much smaller unit such as 
+ * milliseconds or jiffies.
+ * This function takes a decimal number with a possible fractional
+ * component, and produces an integer which is the result of
+ * multiplying that number by 10^'scale'.
+ * all without any floating-point arithmetic.
+ */
+int strict_strtoul_scaled(const char *cp, unsigned long *res, int scale)
+{
+       unsigned long result = 0;
+       long decimals = -1;
+       while (isdigit(*cp) || (*cp == '.' && decimals < 0)) {
+               if (*cp == '.')
+                       decimals = 0;
+               else if (decimals < scale) {
+                       unsigned int value;
+                       value = *cp - '0';
+                       result = result * 10 + value;
+                       if (decimals >= 0)
+                               decimals++;
+               }
+               cp++;
+       }
+       if (*cp == '\n')
+               cp++;
+       if (*cp)
+               return -EINVAL;
+       if (decimals < 0)
+               decimals = 0;
+       while (decimals < scale) {
+               result *= 10;
+               decimals ++;
+       }
+       *res = result;
+       return 0;
+}
+
+
 static void md_safemode_timeout(unsigned long data);
 
 static ssize_t
@@ -2670,31 +2859,10 @@ safe_delay_show(mddev_t *mddev, char *page)
 static ssize_t
 safe_delay_store(mddev_t *mddev, const char *cbuf, size_t len)
 {
-       int scale=1;
-       int dot=0;
-       int i;
        unsigned long msec;
-       char buf[30];
 
-       /* remove a period, and count digits after it */
-       if (len >= sizeof(buf))
-               return -EINVAL;
-       strlcpy(buf, cbuf, sizeof(buf));
-       for (i=0; i<len; i++) {
-               if (dot) {
-                       if (isdigit(buf[i])) {
-                               buf[i-1] = buf[i];
-                               scale *= 10;
-                       }
-                       buf[i] = 0;
-               } else if (buf[i] == '.') {
-                       dot=1;
-                       buf[i] = 0;
-               }
-       }
-       if (strict_strtoul(buf, 10, &msec) < 0)
+       if (strict_strtoul_scaled(cbuf, &msec, 3) < 0)
                return -EINVAL;
-       msec = (msec * 1000) / scale;
        if (msec == 0)
                mddev->safemode_delay = 0;
        else {
@@ -2970,7 +3138,9 @@ resync_start_store(mddev_t *mddev, const char *buf, size_t len)
 
        if (mddev->pers)
                return -EBUSY;
-       if (!*buf || (*e && *e != '\n'))
+       if (cmd_match(buf, "none"))
+               n = MaxSector;
+       else if (!*buf || (*e && *e != '\n'))
                return -EINVAL;
 
        mddev->recovery_cp = n;
@@ -3165,6 +3335,29 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len)
 static struct md_sysfs_entry md_array_state =
 __ATTR(array_state, S_IRUGO|S_IWUSR, array_state_show, array_state_store);
 
+static ssize_t
+max_corrected_read_errors_show(mddev_t *mddev, char *page) {
+       return sprintf(page, "%d\n",
+                      atomic_read(&mddev->max_corr_read_errors));
+}
+
+static ssize_t
+max_corrected_read_errors_store(mddev_t *mddev, const char *buf, size_t len)
+{
+       char *e;
+       unsigned long n = simple_strtoul(buf, &e, 10);
+
+       if (*buf && (*e == 0 || *e == '\n')) {
+               atomic_set(&mddev->max_corr_read_errors, n);
+               return len;
+       }
+       return -EINVAL;
+}
+
+static struct md_sysfs_entry max_corr_read_errors =
+__ATTR(max_read_errors, S_IRUGO|S_IWUSR, max_corrected_read_errors_show,
+       max_corrected_read_errors_store);
+
 static ssize_t
 null_show(mddev_t *mddev, char *page)
 {
@@ -3790,6 +3983,7 @@ static struct attribute *md_default_attrs[] = {
        &md_array_state.attr,
        &md_reshape_position.attr,
        &md_array_size.attr,
+       &max_corr_read_errors.attr,
        NULL,
 };
 
@@ -3894,6 +4088,7 @@ static void mddev_delayed_delete(struct work_struct *ws)
                mddev->sysfs_action = NULL;
                mddev->private = NULL;
        }
+       sysfs_remove_group(&mddev->kobj, &md_bitmap_group);
        kobject_del(&mddev->kobj);
        kobject_put(&mddev->kobj);
 }
@@ -3985,6 +4180,8 @@ static int md_alloc(dev_t dev, char *name)
                       disk->disk_name);
                error = 0;
        }
+       if (sysfs_create_group(&mddev->kobj, &md_bitmap_group))
+               printk(KERN_DEBUG "pointless warning\n");
  abort:
        mutex_unlock(&disks_mutex);
        if (!error) {
@@ -4206,6 +4403,8 @@ static int do_md_run(mddev_t * mddev)
                mddev->ro = 0;
 
        atomic_set(&mddev->writes_pending,0);
+       atomic_set(&mddev->max_corr_read_errors,
+                  MD_DEFAULT_MAX_CORRECTED_READ_ERRORS);
        mddev->safemode = 0;
        mddev->safemode_timer.function = md_safemode_timeout;
        mddev->safemode_timer.data = (unsigned long) mddev;
@@ -4310,7 +4509,7 @@ static int deny_bitmap_write_access(struct file * file)
        return 0;
 }
 
-static void restore_bitmap_write_access(struct file *file)
+void restore_bitmap_write_access(struct file *file)
 {
        struct inode *inode = file->f_mapping->host;
 
@@ -4405,12 +4604,12 @@ out:
                printk(KERN_INFO "md: %s stopped.\n", mdname(mddev));
 
                bitmap_destroy(mddev);
-               if (mddev->bitmap_file) {
-                       restore_bitmap_write_access(mddev->bitmap_file);
-                       fput(mddev->bitmap_file);
-                       mddev->bitmap_file = NULL;
+               if (mddev->bitmap_info.file) {
+                       restore_bitmap_write_access(mddev->bitmap_info.file);
+                       fput(mddev->bitmap_info.file);
+                       mddev->bitmap_info.file = NULL;
                }
-               mddev->bitmap_offset = 0;
+               mddev->bitmap_info.offset = 0;
 
                /* make sure all md_delayed_delete calls have finished */
                flush_scheduled_work();
@@ -4451,6 +4650,11 @@ out:
                mddev->degraded = 0;
                mddev->barriers_work = 0;
                mddev->safemode = 0;
+               mddev->bitmap_info.offset = 0;
+               mddev->bitmap_info.default_offset = 0;
+               mddev->bitmap_info.chunksize = 0;
+               mddev->bitmap_info.daemon_sleep = 0;
+               mddev->bitmap_info.max_write_behind = 0;
                kobject_uevent(&disk_to_dev(mddev->gendisk)->kobj, KOBJ_CHANGE);
                if (mddev->hold_active == UNTIL_STOP)
                        mddev->hold_active = 0;
@@ -4636,7 +4840,7 @@ static int get_array_info(mddev_t * mddev, void __user * arg)
        info.state         = 0;
        if (mddev->in_sync)
                info.state = (1<<MD_SB_CLEAN);
-       if (mddev->bitmap && mddev->bitmap_offset)
+       if (mddev->bitmap && mddev->bitmap_info.offset)
                info.state = (1<<MD_SB_BITMAP_PRESENT);
        info.active_disks  = insync;
        info.working_disks = working;
@@ -4994,23 +5198,23 @@ static int set_bitmap_file(mddev_t *mddev, int fd)
        if (fd >= 0) {
                if (mddev->bitmap)
                        return -EEXIST; /* cannot add when bitmap is present */
-               mddev->bitmap_file = fget(fd);
+               mddev->bitmap_info.file = fget(fd);
 
-               if (mddev->bitmap_file == NULL) {
+               if (mddev->bitmap_info.file == NULL) {
                        printk(KERN_ERR "%s: error: failed to get bitmap file\n",
                               mdname(mddev));
                        return -EBADF;
                }
 
-               err = deny_bitmap_write_access(mddev->bitmap_file);
+               err = deny_bitmap_write_access(mddev->bitmap_info.file);
                if (err) {
                        printk(KERN_ERR "%s: error: bitmap file is already in use\n",
                               mdname(mddev));
-                       fput(mddev->bitmap_file);
-                       mddev->bitmap_file = NULL;
+                       fput(mddev->bitmap_info.file);
+                       mddev->bitmap_info.file = NULL;
                        return err;
                }
-               mddev->bitmap_offset = 0; /* file overrides offset */
+               mddev->bitmap_info.offset = 0; /* file overrides offset */
        } else if (mddev->bitmap == NULL)
                return -ENOENT; /* cannot remove what isn't there */
        err = 0;
@@ -5025,11 +5229,11 @@ static int set_bitmap_file(mddev_t *mddev, int fd)
                mddev->pers->quiesce(mddev, 0);
        }
        if (fd < 0) {
-               if (mddev->bitmap_file) {
-                       restore_bitmap_write_access(mddev->bitmap_file);
-                       fput(mddev->bitmap_file);
+               if (mddev->bitmap_info.file) {
+                       restore_bitmap_write_access(mddev->bitmap_info.file);
+                       fput(mddev->bitmap_info.file);
                }
-               mddev->bitmap_file = NULL;
+               mddev->bitmap_info.file = NULL;
        }
 
        return err;
@@ -5096,8 +5300,8 @@ static int set_array_info(mddev_t * mddev, mdu_array_info_t *info)
                mddev->flags         = 0;
        set_bit(MD_CHANGE_DEVS, &mddev->flags);
 
-       mddev->default_bitmap_offset = MD_SB_BYTES >> 9;
-       mddev->bitmap_offset = 0;
+       mddev->bitmap_info.default_offset = MD_SB_BYTES >> 9;
+       mddev->bitmap_info.offset = 0;
 
        mddev->reshape_position = MaxSector;
 
@@ -5197,7 +5401,7 @@ static int update_array_info(mddev_t *mddev, mdu_array_info_t *info)
        int state = 0;
 
        /* calculate expected state,ignoring low bits */
-       if (mddev->bitmap && mddev->bitmap_offset)
+       if (mddev->bitmap && mddev->bitmap_info.offset)
                state |= (1 << MD_SB_BITMAP_PRESENT);
 
        if (mddev->major_version != info->major_version ||
@@ -5256,9 +5460,10 @@ static int update_array_info(mddev_t *mddev, mdu_array_info_t *info)
                        /* add the bitmap */
                        if (mddev->bitmap)
                                return -EEXIST;
-                       if (mddev->default_bitmap_offset == 0)
+                       if (mddev->bitmap_info.default_offset == 0)
                                return -EINVAL;
-                       mddev->bitmap_offset = mddev->default_bitmap_offset;
+                       mddev->bitmap_info.offset =
+                               mddev->bitmap_info.default_offset;
                        mddev->pers->quiesce(mddev, 1);
                        rv = bitmap_create(mddev);
                        if (rv)
@@ -5273,7 +5478,7 @@ static int update_array_info(mddev_t *mddev, mdu_array_info_t *info)
                        mddev->pers->quiesce(mddev, 1);
                        bitmap_destroy(mddev);
                        mddev->pers->quiesce(mddev, 0);
-                       mddev->bitmap_offset = 0;
+                       mddev->bitmap_info.offset = 0;
                }
        }
        md_update_sb(mddev, 1);
@@ -5524,6 +5729,25 @@ done:
 abort:
        return err;
 }
+#ifdef CONFIG_COMPAT
+static int md_compat_ioctl(struct block_device *bdev, fmode_t mode,
+                   unsigned int cmd, unsigned long arg)
+{
+       switch (cmd) {
+       case HOT_REMOVE_DISK:
+       case HOT_ADD_DISK:
+       case SET_DISK_FAULTY:
+       case SET_BITMAP_FILE:
+               /* These take in integer arg, do not convert */
+               break;
+       default:
+               arg = (unsigned long)compat_ptr(arg);
+               break;
+       }
+
+       return md_ioctl(bdev, mode, cmd, arg);
+}
+#endif /* CONFIG_COMPAT */
 
 static int md_open(struct block_device *bdev, fmode_t mode)
 {
@@ -5589,6 +5813,9 @@ static const struct block_device_operations md_fops =
        .open           = md_open,
        .release        = md_release,
        .ioctl          = md_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = md_compat_ioctl,
+#endif
        .getgeo         = md_getgeo,
        .media_changed  = md_media_changed,
        .revalidate_disk= md_revalidate,
@@ -5982,14 +6209,14 @@ static int md_seq_show(struct seq_file *seq, void *v)
                        unsigned long chunk_kb;
                        unsigned long flags;
                        spin_lock_irqsave(&bitmap->lock, flags);
-                       chunk_kb = bitmap->chunksize >> 10;
+                       chunk_kb = mddev->bitmap_info.chunksize >> 10;
                        seq_printf(seq, "bitmap: %lu/%lu pages [%luKB], "
                                "%lu%s chunk",
                                bitmap->pages - bitmap->missing_pages,
                                bitmap->pages,
                                (bitmap->pages - bitmap->missing_pages)
                                        << (PAGE_SHIFT - 10),
-                               chunk_kb ? chunk_kb : bitmap->chunksize,
+                               chunk_kb ? chunk_kb : mddev->bitmap_info.chunksize,
                                chunk_kb ? "KB" : "B");
                        if (bitmap->file) {
                                seq_printf(seq, ", file: ");
@@ -6338,12 +6565,14 @@ void md_do_sync(mddev_t *mddev)
                /* recovery follows the physical size of devices */
                max_sectors = mddev->dev_sectors;
                j = MaxSector;
-               list_for_each_entry(rdev, &mddev->disks, same_set)
+               rcu_read_lock();
+               list_for_each_entry_rcu(rdev, &mddev->disks, same_set)
                        if (rdev->raid_disk >= 0 &&
                            !test_bit(Faulty, &rdev->flags) &&
                            !test_bit(In_sync, &rdev->flags) &&
                            rdev->recovery_offset < j)
                                j = rdev->recovery_offset;
+               rcu_read_unlock();
        }
 
        printk(KERN_INFO "md: %s of RAID array %s\n", desc, mdname(mddev));
@@ -6380,6 +6609,7 @@ void md_do_sync(mddev_t *mddev)
                       desc, mdname(mddev));
                mddev->curr_resync = j;
        }
+       mddev->curr_resync_completed = mddev->curr_resync;
 
        while (j < max_sectors) {
                sector_t sectors;
@@ -6512,22 +6742,29 @@ void md_do_sync(mddev_t *mddev)
                } else {
                        if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery))
                                mddev->curr_resync = MaxSector;
-                       list_for_each_entry(rdev, &mddev->disks, same_set)
+                       rcu_read_lock();
+                       list_for_each_entry_rcu(rdev, &mddev->disks, same_set)
                                if (rdev->raid_disk >= 0 &&
                                    !test_bit(Faulty, &rdev->flags) &&
                                    !test_bit(In_sync, &rdev->flags) &&
                                    rdev->recovery_offset < mddev->curr_resync)
                                        rdev->recovery_offset = mddev->curr_resync;
+                       rcu_read_unlock();
                }
        }
        set_bit(MD_CHANGE_DEVS, &mddev->flags);
 
  skip:
+       if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) {
+               /* We completed so min/max setting can be forgotten if used. */
+               if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
+                       mddev->resync_min = 0;
+               mddev->resync_max = MaxSector;
+       } else if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
+               mddev->resync_min = mddev->curr_resync_completed;
        mddev->curr_resync = 0;
-       mddev->curr_resync_completed = 0;
        if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery))
-               /* We completed so max setting can be forgotten. */
-               mddev->resync_max = MaxSector;
+               mddev->curr_resync_completed = 0;
        sysfs_notify(&mddev->kobj, NULL, "sync_completed");
        wake_up(&resync_wait);
        set_bit(MD_RECOVERY_DONE, &mddev->recovery);
@@ -6590,6 +6827,7 @@ static int remove_and_add_spares(mddev_t *mddev)
                                                       nm, mdname(mddev));
                                        spares++;
                                        md_new_event(mddev);
+                                       set_bit(MD_CHANGE_DEVS, &mddev->flags);
                                } else
                                        break;
                        }
@@ -6625,7 +6863,7 @@ void md_check_recovery(mddev_t *mddev)
 
 
        if (mddev->bitmap)
-               bitmap_daemon_work(mddev->bitmap);
+               bitmap_daemon_work(mddev);
 
        if (mddev->ro)
                return;
@@ -6995,5 +7233,6 @@ EXPORT_SYMBOL(md_unregister_thread);
 EXPORT_SYMBOL(md_wakeup_thread);
 EXPORT_SYMBOL(md_check_recovery);
 MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MD RAID framework");
 MODULE_ALIAS("md");
 MODULE_ALIAS_BLOCKDEV_MAJOR(MD_MAJOR);
index f184b69ef337514d460d669ffc4309a7d5dcc515..8e4c75c00d4628f76ca32e0aaab243e3aea70d4c 100644 (file)
@@ -97,6 +97,9 @@ struct mdk_rdev_s
        atomic_t        read_errors;    /* number of consecutive read errors that
                                         * we have tried to ignore.
                                         */
+       struct timespec last_read_error;        /* monotonic time since our
+                                                * last read error
+                                                */
        atomic_t        corrected_errors; /* number of corrected read errors,
                                           * for reporting to userspace and storing
                                           * in superblock.
@@ -280,17 +283,38 @@ struct mddev_s
        unsigned int                    max_write_behind; /* 0 = sync */
 
        struct bitmap                   *bitmap; /* the bitmap for the device */
-       struct file                     *bitmap_file; /* the bitmap file */
-       long                            bitmap_offset; /* offset from superblock of
-                                                       * start of bitmap. May be
-                                                       * negative, but not '0'
-                                                       */
-       long                            default_bitmap_offset; /* this is the offset to use when
-                                                               * hot-adding a bitmap.  It should
-                                                               * eventually be settable by sysfs.
-                                                               */
-
+       struct {
+               struct file             *file; /* the bitmap file */
+               loff_t                  offset; /* offset from superblock of
+                                                * start of bitmap. May be
+                                                * negative, but not '0'
+                                                * For external metadata, offset
+                                                * from start of device. 
+                                                */
+               loff_t                  default_offset; /* this is the offset to use when
+                                                        * hot-adding a bitmap.  It should
+                                                        * eventually be settable by sysfs.
+                                                        */
+               struct mutex            mutex;
+               unsigned long           chunksize;
+               unsigned long           daemon_sleep; /* how many seconds between updates? */
+               unsigned long           max_write_behind; /* write-behind mode */
+               int                     external;
+       } bitmap_info;
+
+       atomic_t                        max_corr_read_errors; /* max read retries */
        struct list_head                all_mddevs;
+
+       /* Generic barrier handling.
+        * If there is a pending barrier request, all other
+        * writes are blocked while the devices are flushed.
+        * The last to finish a flush schedules a worker to
+        * submit the barrier request (without the barrier flag),
+        * then submit more flush requests.
+        */
+       struct bio *barrier;
+       atomic_t flush_pending;
+       struct work_struct barrier_work;
 };
 
 
@@ -353,7 +377,7 @@ struct md_sysfs_entry {
        ssize_t (*show)(mddev_t *, char *);
        ssize_t (*store)(mddev_t *, const char *, size_t);
 };
-
+extern struct attribute_group md_bitmap_group;
 
 static inline char * mdname (mddev_t * mddev)
 {
@@ -431,6 +455,7 @@ extern void md_done_sync(mddev_t *mddev, int blocks, int ok);
 extern void md_error(mddev_t *mddev, mdk_rdev_t *rdev);
 
 extern int mddev_congested(mddev_t *mddev, int bits);
+extern void md_barrier_request(mddev_t *mddev, struct bio *bio);
 extern void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev,
                           sector_t sector, int size, struct page *page);
 extern void md_super_wait(mddev_t *mddev);
@@ -443,6 +468,8 @@ extern void md_wait_for_blocked_rdev(mdk_rdev_t *rdev, mddev_t *mddev);
 extern void md_set_array_sectors(mddev_t *mddev, sector_t array_sectors);
 extern int md_check_no_bitmap(mddev_t *mddev);
 extern int md_integrity_register(mddev_t *mddev);
-void md_integrity_add_rdev(mdk_rdev_t *rdev, mddev_t *mddev);
+extern void md_integrity_add_rdev(mdk_rdev_t *rdev, mddev_t *mddev);
+extern int strict_strtoul_scaled(const char *cp, unsigned long *res, int scale);
+extern void restore_bitmap_write_access(struct file *file);
 
 #endif /* _MD_MD_H */
index ee7646f974a07165bd368deb3a18f6390e5553dc..32a662fc55c95d5f08de09362f85d0d6ab0917e3 100644 (file)
@@ -145,7 +145,7 @@ static int multipath_make_request (struct request_queue *q, struct bio * bio)
        int cpu;
 
        if (unlikely(bio_rw_flagged(bio, BIO_RW_BARRIER))) {
-               bio_endio(bio, -EOPNOTSUPP);
+               md_barrier_request(mddev, bio);
                return 0;
        }
 
@@ -581,6 +581,7 @@ static void __exit multipath_exit (void)
 module_init(multipath_init);
 module_exit(multipath_exit);
 MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("simple multi-path personality for MD");
 MODULE_ALIAS("md-personality-7"); /* MULTIPATH */
 MODULE_ALIAS("md-multipath");
 MODULE_ALIAS("md-level--4");
index d3a4ce06015a300e9d4df5e95ee63669613db17e..77605cdceaf179ce1a5ce15d9bf50d4239efb91e 100644 (file)
@@ -453,7 +453,7 @@ static int raid0_make_request(struct request_queue *q, struct bio *bio)
        int cpu;
 
        if (unlikely(bio_rw_flagged(bio, BIO_RW_BARRIER))) {
-               bio_endio(bio, -EOPNOTSUPP);
+               md_barrier_request(mddev, bio);
                return 0;
        }
 
@@ -567,6 +567,7 @@ static void raid0_exit (void)
 module_init(raid0_init);
 module_exit(raid0_exit);
 MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("RAID0 (striping) personality for MD");
 MODULE_ALIAS("md-personality-2"); /* RAID0 */
 MODULE_ALIAS("md-raid0");
 MODULE_ALIAS("md-level-0");
index e07ce2e033a95c48ba2c9a78c519640743220e2d..859bd3ffe4351bad9204aa04e906e751a788c64a 100644 (file)
@@ -677,6 +677,7 @@ static void raise_barrier(conf_t *conf)
 static void lower_barrier(conf_t *conf)
 {
        unsigned long flags;
+       BUG_ON(conf->barrier <= 0);
        spin_lock_irqsave(&conf->resync_lock, flags);
        conf->barrier--;
        spin_unlock_irqrestore(&conf->resync_lock, flags);
@@ -801,6 +802,25 @@ static int make_request(struct request_queue *q, struct bio * bio)
 
        md_write_start(mddev, bio); /* wait on superblock update early */
 
+       if (bio_data_dir(bio) == WRITE &&
+           bio->bi_sector + bio->bi_size/512 > mddev->suspend_lo &&
+           bio->bi_sector < mddev->suspend_hi) {
+               /* As the suspend_* range is controlled by
+                * userspace, we want an interruptible
+                * wait.
+                */
+               DEFINE_WAIT(w);
+               for (;;) {
+                       flush_signals(current);
+                       prepare_to_wait(&conf->wait_barrier,
+                                       &w, TASK_INTERRUPTIBLE);
+                       if (bio->bi_sector + bio->bi_size/512 <= mddev->suspend_lo ||
+                           bio->bi_sector >= mddev->suspend_hi)
+                               break;
+                       schedule();
+               }
+               finish_wait(&conf->wait_barrier, &w);
+       }
        if (unlikely(!mddev->barriers_work &&
                     bio_rw_flagged(bio, BIO_RW_BARRIER))) {
                if (rw == WRITE)
@@ -923,7 +943,8 @@ static int make_request(struct request_queue *q, struct bio * bio)
 
        /* do behind I/O ? */
        if (bitmap &&
-           atomic_read(&bitmap->behind_writes) < bitmap->max_write_behind &&
+           (atomic_read(&bitmap->behind_writes)
+            < mddev->bitmap_info.max_write_behind) &&
            (behind_pages = alloc_behind_pages(bio)) != NULL)
                set_bit(R1BIO_BehindIO, &r1_bio->state);
 
@@ -1941,74 +1962,48 @@ static sector_t raid1_size(mddev_t *mddev, sector_t sectors, int raid_disks)
        return mddev->dev_sectors;
 }
 
-static int run(mddev_t *mddev)
+static conf_t *setup_conf(mddev_t *mddev)
 {
        conf_t *conf;
-       int i, j, disk_idx;
+       int i;
        mirror_info_t *disk;
        mdk_rdev_t *rdev;
+       int err = -ENOMEM;
 
-       if (mddev->level != 1) {
-               printk("raid1: %s: raid level not set to mirroring (%d)\n",
-                      mdname(mddev), mddev->level);
-               goto out;
-       }
-       if (mddev->reshape_position != MaxSector) {
-               printk("raid1: %s: reshape_position set but not supported\n",
-                      mdname(mddev));
-               goto out;
-       }
-       /*
-        * copy the already verified devices into our private RAID1
-        * bookkeeping area. [whatever we allocate in run(),
-        * should be freed in stop()]
-        */
        conf = kzalloc(sizeof(conf_t), GFP_KERNEL);
-       mddev->private = conf;
        if (!conf)
-               goto out_no_mem;
+               goto abort;
 
        conf->mirrors = kzalloc(sizeof(struct mirror_info)*mddev->raid_disks,
                                 GFP_KERNEL);
        if (!conf->mirrors)
-               goto out_no_mem;
+               goto abort;
 
        conf->tmppage = alloc_page(GFP_KERNEL);
        if (!conf->tmppage)
-               goto out_no_mem;
+               goto abort;
 
-       conf->poolinfo = kmalloc(sizeof(*conf->poolinfo), GFP_KERNEL);
+       conf->poolinfo = kzalloc(sizeof(*conf->poolinfo), GFP_KERNEL);
        if (!conf->poolinfo)
-               goto out_no_mem;
-       conf->poolinfo->mddev = NULL;
+               goto abort;
        conf->poolinfo->raid_disks = mddev->raid_disks;
        conf->r1bio_pool = mempool_create(NR_RAID1_BIOS, r1bio_pool_alloc,
                                          r1bio_pool_free,
                                          conf->poolinfo);
        if (!conf->r1bio_pool)
-               goto out_no_mem;
+               goto abort;
+
        conf->poolinfo->mddev = mddev;
 
        spin_lock_init(&conf->device_lock);
-       mddev->queue->queue_lock = &conf->device_lock;
-
        list_for_each_entry(rdev, &mddev->disks, same_set) {
-               disk_idx = rdev->raid_disk;
+               int disk_idx = rdev->raid_disk;
                if (disk_idx >= mddev->raid_disks
                    || disk_idx < 0)
                        continue;
                disk = conf->mirrors + disk_idx;
 
                disk->rdev = rdev;
-               disk_stack_limits(mddev->gendisk, rdev->bdev,
-                                 rdev->data_offset << 9);
-               /* as we don't honour merge_bvec_fn, we must never risk
-                * violating it, so limit ->max_sector to one PAGE, as
-                * a one page request is never in violation.
-                */
-               if (rdev->bdev->bd_disk->queue->merge_bvec_fn &&
-                   queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9))
-                       blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
 
                disk->head_position = 0;
        }
@@ -2022,8 +2017,7 @@ static int run(mddev_t *mddev)
        bio_list_init(&conf->pending_bio_list);
        bio_list_init(&conf->flushing_bio_list);
 
-
-       mddev->degraded = 0;
+       conf->last_used = -1;
        for (i = 0; i < conf->raid_disks; i++) {
 
                disk = conf->mirrors + i;
@@ -2031,38 +2025,97 @@ static int run(mddev_t *mddev)
                if (!disk->rdev ||
                    !test_bit(In_sync, &disk->rdev->flags)) {
                        disk->head_position = 0;
-                       mddev->degraded++;
                        if (disk->rdev)
                                conf->fullsync = 1;
-               }
+               } else if (conf->last_used < 0)
+                       /*
+                        * The first working device is used as a
+                        * starting point to read balancing.
+                        */
+                       conf->last_used = i;
        }
-       if (mddev->degraded == conf->raid_disks) {
+
+       err = -EIO;
+       if (conf->last_used < 0) {
                printk(KERN_ERR "raid1: no operational mirrors for %s\n",
-                       mdname(mddev));
-               goto out_free_conf;
+                      mdname(mddev));
+               goto abort;
        }
-       if (conf->raid_disks - mddev->degraded == 1)
-               mddev->recovery_cp = MaxSector;
+       err = -ENOMEM;
+       conf->thread = md_register_thread(raid1d, mddev, NULL);
+       if (!conf->thread) {
+               printk(KERN_ERR
+                      "raid1: couldn't allocate thread for %s\n",
+                      mdname(mddev));
+               goto abort;
+       }
+
+       return conf;
+
+ abort:
+       if (conf) {
+               if (conf->r1bio_pool)
+                       mempool_destroy(conf->r1bio_pool);
+               kfree(conf->mirrors);
+               safe_put_page(conf->tmppage);
+               kfree(conf->poolinfo);
+               kfree(conf);
+       }
+       return ERR_PTR(err);
+}
 
+static int run(mddev_t *mddev)
+{
+       conf_t *conf;
+       int i;
+       mdk_rdev_t *rdev;
+
+       if (mddev->level != 1) {
+               printk("raid1: %s: raid level not set to mirroring (%d)\n",
+                      mdname(mddev), mddev->level);
+               return -EIO;
+       }
+       if (mddev->reshape_position != MaxSector) {
+               printk("raid1: %s: reshape_position set but not supported\n",
+                      mdname(mddev));
+               return -EIO;
+       }
        /*
-        * find the first working one and use it as a starting point
-        * to read balancing.
+        * copy the already verified devices into our private RAID1
+        * bookkeeping area. [whatever we allocate in run(),
+        * should be freed in stop()]
         */
-       for (j = 0; j < conf->raid_disks &&
-                    (!conf->mirrors[j].rdev ||
-                     !test_bit(In_sync, &conf->mirrors[j].rdev->flags)) ; j++)
-               /* nothing */;
-       conf->last_used = j;
+       if (mddev->private == NULL)
+               conf = setup_conf(mddev);
+       else
+               conf = mddev->private;
 
+       if (IS_ERR(conf))
+               return PTR_ERR(conf);
 
-       mddev->thread = md_register_thread(raid1d, mddev, NULL);
-       if (!mddev->thread) {
-               printk(KERN_ERR
-                      "raid1: couldn't allocate thread for %s\n",
-                      mdname(mddev));
-               goto out_free_conf;
+       mddev->queue->queue_lock = &conf->device_lock;
+       list_for_each_entry(rdev, &mddev->disks, same_set) {
+               disk_stack_limits(mddev->gendisk, rdev->bdev,
+                                 rdev->data_offset << 9);
+               /* as we don't honour merge_bvec_fn, we must never risk
+                * violating it, so limit ->max_sector to one PAGE, as
+                * a one page request is never in violation.
+                */
+               if (rdev->bdev->bd_disk->queue->merge_bvec_fn &&
+                   queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9))
+                       blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
        }
 
+       mddev->degraded = 0;
+       for (i=0; i < conf->raid_disks; i++)
+               if (conf->mirrors[i].rdev == NULL ||
+                   !test_bit(In_sync, &conf->mirrors[i].rdev->flags) ||
+                   test_bit(Faulty, &conf->mirrors[i].rdev->flags))
+                       mddev->degraded++;
+
+       if (conf->raid_disks - mddev->degraded == 1)
+               mddev->recovery_cp = MaxSector;
+
        if (mddev->recovery_cp != MaxSector)
                printk(KERN_NOTICE "raid1: %s is not clean"
                       " -- starting background reconstruction\n",
@@ -2071,9 +2124,14 @@ static int run(mddev_t *mddev)
                "raid1: raid set %s active with %d out of %d mirrors\n",
                mdname(mddev), mddev->raid_disks - mddev->degraded, 
                mddev->raid_disks);
+
        /*
         * Ok, everything is just fine now
         */
+       mddev->thread = conf->thread;
+       conf->thread = NULL;
+       mddev->private = conf;
+
        md_set_array_sectors(mddev, raid1_size(mddev, 0, 0));
 
        mddev->queue->unplug_fn = raid1_unplug;
@@ -2081,23 +2139,6 @@ static int run(mddev_t *mddev)
        mddev->queue->backing_dev_info.congested_data = mddev;
        md_integrity_register(mddev);
        return 0;
-
-out_no_mem:
-       printk(KERN_ERR "raid1: couldn't allocate memory for %s\n",
-              mdname(mddev));
-
-out_free_conf:
-       if (conf) {
-               if (conf->r1bio_pool)
-                       mempool_destroy(conf->r1bio_pool);
-               kfree(conf->mirrors);
-               safe_put_page(conf->tmppage);
-               kfree(conf->poolinfo);
-               kfree(conf);
-               mddev->private = NULL;
-       }
-out:
-       return -EIO;
 }
 
 static int stop(mddev_t *mddev)
@@ -2271,6 +2312,9 @@ static void raid1_quiesce(mddev_t *mddev, int state)
        conf_t *conf = mddev->private;
 
        switch(state) {
+       case 2: /* wake for suspend */
+               wake_up(&conf->wait_barrier);
+               break;
        case 1:
                raise_barrier(conf);
                break;
@@ -2280,6 +2324,23 @@ static void raid1_quiesce(mddev_t *mddev, int state)
        }
 }
 
+static void *raid1_takeover(mddev_t *mddev)
+{
+       /* raid1 can take over:
+        *  raid5 with 2 devices, any layout or chunk size
+        */
+       if (mddev->level == 5 && mddev->raid_disks == 2) {
+               conf_t *conf;
+               mddev->new_level = 1;
+               mddev->new_layout = 0;
+               mddev->new_chunk_sectors = 0;
+               conf = setup_conf(mddev);
+               if (!IS_ERR(conf))
+                       conf->barrier = 1;
+               return conf;
+       }
+       return ERR_PTR(-EINVAL);
+}
 
 static struct mdk_personality raid1_personality =
 {
@@ -2299,6 +2360,7 @@ static struct mdk_personality raid1_personality =
        .size           = raid1_size,
        .check_reshape  = raid1_reshape,
        .quiesce        = raid1_quiesce,
+       .takeover       = raid1_takeover,
 };
 
 static int __init raid_init(void)
@@ -2314,6 +2376,7 @@ static void raid_exit(void)
 module_init(raid_init);
 module_exit(raid_exit);
 MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("RAID1 (mirroring) personality for MD");
 MODULE_ALIAS("md-personality-3"); /* RAID1 */
 MODULE_ALIAS("md-raid1");
 MODULE_ALIAS("md-level-1");
index e87b84deff6831b4320bf2d496c4570ca14339f7..5f2d443ae28af03cb31d6b16d30495abc73b45ff 100644 (file)
@@ -59,6 +59,11 @@ struct r1_private_data_s {
 
        mempool_t *r1bio_pool;
        mempool_t *r1buf_pool;
+
+       /* When taking over an array from a different personality, we store
+        * the new thread here until we fully activate the array.
+        */
+       struct mdk_thread_s     *thread;
 };
 
 typedef struct r1_private_data_s conf_t;
index c2cb7b87b440dce777d92bb6c215d1c82efddbe1..d119b7b75e71ffabe5863b0b3463b7a66304f831 100644 (file)
@@ -804,7 +804,7 @@ static int make_request(struct request_queue *q, struct bio * bio)
        mdk_rdev_t *blocked_rdev;
 
        if (unlikely(bio_rw_flagged(bio, BIO_RW_BARRIER))) {
-               bio_endio(bio, -EOPNOTSUPP);
+               md_barrier_request(mddev, bio);
                return 0;
        }
 
@@ -1431,6 +1431,43 @@ static void recovery_request_write(mddev_t *mddev, r10bio_t *r10_bio)
 }
 
 
+/*
+ * Used by fix_read_error() to decay the per rdev read_errors.
+ * We halve the read error count for every hour that has elapsed
+ * since the last recorded read error.
+ *
+ */
+static void check_decay_read_errors(mddev_t *mddev, mdk_rdev_t *rdev)
+{
+       struct timespec cur_time_mon;
+       unsigned long hours_since_last;
+       unsigned int read_errors = atomic_read(&rdev->read_errors);
+
+       ktime_get_ts(&cur_time_mon);
+
+       if (rdev->last_read_error.tv_sec == 0 &&
+           rdev->last_read_error.tv_nsec == 0) {
+               /* first time we've seen a read error */
+               rdev->last_read_error = cur_time_mon;
+               return;
+       }
+
+       hours_since_last = (cur_time_mon.tv_sec -
+                           rdev->last_read_error.tv_sec) / 3600;
+
+       rdev->last_read_error = cur_time_mon;
+
+       /*
+        * if hours_since_last is > the number of bits in read_errors
+        * just set read errors to 0. We do this to avoid
+        * overflowing the shift of read_errors by hours_since_last.
+        */
+       if (hours_since_last >= 8 * sizeof(read_errors))
+               atomic_set(&rdev->read_errors, 0);
+       else
+               atomic_set(&rdev->read_errors, read_errors >> hours_since_last);
+}
+
 /*
  * This is a kernel thread which:
  *
@@ -1444,6 +1481,43 @@ static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio)
        int sect = 0; /* Offset from r10_bio->sector */
        int sectors = r10_bio->sectors;
        mdk_rdev_t*rdev;
+       int max_read_errors = atomic_read(&mddev->max_corr_read_errors);
+
+       rcu_read_lock();
+       {
+               int d = r10_bio->devs[r10_bio->read_slot].devnum;
+               char b[BDEVNAME_SIZE];
+               int cur_read_error_count = 0;
+
+               rdev = rcu_dereference(conf->mirrors[d].rdev);
+               bdevname(rdev->bdev, b);
+
+               if (test_bit(Faulty, &rdev->flags)) {
+                       rcu_read_unlock();
+                       /* drive has already been failed, just ignore any
+                          more fix_read_error() attempts */
+                       return;
+               }
+
+               check_decay_read_errors(mddev, rdev);
+               atomic_inc(&rdev->read_errors);
+               cur_read_error_count = atomic_read(&rdev->read_errors);
+               if (cur_read_error_count > max_read_errors) {
+                       rcu_read_unlock();
+                       printk(KERN_NOTICE
+                              "raid10: %s: Raid device exceeded "
+                              "read_error threshold "
+                              "[cur %d:max %d]\n",
+                              b, cur_read_error_count, max_read_errors);
+                       printk(KERN_NOTICE
+                              "raid10: %s: Failing raid "
+                              "device\n", b);
+                       md_error(mddev, conf->mirrors[d].rdev);
+                       return;
+               }
+       }
+       rcu_read_unlock();
+
        while(sectors) {
                int s = sectors;
                int sl = r10_bio->read_slot;
@@ -1488,6 +1562,7 @@ static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio)
                /* write it back and re-read */
                rcu_read_lock();
                while (sl != r10_bio->read_slot) {
+                       char b[BDEVNAME_SIZE];
                        int d;
                        if (sl==0)
                                sl = conf->copies;
@@ -1503,9 +1578,21 @@ static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio)
                                                 r10_bio->devs[sl].addr +
                                                 sect + rdev->data_offset,
                                                 s<<9, conf->tmppage, WRITE)
-                                   == 0)
+                                   == 0) {
                                        /* Well, this device is dead */
+                                       printk(KERN_NOTICE
+                                              "raid10:%s: read correction "
+                                              "write failed"
+                                              " (%d sectors at %llu on %s)\n",
+                                              mdname(mddev), s,
+                                              (unsigned long long)(sect+
+                                              rdev->data_offset),
+                                              bdevname(rdev->bdev, b));
+                                       printk(KERN_NOTICE "raid10:%s: failing "
+                                              "drive\n",
+                                              bdevname(rdev->bdev, b));
                                        md_error(mddev, rdev);
+                               }
                                rdev_dec_pending(rdev, mddev);
                                rcu_read_lock();
                        }
@@ -1526,10 +1613,22 @@ static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio)
                                if (sync_page_io(rdev->bdev,
                                                 r10_bio->devs[sl].addr +
                                                 sect + rdev->data_offset,
-                                                s<<9, conf->tmppage, READ) == 0)
+                                                s<<9, conf->tmppage,
+                                                READ) == 0) {
                                        /* Well, this device is dead */
+                                       printk(KERN_NOTICE
+                                              "raid10:%s: unable to read back "
+                                              "corrected sectors"
+                                              " (%d sectors at %llu on %s)\n",
+                                              mdname(mddev), s,
+                                              (unsigned long long)(sect+
+                                                   rdev->data_offset),
+                                              bdevname(rdev->bdev, b));
+                                       printk(KERN_NOTICE "raid10:%s: failing drive\n",
+                                              bdevname(rdev->bdev, b));
+
                                        md_error(mddev, rdev);
-                               else
+                               } else {
                                        printk(KERN_INFO
                                               "raid10:%s: read error corrected"
                                               " (%d sectors at %llu on %s)\n",
@@ -1537,6 +1636,7 @@ static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio)
                                               (unsigned long long)(sect+
                                                    rdev->data_offset),
                                               bdevname(rdev->bdev, b));
+                               }
 
                                rdev_dec_pending(rdev, mddev);
                                rcu_read_lock();
@@ -2275,13 +2375,6 @@ static void raid10_quiesce(mddev_t *mddev, int state)
                lower_barrier(conf);
                break;
        }
-       if (mddev->thread) {
-               if (mddev->bitmap)
-                       mddev->thread->timeout = mddev->bitmap->daemon_sleep * HZ;
-               else
-                       mddev->thread->timeout = MAX_SCHEDULE_TIMEOUT;
-               md_wakeup_thread(mddev->thread);
-       }
 }
 
 static struct mdk_personality raid10_personality =
@@ -2315,6 +2408,7 @@ static void raid_exit(void)
 module_init(raid_init);
 module_exit(raid_exit);
 MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("RAID10 (striped mirror) personality for MD");
 MODULE_ALIAS("md-personality-9"); /* RAID10 */
 MODULE_ALIAS("md-raid10");
 MODULE_ALIAS("md-level-10");
index d29215d966dadc23f4c1a6844a725dc89d6a8304..e84204eb12dff9c87daaf8ecbdba4462eda8971f 100644 (file)
@@ -2947,6 +2947,7 @@ static void handle_stripe5(struct stripe_head *sh)
        struct r5dev *dev;
        mdk_rdev_t *blocked_rdev = NULL;
        int prexor;
+       int dec_preread_active = 0;
 
        memset(&s, 0, sizeof(s));
        pr_debug("handling stripe %llu, state=%#lx cnt=%d, pd_idx=%d check:%d "
@@ -3096,12 +3097,8 @@ static void handle_stripe5(struct stripe_head *sh)
                                        set_bit(STRIPE_INSYNC, &sh->state);
                        }
                }
-               if (test_and_clear_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) {
-                       atomic_dec(&conf->preread_active_stripes);
-                       if (atomic_read(&conf->preread_active_stripes) <
-                               IO_THRESHOLD)
-                               md_wakeup_thread(conf->mddev->thread);
-               }
+               if (test_and_clear_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
+                       dec_preread_active = 1;
        }
 
        /* Now to consider new write requests and what else, if anything
@@ -3208,6 +3205,16 @@ static void handle_stripe5(struct stripe_head *sh)
 
        ops_run_io(sh, &s);
 
+       if (dec_preread_active) {
+               /* We delay this until after ops_run_io so that if make_request
+                * is waiting on a barrier, it won't continue until the writes
+                * have actually been submitted.
+                */
+               atomic_dec(&conf->preread_active_stripes);
+               if (atomic_read(&conf->preread_active_stripes) <
+                   IO_THRESHOLD)
+                       md_wakeup_thread(conf->mddev->thread);
+       }
        return_io(return_bi);
 }
 
@@ -3221,6 +3228,7 @@ static void handle_stripe6(struct stripe_head *sh)
        struct r6_state r6s;
        struct r5dev *dev, *pdev, *qdev;
        mdk_rdev_t *blocked_rdev = NULL;
+       int dec_preread_active = 0;
 
        pr_debug("handling stripe %llu, state=%#lx cnt=%d, "
                "pd_idx=%d, qd_idx=%d\n, check:%d, reconstruct:%d\n",
@@ -3358,7 +3366,6 @@ static void handle_stripe6(struct stripe_head *sh)
         * completed
         */
        if (sh->reconstruct_state == reconstruct_state_drain_result) {
-               int qd_idx = sh->qd_idx;
 
                sh->reconstruct_state = reconstruct_state_idle;
                /* All the 'written' buffers and the parity blocks are ready to
@@ -3380,12 +3387,8 @@ static void handle_stripe6(struct stripe_head *sh)
                                        set_bit(STRIPE_INSYNC, &sh->state);
                        }
                }
-               if (test_and_clear_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) {
-                       atomic_dec(&conf->preread_active_stripes);
-                       if (atomic_read(&conf->preread_active_stripes) <
-                               IO_THRESHOLD)
-                               md_wakeup_thread(conf->mddev->thread);
-               }
+               if (test_and_clear_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
+                       dec_preread_active = 1;
        }
 
        /* Now to consider new write requests and what else, if anything
@@ -3494,6 +3497,18 @@ static void handle_stripe6(struct stripe_head *sh)
 
        ops_run_io(sh, &s);
 
+
+       if (dec_preread_active) {
+               /* We delay this until after ops_run_io so that if make_request
+                * is waiting on a barrier, it won't continue until the writes
+                * have actually been submitted.
+                */
+               atomic_dec(&conf->preread_active_stripes);
+               if (atomic_read(&conf->preread_active_stripes) <
+                   IO_THRESHOLD)
+                       md_wakeup_thread(conf->mddev->thread);
+       }
+
        return_io(return_bi);
 }
 
@@ -3741,7 +3756,7 @@ static int chunk_aligned_read(struct request_queue *q, struct bio * raid_bio)
 {
        mddev_t *mddev = q->queuedata;
        raid5_conf_t *conf = mddev->private;
-       unsigned int dd_idx;
+       int dd_idx;
        struct bio* align_bi;
        mdk_rdev_t *rdev;
 
@@ -3866,7 +3881,13 @@ static int make_request(struct request_queue *q, struct bio * bi)
        int cpu, remaining;
 
        if (unlikely(bio_rw_flagged(bi, BIO_RW_BARRIER))) {
-               bio_endio(bi, -EOPNOTSUPP);
+               /* Drain all pending writes.  We only really need
+                * to ensure they have been submitted, but this is
+                * easier.
+                */
+               mddev->pers->quiesce(mddev, 1);
+               mddev->pers->quiesce(mddev, 0);
+               md_barrier_request(mddev, bi);
                return 0;
        }
 
@@ -3990,6 +4011,9 @@ static int make_request(struct request_queue *q, struct bio * bi)
                        finish_wait(&conf->wait_for_overlap, &w);
                        set_bit(STRIPE_HANDLE, &sh->state);
                        clear_bit(STRIPE_DELAYED, &sh->state);
+                       if (mddev->barrier && 
+                           !test_and_set_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
+                               atomic_inc(&conf->preread_active_stripes);
                        release_stripe(sh);
                } else {
                        /* cannot get stripe for read-ahead, just give-up */
@@ -4009,6 +4033,14 @@ static int make_request(struct request_queue *q, struct bio * bi)
 
                bio_endio(bi, 0);
        }
+
+       if (mddev->barrier) {
+               /* We need to wait for the stripes to all be handled.
+                * So: wait for preread_active_stripes to drop to 0.
+                */
+               wait_event(mddev->thread->wqueue,
+                          atomic_read(&conf->preread_active_stripes) == 0);
+       }
        return 0;
 }
 
@@ -5860,6 +5892,7 @@ static void raid5_exit(void)
 module_init(raid5_init);
 module_exit(raid5_exit);
 MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("RAID4/5/6 (striping with parity) personality for MD");
 MODULE_ALIAS("md-personality-4"); /* RAID5 */
 MODULE_ALIAS("md-raid5");
 MODULE_ALIAS("md-raid4");
index 866215ac7f2554f86733cc900f4b902b3f60bc76..bffc61bff5ab7c743d4ce0da3d716cd8642112f0 100644 (file)
@@ -31,25 +31,6 @@ EXPORT_SYMBOL(raid6_empty_zero_page);
 struct raid6_calls raid6_call;
 EXPORT_SYMBOL_GPL(raid6_call);
 
-/* Various routine sets */
-extern const struct raid6_calls raid6_intx1;
-extern const struct raid6_calls raid6_intx2;
-extern const struct raid6_calls raid6_intx4;
-extern const struct raid6_calls raid6_intx8;
-extern const struct raid6_calls raid6_intx16;
-extern const struct raid6_calls raid6_intx32;
-extern const struct raid6_calls raid6_mmxx1;
-extern const struct raid6_calls raid6_mmxx2;
-extern const struct raid6_calls raid6_sse1x1;
-extern const struct raid6_calls raid6_sse1x2;
-extern const struct raid6_calls raid6_sse2x1;
-extern const struct raid6_calls raid6_sse2x2;
-extern const struct raid6_calls raid6_sse2x4;
-extern const struct raid6_calls raid6_altivec1;
-extern const struct raid6_calls raid6_altivec2;
-extern const struct raid6_calls raid6_altivec4;
-extern const struct raid6_calls raid6_altivec8;
-
 const struct raid6_calls * const raid6_algos[] = {
        &raid6_intx1,
        &raid6_intx2,
@@ -169,3 +150,4 @@ static void raid6_exit(void)
 subsys_initcall(raid6_select_algo);
 module_exit(raid6_exit);
 MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("RAID6 Q-syndrome calculations");
diff --git a/drivers/mfd/88pm8607.c b/drivers/mfd/88pm8607.c
new file mode 100644 (file)
index 0000000..7e3f659
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ * Base 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/module.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/88pm8607.h>
+
+
+#define PM8607_REG_RESOURCE(_start, _end)              \
+{                                                      \
+       .start  = PM8607_##_start,                      \
+       .end    = PM8607_##_end,                        \
+       .flags  = IORESOURCE_IO,                        \
+}
+
+static struct resource pm8607_regulator_resources[] = {
+       PM8607_REG_RESOURCE(BUCK1, BUCK1),
+       PM8607_REG_RESOURCE(BUCK2, BUCK2),
+       PM8607_REG_RESOURCE(BUCK3, BUCK3),
+       PM8607_REG_RESOURCE(LDO1,  LDO1),
+       PM8607_REG_RESOURCE(LDO2,  LDO2),
+       PM8607_REG_RESOURCE(LDO3,  LDO3),
+       PM8607_REG_RESOURCE(LDO4,  LDO4),
+       PM8607_REG_RESOURCE(LDO5,  LDO5),
+       PM8607_REG_RESOURCE(LDO6,  LDO6),
+       PM8607_REG_RESOURCE(LDO7,  LDO7),
+       PM8607_REG_RESOURCE(LDO8,  LDO8),
+       PM8607_REG_RESOURCE(LDO9,  LDO9),
+       PM8607_REG_RESOURCE(LDO10, LDO10),
+       PM8607_REG_RESOURCE(LDO12, LDO12),
+       PM8607_REG_RESOURCE(LDO14, LDO14),
+};
+
+#define PM8607_REG_DEVS(_name, _id)                                    \
+{                                                                      \
+       .name           = "88pm8607-" #_name,                           \
+       .num_resources  = 1,                                            \
+       .resources      = &pm8607_regulator_resources[PM8607_ID_##_id], \
+}
+
+static struct mfd_cell pm8607_devs[] = {
+       PM8607_REG_DEVS(buck1, BUCK1),
+       PM8607_REG_DEVS(buck2, BUCK2),
+       PM8607_REG_DEVS(buck3, BUCK3),
+       PM8607_REG_DEVS(ldo1,  LDO1),
+       PM8607_REG_DEVS(ldo2,  LDO2),
+       PM8607_REG_DEVS(ldo3,  LDO3),
+       PM8607_REG_DEVS(ldo4,  LDO4),
+       PM8607_REG_DEVS(ldo5,  LDO5),
+       PM8607_REG_DEVS(ldo6,  LDO6),
+       PM8607_REG_DEVS(ldo7,  LDO7),
+       PM8607_REG_DEVS(ldo8,  LDO8),
+       PM8607_REG_DEVS(ldo9,  LDO9),
+       PM8607_REG_DEVS(ldo10, LDO10),
+       PM8607_REG_DEVS(ldo12, LDO12),
+       PM8607_REG_DEVS(ldo14, LDO14),
+};
+
+static inline int pm8607_read_device(struct pm8607_chip *chip,
+                                    int reg, int bytes, void *dest)
+{
+       struct i2c_client *i2c = chip->client;
+       unsigned char data;
+       int ret;
+
+       data = (unsigned char)reg;
+       ret = i2c_master_send(i2c, &data, 1);
+       if (ret < 0)
+               return ret;
+
+       ret = i2c_master_recv(i2c, dest, bytes);
+       if (ret < 0)
+               return ret;
+       return 0;
+}
+
+static inline int pm8607_write_device(struct pm8607_chip *chip,
+                                     int reg, int bytes, void *src)
+{
+       struct i2c_client *i2c = chip->client;
+       unsigned char buf[bytes + 1];
+       int ret;
+
+       buf[0] = (unsigned char)reg;
+       memcpy(&buf[1], src, bytes);
+
+       ret = i2c_master_send(i2c, buf, bytes + 1);
+       if (ret < 0)
+               return ret;
+       return 0;
+}
+
+int pm8607_reg_read(struct pm8607_chip *chip, int reg)
+{
+       unsigned char data;
+       int ret;
+
+       mutex_lock(&chip->io_lock);
+       ret = chip->read(chip, reg, 1, &data);
+       mutex_unlock(&chip->io_lock);
+
+       if (ret < 0)
+               return ret;
+       else
+               return (int)data;
+}
+EXPORT_SYMBOL(pm8607_reg_read);
+
+int pm8607_reg_write(struct pm8607_chip *chip, int reg,
+                    unsigned char data)
+{
+       int ret;
+
+       mutex_lock(&chip->io_lock);
+       ret = chip->write(chip, reg, 1, &data);
+       mutex_unlock(&chip->io_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL(pm8607_reg_write);
+
+int pm8607_bulk_read(struct pm8607_chip *chip, int reg,
+                    int count, unsigned char *buf)
+{
+       int ret;
+
+       mutex_lock(&chip->io_lock);
+       ret = chip->read(chip, reg, count, buf);
+       mutex_unlock(&chip->io_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL(pm8607_bulk_read);
+
+int pm8607_bulk_write(struct pm8607_chip *chip, int reg,
+                     int count, unsigned char *buf)
+{
+       int ret;
+
+       mutex_lock(&chip->io_lock);
+       ret = chip->write(chip, reg, count, buf);
+       mutex_unlock(&chip->io_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL(pm8607_bulk_write);
+
+int pm8607_set_bits(struct pm8607_chip *chip, int reg,
+                   unsigned char mask, unsigned char data)
+{
+       unsigned char value;
+       int ret;
+
+       mutex_lock(&chip->io_lock);
+       ret = chip->read(chip, reg, 1, &value);
+       if (ret < 0)
+               goto out;
+       value &= ~mask;
+       value |= data;
+       ret = chip->write(chip, reg, 1, &value);
+out:
+       mutex_unlock(&chip->io_lock);
+       return ret;
+}
+EXPORT_SYMBOL(pm8607_set_bits);
+
+
+static const struct i2c_device_id pm8607_id_table[] = {
+       { "88PM8607", 0 },
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, pm8607_id_table);
+
+
+static int __devinit pm8607_probe(struct i2c_client *client,
+                                 const struct i2c_device_id *id)
+{
+       struct pm8607_platform_data *pdata = client->dev.platform_data;
+       struct pm8607_chip *chip;
+       int i, count;
+       int ret;
+
+       chip = kzalloc(sizeof(struct pm8607_chip), GFP_KERNEL);
+       if (chip == NULL)
+               return -ENOMEM;
+
+       chip->client = client;
+       chip->dev = &client->dev;
+       chip->read = pm8607_read_device;
+       chip->write = pm8607_write_device;
+       i2c_set_clientdata(client, chip);
+
+       mutex_init(&chip->io_lock);
+       dev_set_drvdata(chip->dev, chip);
+
+       ret = pm8607_reg_read(chip, PM8607_CHIP_ID);
+       if (ret < 0) {
+               dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret);
+               goto out;
+       }
+       if ((ret & CHIP_ID_MASK) == CHIP_ID)
+               dev_info(chip->dev, "Marvell 88PM8607 (ID: %02x) detected\n",
+                        ret);
+       else {
+               dev_err(chip->dev, "Failed to detect Marvell 88PM8607. "
+                       "Chip ID: %02x\n", ret);
+               goto out;
+       }
+       chip->chip_id = ret;
+
+       ret = pm8607_reg_read(chip, PM8607_BUCK3);
+       if (ret < 0) {
+               dev_err(chip->dev, "Failed to read BUCK3 register: %d\n", ret);
+               goto out;
+       }
+       if (ret & PM8607_BUCK3_DOUBLE)
+               chip->buck3_double = 1;
+
+       ret = pm8607_reg_read(chip, PM8607_MISC1);
+       if (ret < 0) {
+               dev_err(chip->dev, "Failed to read MISC1 register: %d\n", ret);
+               goto out;
+       }
+       if (pdata->i2c_port == PI2C_PORT)
+               ret |= PM8607_MISC1_PI2C;
+       else
+               ret &= ~PM8607_MISC1_PI2C;
+       ret = pm8607_reg_write(chip, PM8607_MISC1, ret);
+       if (ret < 0) {
+               dev_err(chip->dev, "Failed to write MISC1 register: %d\n", ret);
+               goto out;
+       }
+
+
+       count = ARRAY_SIZE(pm8607_devs);
+       for (i = 0; i < count; i++) {
+               ret = mfd_add_devices(chip->dev, i, &pm8607_devs[i],
+                                     1, NULL, 0);
+               if (ret != 0) {
+                       dev_err(chip->dev, "Failed to add subdevs\n");
+                       goto out;
+               }
+       }
+
+       return 0;
+
+out:
+       i2c_set_clientdata(client, NULL);
+       kfree(chip);
+       return ret;
+}
+
+static int __devexit pm8607_remove(struct i2c_client *client)
+{
+       struct pm8607_chip *chip = i2c_get_clientdata(client);
+
+       mfd_remove_devices(chip->dev);
+       kfree(chip);
+       return 0;
+}
+
+static struct i2c_driver pm8607_driver = {
+       .driver = {
+               .name   = "88PM8607",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = pm8607_probe,
+       .remove         = __devexit_p(pm8607_remove),
+       .id_table       = pm8607_id_table,
+};
+
+static int __init pm8607_init(void)
+{
+       int ret;
+       ret = i2c_add_driver(&pm8607_driver);
+       if (ret != 0)
+               pr_err("Failed to register 88PM8607 I2C driver: %d\n", ret);
+       return ret;
+}
+subsys_initcall(pm8607_init);
+
+static void __exit pm8607_exit(void)
+{
+       i2c_del_driver(&pm8607_driver);
+}
+module_exit(pm8607_exit);
+
+MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM8607");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_LICENSE("GPL");
index a296e717e86edbad24c9c34460ae65376c531af4..87829789243e87ded4653aa8b41da634060a670d 100644 (file)
@@ -103,10 +103,10 @@ config MENELAUS
          cell phones and PDAs.
 
 config TWL4030_CORE
-       bool "Texas Instruments TWL4030/TPS659x0 Support"
+       bool "Texas Instruments TWL4030/TWL5030/TWL6030/TPS659x0 Support"
        depends on I2C=y && GENERIC_HARDIRQS
        help
-         Say yes here if you have TWL4030 family chip on your board.
+         Say yes here if you have TWL4030 / TWL6030 family chip on your board.
          This core driver provides register access and IRQ handling
          facilities, and registers devices for the various functions
          so that function-specific drivers can bind to them.
@@ -174,6 +174,16 @@ config PMIC_DA903X
          individual components like LCD backlight, voltage regulators,
          LEDs and battery-charger under the corresponding menus.
 
+config PMIC_ADP5520
+       bool "Analog Devices ADP5520/01 MFD PMIC Core Support"
+       depends on I2C=y
+       help
+         Say yes here to add support for Analog Devices AD5520 and ADP5501,
+         Multifunction Power Management IC. This includes
+         the I2C driver and the core APIs _only_, you have to select
+         individual components like LCD backlight, LEDs, GPIOs and Kepad
+         under the corresponding menus.
+
 config MFD_WM8400
        tristate "Support Wolfson Microelectronics WM8400"
        select MFD_CORE
@@ -185,12 +195,12 @@ config MFD_WM8400
          the functionality of the device.
 
 config MFD_WM831X
-       tristate "Support Wolfson Microelectronics WM831x PMICs"
+       bool "Support Wolfson Microelectronics WM831x/2x PMICs"
        select MFD_CORE
-       depends on I2C
+       depends on I2C=y
        help
-         Support for the Wolfson Microelecronics WM831x PMICs.  This
-         driver provides common support for accessing the device,
+         Support for the Wolfson Microelecronics WM831x and WM832x PMICs.
+         This driver provides common support for accessing the device,
          additional drivers must be enabled in order to use the
          functionality of the device.
 
@@ -319,6 +329,25 @@ config EZX_PCAP
          This enables the PCAP ASIC present on EZX Phones. This is
          needed for MMC, TouchScreen, Sound, USB, etc..
 
+config MFD_88PM8607
+       bool "Support Marvell 88PM8607"
+       depends on I2C=y
+       select MFD_CORE
+       help
+         This supports for Marvell 88PM8607 Power Management IC. This includes
+         the I2C driver and the core APIs _only_, you have to select
+         individual components like voltage regulators, RTC and
+         battery-charger under the corresponding menus.
+
+config AB4500_CORE
+       tristate "ST-Ericsson's AB4500 Mixed Signal Power management chip"
+       depends on SPI
+       help
+         Select this option to enable access to AB4500 power management
+         chip. This connects to U8500 on the SSP/SPI bus and exports
+         read/write functions for the devices to get access to this chip.
+         This chip embeds various other multimedia funtionalities as well.
+
 endmenu
 
 menu "Multimedia Capabilities Port drivers"
index 11350c1d9301a72296a563daad3fc94e1f52b182..ca2f2c4ff05e70e2ac207516f4a215df3401136a 100644 (file)
@@ -19,13 +19,14 @@ obj-$(CONFIG_MFD_WM8400)    += wm8400-core.o
 wm831x-objs                    := wm831x-core.o wm831x-irq.o wm831x-otp.o
 obj-$(CONFIG_MFD_WM831X)       += wm831x.o
 wm8350-objs                    := wm8350-core.o wm8350-regmap.o wm8350-gpio.o
+wm8350-objs                    += wm8350-irq.o
 obj-$(CONFIG_MFD_WM8350)       += wm8350.o
 obj-$(CONFIG_MFD_WM8350_I2C)   += wm8350-i2c.o
 
 obj-$(CONFIG_TPS65010)         += tps65010.o
 obj-$(CONFIG_MENELAUS)         += menelaus.o
 
-obj-$(CONFIG_TWL4030_CORE)     += twl4030-core.o twl4030-irq.o
+obj-$(CONFIG_TWL4030_CORE)     += twl-core.o twl4030-irq.o twl6030-irq.o
 obj-$(CONFIG_TWL4030_POWER)    += twl4030-power.o
 obj-$(CONFIG_TWL4030_CODEC)    += twl4030-codec.o
 
@@ -52,3 +53,6 @@ obj-$(CONFIG_PCF50633_ADC)    += pcf50633-adc.o
 obj-$(CONFIG_PCF50633_GPIO)    += pcf50633-gpio.o
 obj-$(CONFIG_AB3100_CORE)      += ab3100-core.o
 obj-$(CONFIG_AB3100_OTP)       += ab3100-otp.o
+obj-$(CONFIG_AB4500_CORE)      += ab4500-core.o
+obj-$(CONFIG_MFD_88PM8607)     += 88pm8607.o
+obj-$(CONFIG_PMIC_ADP5520)     += adp5520.o
\ No newline at end of file
index 613481028272f114c754a4a652987fce90452cae..fd42a80e7bf95df87cfa6d88301b418fae596a96 100644 (file)
@@ -900,9 +900,6 @@ static int __init ab3100_probe(struct i2c_client *client,
                goto exit_no_testreg_client;
        }
 
-       strlcpy(ab3100->testreg_client->name, id->name,
-               sizeof(ab3100->testreg_client->name));
-
        err = ab3100_setup(ab3100);
        if (err)
                goto exit_no_setup;
diff --git a/drivers/mfd/ab4500-core.c b/drivers/mfd/ab4500-core.c
new file mode 100644 (file)
index 0000000..1c44c19
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2009 ST-Ericsson
+ *
+ * Author: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.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.
+ *
+ * AB4500 is a companion power management chip used with U8500.
+ * On this platform, this is interfaced with SSP0 controller
+ * which is a ARM primecell pl022.
+ *
+ * At the moment the module just exports read/write features.
+ * Interrupt management to be added - TODO.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/mfd/ab4500.h>
+
+/* just required if probe fails, we need to
+ * unregister the device
+ */
+static struct spi_driver ab4500_driver;
+
+/*
+ * This funtion writes to any AB4500 registers using
+ * SPI protocol &  before it writes it packs the data
+ * in the below 24 bit frame format
+ *
+ *      *|------------------------------------|
+ *      *| 23|22...18|17.......10|9|8|7......0|
+ *      *| r/w  bank       adr          data  |
+ *      * ------------------------------------
+ *
+ * This function shouldn't be called from interrupt
+ * context
+ */
+int ab4500_write(struct ab4500 *ab4500, unsigned char block,
+               unsigned long addr, unsigned char data)
+{
+       struct spi_transfer xfer;
+       struct spi_message      msg;
+       int err;
+       unsigned long spi_data =
+               block << 18 | addr << 10 | data;
+
+       mutex_lock(&ab4500->lock);
+       ab4500->tx_buf[0] = spi_data;
+       ab4500->rx_buf[0] = 0;
+
+       xfer.tx_buf     = ab4500->tx_buf;
+       xfer.rx_buf     = NULL;
+       xfer.len        = sizeof(unsigned long);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+
+       err = spi_sync(ab4500->spi, &msg);
+       mutex_unlock(&ab4500->lock);
+
+       return err;
+}
+EXPORT_SYMBOL(ab4500_write);
+
+int ab4500_read(struct ab4500 *ab4500, unsigned char block,
+               unsigned long addr)
+{
+       struct spi_transfer xfer;
+       struct spi_message      msg;
+       unsigned long spi_data =
+               1 << 23 | block << 18 | addr << 10;
+
+       mutex_lock(&ab4500->lock);
+       ab4500->tx_buf[0] = spi_data;
+       ab4500->rx_buf[0] = 0;
+
+       xfer.tx_buf     = ab4500->tx_buf;
+       xfer.rx_buf     = ab4500->rx_buf;
+       xfer.len        = sizeof(unsigned long);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+
+       spi_sync(ab4500->spi, &msg);
+       mutex_unlock(&ab4500->lock);
+
+       return  ab4500->rx_buf[0];
+}
+EXPORT_SYMBOL(ab4500_read);
+
+/* ref: ab3100 core */
+#define AB4500_DEVICE(devname, devid)                          \
+static struct platform_device ab4500_##devname##_device = {    \
+       .name   = devid,                                        \
+       .id     = -1,                                           \
+}
+
+/* list of childern devices of ab4500 - all are
+ * not populated here - TODO
+ */
+AB4500_DEVICE(charger, "ab4500-charger");
+AB4500_DEVICE(audio, "ab4500-audio");
+AB4500_DEVICE(usb, "ab4500-usb");
+AB4500_DEVICE(tvout, "ab4500-tvout");
+AB4500_DEVICE(sim, "ab4500-sim");
+AB4500_DEVICE(gpadc, "ab4500-gpadc");
+AB4500_DEVICE(clkmgt, "ab4500-clkmgt");
+AB4500_DEVICE(misc, "ab4500-misc");
+
+static struct platform_device *ab4500_platform_devs[] = {
+       &ab4500_charger_device,
+       &ab4500_audio_device,
+       &ab4500_usb_device,
+       &ab4500_tvout_device,
+       &ab4500_sim_device,
+       &ab4500_gpadc_device,
+       &ab4500_clkmgt_device,
+       &ab4500_misc_device,
+};
+
+static int __init ab4500_probe(struct spi_device *spi)
+{
+       struct ab4500   *ab4500;
+       unsigned char revision;
+       int err = 0;
+       int i;
+
+       ab4500 = kzalloc(sizeof *ab4500, GFP_KERNEL);
+       if (!ab4500) {
+               dev_err(&spi->dev, "could not allocate AB4500\n");
+               err = -ENOMEM;
+               goto not_detect;
+       }
+
+       ab4500->spi = spi;
+       spi_set_drvdata(spi, ab4500);
+
+       mutex_init(&ab4500->lock);
+
+       /* read the revision register */
+       revision = ab4500_read(ab4500, AB4500_MISC, AB4500_REV_REG);
+
+       /* revision id 0x0 is for early drop, 0x10 is for cut1.0 */
+       if (revision == 0x0 || revision == 0x10)
+               dev_info(&spi->dev, "Detected chip: %s, revision = %x\n",
+                       ab4500_driver.driver.name, revision);
+       else    {
+               dev_err(&spi->dev, "unknown chip: 0x%x\n", revision);
+               goto not_detect;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(ab4500_platform_devs); i++)  {
+               ab4500_platform_devs[i]->dev.parent =
+                       &spi->dev;
+               platform_set_drvdata(ab4500_platform_devs[i], ab4500);
+       }
+
+       /* register the ab4500 platform devices */
+       platform_add_devices(ab4500_platform_devs,
+                       ARRAY_SIZE(ab4500_platform_devs));
+
+       return err;
+
+ not_detect:
+       spi_unregister_driver(&ab4500_driver);
+       kfree(ab4500);
+       return err;
+}
+
+static int __devexit ab4500_remove(struct spi_device *spi)
+{
+       struct ab4500 *ab4500 =
+               spi_get_drvdata(spi);
+
+       kfree(ab4500);
+
+       return 0;
+}
+
+static struct spi_driver ab4500_driver = {
+       .driver = {
+               .name = "ab4500",
+               .owner = THIS_MODULE,
+       },
+       .probe = ab4500_probe,
+       .remove = __devexit_p(ab4500_remove)
+};
+
+static int __devinit ab4500_init(void)
+{
+       return spi_register_driver(&ab4500_driver);
+}
+
+static void __exit ab4500_exit(void)
+{
+       spi_unregister_driver(&ab4500_driver);
+}
+
+subsys_initcall(ab4500_init);
+module_exit(ab4500_exit);
+
+MODULE_AUTHOR("Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com");
+MODULE_DESCRIPTION("AB4500 core driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/adp5520.c b/drivers/mfd/adp5520.c
new file mode 100644 (file)
index 0000000..b266447
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+ * Base driver for Analog Devices ADP5520/ADP5501 MFD PMICs
+ * LCD Backlight: drivers/video/backlight/adp5520_bl
+ * LEDs                : drivers/led/leds-adp5520
+ * GPIO                : drivers/gpio/adp5520-gpio (ADP5520 only)
+ * Keys                : drivers/input/keyboard/adp5520-keys (ADP5520 only)
+ *
+ * Copyright 2009 Analog Devices Inc.
+ *
+ * Derived from 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/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+
+#include <linux/mfd/adp5520.h>
+
+struct adp5520_chip {
+       struct i2c_client *client;
+       struct device *dev;
+       struct mutex lock;
+       struct blocking_notifier_head notifier_list;
+       int irq;
+       unsigned long id;
+};
+
+static int __adp5520_read(struct i2c_client *client,
+                               int reg, uint8_t *val)
+{
+       int ret;
+
+       ret = i2c_smbus_read_byte_data(client, reg);
+       if (ret < 0) {
+               dev_err(&client->dev, "failed reading at 0x%02x\n", reg);
+               return ret;
+       }
+
+       *val = (uint8_t)ret;
+       return 0;
+}
+
+static int __adp5520_write(struct i2c_client *client,
+                                int reg, uint8_t val)
+{
+       int ret;
+
+       ret = i2c_smbus_write_byte_data(client, reg, val);
+       if (ret < 0) {
+               dev_err(&client->dev, "failed writing 0x%02x to 0x%02x\n",
+                               val, reg);
+               return ret;
+       }
+       return 0;
+}
+
+static int __adp5520_ack_bits(struct i2c_client *client, int reg,
+                             uint8_t bit_mask)
+{
+       struct adp5520_chip *chip = i2c_get_clientdata(client);
+       uint8_t reg_val;
+       int ret;
+
+       mutex_lock(&chip->lock);
+
+       ret = __adp5520_read(client, reg, &reg_val);
+
+       if (!ret) {
+               reg_val |= bit_mask;
+               ret = __adp5520_write(client, reg, reg_val);
+       }
+
+       mutex_unlock(&chip->lock);
+       return ret;
+}
+
+int adp5520_write(struct device *dev, int reg, uint8_t val)
+{
+       return __adp5520_write(to_i2c_client(dev), reg, val);
+}
+EXPORT_SYMBOL_GPL(adp5520_write);
+
+int adp5520_read(struct device *dev, int reg, uint8_t *val)
+{
+       return __adp5520_read(to_i2c_client(dev), reg, val);
+}
+EXPORT_SYMBOL_GPL(adp5520_read);
+
+int adp5520_set_bits(struct device *dev, int reg, uint8_t bit_mask)
+{
+       struct adp5520_chip *chip = dev_get_drvdata(dev);
+       uint8_t reg_val;
+       int ret;
+
+       mutex_lock(&chip->lock);
+
+       ret = __adp5520_read(chip->client, reg, &reg_val);
+
+       if (!ret && ((reg_val & bit_mask) == 0)) {
+               reg_val |= bit_mask;
+               ret = __adp5520_write(chip->client, reg, reg_val);
+       }
+
+       mutex_unlock(&chip->lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(adp5520_set_bits);
+
+int adp5520_clr_bits(struct device *dev, int reg, uint8_t bit_mask)
+{
+       struct adp5520_chip *chip = dev_get_drvdata(dev);
+       uint8_t reg_val;
+       int ret;
+
+       mutex_lock(&chip->lock);
+
+       ret = __adp5520_read(chip->client, reg, &reg_val);
+
+       if (!ret && (reg_val & bit_mask)) {
+               reg_val &= ~bit_mask;
+               ret = __adp5520_write(chip->client, reg, reg_val);
+       }
+
+       mutex_unlock(&chip->lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(adp5520_clr_bits);
+
+int adp5520_register_notifier(struct device *dev, struct notifier_block *nb,
+                               unsigned int events)
+{
+       struct adp5520_chip *chip = dev_get_drvdata(dev);
+
+       if (chip->irq) {
+               adp5520_set_bits(chip->dev, ADP5520_INTERRUPT_ENABLE,
+                       events & (ADP5520_KP_IEN | ADP5520_KR_IEN |
+                       ADP5520_OVP_IEN | ADP5520_CMPR_IEN));
+
+               return blocking_notifier_chain_register(&chip->notifier_list,
+                        nb);
+       }
+
+       return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(adp5520_register_notifier);
+
+int adp5520_unregister_notifier(struct device *dev, struct notifier_block *nb,
+                               unsigned int events)
+{
+       struct adp5520_chip *chip = dev_get_drvdata(dev);
+
+       adp5520_clr_bits(chip->dev, ADP5520_INTERRUPT_ENABLE,
+               events & (ADP5520_KP_IEN | ADP5520_KR_IEN |
+               ADP5520_OVP_IEN | ADP5520_CMPR_IEN));
+
+       return blocking_notifier_chain_unregister(&chip->notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(adp5520_unregister_notifier);
+
+static irqreturn_t adp5520_irq_thread(int irq, void *data)
+{
+       struct adp5520_chip *chip = data;
+       unsigned int events;
+       uint8_t reg_val;
+       int ret;
+
+       ret = __adp5520_read(chip->client, ADP5520_MODE_STATUS, &reg_val);
+       if (ret)
+               goto out;
+
+       events =  reg_val & (ADP5520_OVP_INT | ADP5520_CMPR_INT |
+               ADP5520_GPI_INT | ADP5520_KR_INT | ADP5520_KP_INT);
+
+       blocking_notifier_call_chain(&chip->notifier_list, events, NULL);
+       /* ACK, Sticky bits are W1C */
+       __adp5520_ack_bits(chip->client, ADP5520_MODE_STATUS, events);
+
+out:
+       return IRQ_HANDLED;
+}
+
+static int __remove_subdev(struct device *dev, void *unused)
+{
+       platform_device_unregister(to_platform_device(dev));
+       return 0;
+}
+
+static int adp5520_remove_subdevs(struct adp5520_chip *chip)
+{
+       return device_for_each_child(chip->dev, NULL, __remove_subdev);
+}
+
+static int __devinit adp5520_probe(struct i2c_client *client,
+                                       const struct i2c_device_id *id)
+{
+       struct adp5520_platform_data *pdata = client->dev.platform_data;
+       struct platform_device *pdev;
+       struct adp5520_chip *chip;
+       int ret;
+
+       if (!i2c_check_functionality(client->adapter,
+                                       I2C_FUNC_SMBUS_BYTE_DATA)) {
+               dev_err(&client->dev, "SMBUS Word Data not Supported\n");
+               return -EIO;
+       }
+
+       if (pdata == NULL) {
+               dev_err(&client->dev, "missing platform data\n");
+               return -ENODEV;
+       }
+
+       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, chip);
+       chip->client = client;
+
+       chip->dev = &client->dev;
+       chip->irq = client->irq;
+       chip->id = id->driver_data;
+       mutex_init(&chip->lock);
+
+       if (chip->irq) {
+               BLOCKING_INIT_NOTIFIER_HEAD(&chip->notifier_list);
+
+               ret = request_threaded_irq(chip->irq, NULL, adp5520_irq_thread,
+                               IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+                               "adp5520", chip);
+               if (ret) {
+                       dev_err(&client->dev, "failed to request irq %d\n",
+                                       chip->irq);
+                       goto out_free_chip;
+               }
+       }
+
+       ret = adp5520_write(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY);
+       if (ret) {
+               dev_err(&client->dev, "failed to write\n");
+               goto out_free_irq;
+       }
+
+       if (pdata->keys) {
+               pdev = platform_device_register_data(chip->dev, "adp5520-keys",
+                               chip->id, pdata->keys, sizeof(*pdata->keys));
+               if (IS_ERR(pdev)) {
+                       ret = PTR_ERR(pdev);
+                       goto out_remove_subdevs;
+               }
+       }
+
+       if (pdata->gpio) {
+               pdev = platform_device_register_data(chip->dev, "adp5520-gpio",
+                               chip->id, pdata->gpio, sizeof(*pdata->gpio));
+               if (IS_ERR(pdev)) {
+                       ret = PTR_ERR(pdev);
+                       goto out_remove_subdevs;
+               }
+       }
+
+       if (pdata->leds) {
+               pdev = platform_device_register_data(chip->dev, "adp5520-led",
+                               chip->id, pdata->leds, sizeof(*pdata->leds));
+               if (IS_ERR(pdev)) {
+                       ret = PTR_ERR(pdev);
+                       goto out_remove_subdevs;
+               }
+       }
+
+       if (pdata->backlight) {
+               pdev = platform_device_register_data(chip->dev,
+                                               "adp5520-backlight",
+                                               chip->id,
+                                               pdata->backlight,
+                                               sizeof(*pdata->backlight));
+               if (IS_ERR(pdev)) {
+                       ret = PTR_ERR(pdev);
+                       goto out_remove_subdevs;
+               }
+       }
+
+       return 0;
+
+out_remove_subdevs:
+       adp5520_remove_subdevs(chip);
+
+out_free_irq:
+       if (chip->irq)
+               free_irq(chip->irq, chip);
+
+out_free_chip:
+       i2c_set_clientdata(client, NULL);
+       kfree(chip);
+
+       return ret;
+}
+
+static int __devexit adp5520_remove(struct i2c_client *client)
+{
+       struct adp5520_chip *chip = dev_get_drvdata(&client->dev);
+
+       if (chip->irq)
+               free_irq(chip->irq, chip);
+
+       adp5520_remove_subdevs(chip);
+       adp5520_write(chip->dev, ADP5520_MODE_STATUS, 0);
+       i2c_set_clientdata(client, NULL);
+       kfree(chip);
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int adp5520_suspend(struct i2c_client *client,
+                                pm_message_t state)
+{
+       struct adp5520_chip *chip = dev_get_drvdata(&client->dev);
+
+       adp5520_clr_bits(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY);
+       return 0;
+}
+
+static int adp5520_resume(struct i2c_client *client)
+{
+       struct adp5520_chip *chip = dev_get_drvdata(&client->dev);
+
+       adp5520_set_bits(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY);
+       return 0;
+}
+#else
+#define adp5520_suspend        NULL
+#define adp5520_resume NULL
+#endif
+
+static const struct i2c_device_id adp5520_id[] = {
+       { "pmic-adp5520", ID_ADP5520 },
+       { "pmic-adp5501", ID_ADP5501 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, adp5520_id);
+
+static struct i2c_driver adp5520_driver = {
+       .driver = {
+               .name   = "adp5520",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = adp5520_probe,
+       .remove         = __devexit_p(adp5520_remove),
+       .suspend        = adp5520_suspend,
+       .resume         = adp5520_resume,
+       .id_table       = adp5520_id,
+};
+
+static int __init adp5520_init(void)
+{
+       return i2c_add_driver(&adp5520_driver);
+}
+module_init(adp5520_init);
+
+static void __exit adp5520_exit(void)
+{
+       i2c_del_driver(&adp5520_driver);
+}
+module_exit(adp5520_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("ADP5520(01) PMIC-MFD Driver");
+MODULE_LICENSE("GPL");
index 63a2a6632106c3ad50a6ecbbb58e6ba80b11ba35..e22128c3e9a8a426825337eb5f2aadb5945f6ad2 100644 (file)
@@ -908,7 +908,7 @@ static int __init asic3_probe(struct platform_device *pdev)
        return ret;
 }
 
-static int asic3_remove(struct platform_device *pdev)
+static int __devexit asic3_remove(struct platform_device *pdev)
 {
        int ret;
        struct asic3 *asic = platform_get_drvdata(pdev);
index 8762889179763eb2a019c7867a72b1cbecd9dbad..df405af968fa2f1f1237b1b45a828249ecde65a1 100644 (file)
@@ -387,7 +387,6 @@ static int __devinit pcap_add_subdev(struct pcap_chip *pcap,
        pdev = platform_device_alloc(subdev->name, subdev->id);
        pdev->dev.parent = &pcap->spi->dev;
        pdev->dev.platform_data = subdev->platform_data;
-       platform_set_drvdata(pdev, pcap);
 
        return platform_device_add(pdev);
 }
index e354d2912ef13dc11eb059959faec1ebfd5a3430..a1ade2324ea903bccfab8a35f75fecaa9428f59e 100644 (file)
 /*
- * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
- *
- * This code is in parts based on wm8350-core.c and pcf50633-core.c
- *
- * Initial development of this code was funded by
- * Phytec Messtechnik GmbH, http://www.phytec.de
+ * Copyright 2009 Pengutronix
+ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
  *
- * 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.
+ * loosely based on an earlier driver that has
+ * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
  *
- * 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.
+ * 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/platform_device.h>
-#include <linux/mfd/mc13783.h>
-#include <linux/completion.h>
-#include <linux/interrupt.h>
-#include <linux/mfd/core.h>
-#include <linux/spi/spi.h>
-#include <linux/uaccess.h>
-#include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/irq.h>
+#include <linux/spi/spi.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/mc13783-private.h>
+
+#define MC13783_IRQSTAT0       0
+#define MC13783_IRQSTAT0_ADCDONEI      (1 << 0)
+#define MC13783_IRQSTAT0_ADCBISDONEI   (1 << 1)
+#define MC13783_IRQSTAT0_TSI           (1 << 2)
+#define MC13783_IRQSTAT0_WHIGHI                (1 << 3)
+#define MC13783_IRQSTAT0_WLOWI         (1 << 4)
+#define MC13783_IRQSTAT0_CHGDETI       (1 << 6)
+#define MC13783_IRQSTAT0_CHGOVI                (1 << 7)
+#define MC13783_IRQSTAT0_CHGREVI       (1 << 8)
+#define MC13783_IRQSTAT0_CHGSHORTI     (1 << 9)
+#define MC13783_IRQSTAT0_CCCVI         (1 << 10)
+#define MC13783_IRQSTAT0_CHGCURRI      (1 << 11)
+#define MC13783_IRQSTAT0_BPONI         (1 << 12)
+#define MC13783_IRQSTAT0_LOBATLI       (1 << 13)
+#define MC13783_IRQSTAT0_LOBATHI       (1 << 14)
+#define MC13783_IRQSTAT0_UDPI          (1 << 15)
+#define MC13783_IRQSTAT0_USBI          (1 << 16)
+#define MC13783_IRQSTAT0_IDI           (1 << 19)
+#define MC13783_IRQSTAT0_SE1I          (1 << 21)
+#define MC13783_IRQSTAT0_CKDETI                (1 << 22)
+#define MC13783_IRQSTAT0_UDMI          (1 << 23)
+
+#define MC13783_IRQMASK0       1
+#define MC13783_IRQMASK0_ADCDONEM      MC13783_IRQSTAT0_ADCDONEI
+#define MC13783_IRQMASK0_ADCBISDONEM   MC13783_IRQSTAT0_ADCBISDONEI
+#define MC13783_IRQMASK0_TSM           MC13783_IRQSTAT0_TSI
+#define MC13783_IRQMASK0_WHIGHM                MC13783_IRQSTAT0_WHIGHI
+#define MC13783_IRQMASK0_WLOWM         MC13783_IRQSTAT0_WLOWI
+#define MC13783_IRQMASK0_CHGDETM       MC13783_IRQSTAT0_CHGDETI
+#define MC13783_IRQMASK0_CHGOVM                MC13783_IRQSTAT0_CHGOVI
+#define MC13783_IRQMASK0_CHGREVM       MC13783_IRQSTAT0_CHGREVI
+#define MC13783_IRQMASK0_CHGSHORTM     MC13783_IRQSTAT0_CHGSHORTI
+#define MC13783_IRQMASK0_CCCVM         MC13783_IRQSTAT0_CCCVI
+#define MC13783_IRQMASK0_CHGCURRM      MC13783_IRQSTAT0_CHGCURRI
+#define MC13783_IRQMASK0_BPONM         MC13783_IRQSTAT0_BPONI
+#define MC13783_IRQMASK0_LOBATLM       MC13783_IRQSTAT0_LOBATLI
+#define MC13783_IRQMASK0_LOBATHM       MC13783_IRQSTAT0_LOBATHI
+#define MC13783_IRQMASK0_UDPM          MC13783_IRQSTAT0_UDPI
+#define MC13783_IRQMASK0_USBM          MC13783_IRQSTAT0_USBI
+#define MC13783_IRQMASK0_IDM           MC13783_IRQSTAT0_IDI
+#define MC13783_IRQMASK0_SE1M          MC13783_IRQSTAT0_SE1I
+#define MC13783_IRQMASK0_CKDETM                MC13783_IRQSTAT0_CKDETI
+#define MC13783_IRQMASK0_UDMM          MC13783_IRQSTAT0_UDMI
+
+#define MC13783_IRQSTAT1       3
+#define MC13783_IRQSTAT1_1HZI          (1 << 0)
+#define MC13783_IRQSTAT1_TODAI         (1 << 1)
+#define MC13783_IRQSTAT1_ONOFD1I       (1 << 3)
+#define MC13783_IRQSTAT1_ONOFD2I       (1 << 4)
+#define MC13783_IRQSTAT1_ONOFD3I       (1 << 5)
+#define MC13783_IRQSTAT1_SYSRSTI       (1 << 6)
+#define MC13783_IRQSTAT1_RTCRSTI       (1 << 7)
+#define MC13783_IRQSTAT1_PCI           (1 << 8)
+#define MC13783_IRQSTAT1_WARMI         (1 << 9)
+#define MC13783_IRQSTAT1_MEMHLDI       (1 << 10)
+#define MC13783_IRQSTAT1_PWRRDYI       (1 << 11)
+#define MC13783_IRQSTAT1_THWARNLI      (1 << 12)
+#define MC13783_IRQSTAT1_THWARNHI      (1 << 13)
+#define MC13783_IRQSTAT1_CLKI          (1 << 14)
+#define MC13783_IRQSTAT1_SEMAFI                (1 << 15)
+#define MC13783_IRQSTAT1_MC2BI         (1 << 17)
+#define MC13783_IRQSTAT1_HSDETI                (1 << 18)
+#define MC13783_IRQSTAT1_HSLI          (1 << 19)
+#define MC13783_IRQSTAT1_ALSPTHI       (1 << 20)
+#define MC13783_IRQSTAT1_AHSSHORTI     (1 << 21)
+
+#define MC13783_IRQMASK1       4
+#define MC13783_IRQMASK1_1HZM          MC13783_IRQSTAT1_1HZI
+#define MC13783_IRQMASK1_TODAM         MC13783_IRQSTAT1_TODAI
+#define MC13783_IRQMASK1_ONOFD1M       MC13783_IRQSTAT1_ONOFD1I
+#define MC13783_IRQMASK1_ONOFD2M       MC13783_IRQSTAT1_ONOFD2I
+#define MC13783_IRQMASK1_ONOFD3M       MC13783_IRQSTAT1_ONOFD3I
+#define MC13783_IRQMASK1_SYSRSTM       MC13783_IRQSTAT1_SYSRSTI
+#define MC13783_IRQMASK1_RTCRSTM       MC13783_IRQSTAT1_RTCRSTI
+#define MC13783_IRQMASK1_PCM           MC13783_IRQSTAT1_PCI
+#define MC13783_IRQMASK1_WARMM         MC13783_IRQSTAT1_WARMI
+#define MC13783_IRQMASK1_MEMHLDM       MC13783_IRQSTAT1_MEMHLDI
+#define MC13783_IRQMASK1_PWRRDYM       MC13783_IRQSTAT1_PWRRDYI
+#define MC13783_IRQMASK1_THWARNLM      MC13783_IRQSTAT1_THWARNLI
+#define MC13783_IRQMASK1_THWARNHM      MC13783_IRQSTAT1_THWARNHI
+#define MC13783_IRQMASK1_CLKM          MC13783_IRQSTAT1_CLKI
+#define MC13783_IRQMASK1_SEMAFM                MC13783_IRQSTAT1_SEMAFI
+#define MC13783_IRQMASK1_MC2BM         MC13783_IRQSTAT1_MC2BI
+#define MC13783_IRQMASK1_HSDETM                MC13783_IRQSTAT1_HSDETI
+#define MC13783_IRQMASK1_HSLM          MC13783_IRQSTAT1_HSLI
+#define MC13783_IRQMASK1_ALSPTHM       MC13783_IRQSTAT1_ALSPTHI
+#define MC13783_IRQMASK1_AHSSHORTM     MC13783_IRQSTAT1_AHSSHORTI
+
+#define MC13783_ADC1           44
+#define MC13783_ADC1_ADEN              (1 << 0)
+#define MC13783_ADC1_RAND              (1 << 1)
+#define MC13783_ADC1_ADSEL             (1 << 3)
+#define MC13783_ADC1_ASC               (1 << 20)
+#define MC13783_ADC1_ADTRIGIGN         (1 << 21)
+
+#define MC13783_NUMREGS 0x3f
+
+void mc13783_lock(struct mc13783 *mc13783)
+{
+       if (!mutex_trylock(&mc13783->lock)) {
+               dev_dbg(&mc13783->spidev->dev, "wait for %s from %pf\n",
+                               __func__, __builtin_return_address(0));
+
+               mutex_lock(&mc13783->lock);
+       }
+       dev_dbg(&mc13783->spidev->dev, "%s from %pf\n",
+                       __func__, __builtin_return_address(0));
+}
+EXPORT_SYMBOL(mc13783_lock);
 
-#define MC13783_MAX_REG_NUM    0x3f
-#define MC13783_FRAME_MASK     0x00ffffff
-#define MC13783_MAX_REG_NUM    0x3f
-#define MC13783_REG_NUM_SHIFT  0x19
-#define MC13783_WRITE_BIT_SHIFT        31
+void mc13783_unlock(struct mc13783 *mc13783)
+{
+       dev_dbg(&mc13783->spidev->dev, "%s from %pf\n",
+                       __func__, __builtin_return_address(0));
+       mutex_unlock(&mc13783->lock);
+}
+EXPORT_SYMBOL(mc13783_unlock);
 
-static inline int spi_rw(struct spi_device *spi, u8 * buf, size_t len)
+#define MC13783_REGOFFSET_SHIFT 25
+int mc13783_reg_read(struct mc13783 *mc13783, unsigned int offset, u32 *val)
 {
-       struct spi_transfer t = {
-               .tx_buf = (const void *)buf,
-               .rx_buf = buf,
-               .len = len,
-               .cs_change = 0,
-               .delay_usecs = 0,
-       };
+       struct spi_transfer t;
        struct spi_message m;
+       int ret;
+
+       BUG_ON(!mutex_is_locked(&mc13783->lock));
+
+       if (offset > MC13783_NUMREGS)
+               return -EINVAL;
+
+       *val = offset << MC13783_REGOFFSET_SHIFT;
+
+       memset(&t, 0, sizeof(t));
+
+       t.tx_buf = val;
+       t.rx_buf = val;
+       t.len = sizeof(u32);
 
        spi_message_init(&m);
        spi_message_add_tail(&t, &m);
-       if (spi_sync(spi, &m) != 0 || m.status != 0)
-               return -EINVAL;
-       return len - m.actual_length;
-}
 
-static int mc13783_read(struct mc13783 *mc13783, int reg_num, u32 *reg_val)
-{
-       unsigned int frame = 0;
-       int ret = 0;
+       ret = spi_sync(mc13783->spidev, &m);
 
-       if (reg_num > MC13783_MAX_REG_NUM)
-               return -EINVAL;
+       /* error in message.status implies error return from spi_sync */
+       BUG_ON(!ret && m.status);
 
-       frame |= reg_num << MC13783_REG_NUM_SHIFT;
+       if (ret)
+               return ret;
 
-       ret = spi_rw(mc13783->spi_device, (u8 *)&frame, 4);
+       *val &= 0xffffff;
 
-       *reg_val = frame & MC13783_FRAME_MASK;
+       dev_vdbg(&mc13783->spidev->dev, "[0x%02x] -> 0x%06x\n", offset, *val);
 
-       return ret;
+       return 0;
 }
+EXPORT_SYMBOL(mc13783_reg_read);
 
-static int mc13783_write(struct mc13783 *mc13783, int reg_num, u32 reg_val)
+int mc13783_reg_write(struct mc13783 *mc13783, unsigned int offset, u32 val)
 {
-       unsigned int frame = 0;
+       u32 buf;
+       struct spi_transfer t;
+       struct spi_message m;
+       int ret;
+
+       BUG_ON(!mutex_is_locked(&mc13783->lock));
 
-       if (reg_num > MC13783_MAX_REG_NUM)
+       dev_vdbg(&mc13783->spidev->dev, "[0x%02x] <- 0x%06x\n", offset, val);
+
+       if (offset > MC13783_NUMREGS || val > 0xffffff)
                return -EINVAL;
 
-       frame |= (1 << MC13783_WRITE_BIT_SHIFT);
-       frame |= reg_num << MC13783_REG_NUM_SHIFT;
-       frame |= reg_val & MC13783_FRAME_MASK;
+       buf = 1 << 31 | offset << MC13783_REGOFFSET_SHIFT | val;
+
+       memset(&t, 0, sizeof(t));
 
-       return spi_rw(mc13783->spi_device, (u8 *)&frame, 4);
+       t.tx_buf = &buf;
+       t.rx_buf = &buf;
+       t.len = sizeof(u32);
+
+       spi_message_init(&m);
+       spi_message_add_tail(&t, &m);
+
+       ret = spi_sync(mc13783->spidev, &m);
+
+       BUG_ON(!ret && m.status);
+
+       if (ret)
+               return ret;
+
+       return 0;
 }
+EXPORT_SYMBOL(mc13783_reg_write);
 
-int mc13783_reg_read(struct mc13783 *mc13783, int reg_num, u32 *reg_val)
+int mc13783_reg_rmw(struct mc13783 *mc13783, unsigned int offset,
+               u32 mask, u32 val)
 {
        int ret;
+       u32 valread;
 
-       mutex_lock(&mc13783->io_lock);
-       ret = mc13783_read(mc13783, reg_num, reg_val);
-       mutex_unlock(&mc13783->io_lock);
+       BUG_ON(val & ~mask);
 
-       return ret;
+       ret = mc13783_reg_read(mc13783, offset, &valread);
+       if (ret)
+               return ret;
+
+       valread = (valread & ~mask) | val;
+
+       return mc13783_reg_write(mc13783, offset, valread);
 }
-EXPORT_SYMBOL_GPL(mc13783_reg_read);
+EXPORT_SYMBOL(mc13783_reg_rmw);
 
-int mc13783_reg_write(struct mc13783 *mc13783, int reg_num, u32 reg_val)
+int mc13783_mask(struct mc13783 *mc13783, int irq)
 {
        int ret;
+       unsigned int offmask = irq < 24 ? MC13783_IRQMASK0 : MC13783_IRQMASK1;
+       u32 irqbit = 1 << (irq < 24 ? irq : irq - 24);
+       u32 mask;
 
-       mutex_lock(&mc13783->io_lock);
-       ret = mc13783_write(mc13783, reg_num, reg_val);
-       mutex_unlock(&mc13783->io_lock);
+       if (irq < 0 || irq >= MC13783_NUM_IRQ)
+               return -EINVAL;
 
-       return ret;
+       ret = mc13783_reg_read(mc13783, offmask, &mask);
+       if (ret)
+               return ret;
+
+       if (mask & irqbit)
+               /* already masked */
+               return 0;
+
+       return mc13783_reg_write(mc13783, offmask, mask | irqbit);
 }
-EXPORT_SYMBOL_GPL(mc13783_reg_write);
+EXPORT_SYMBOL(mc13783_mask);
 
-/**
- * mc13783_set_bits - Bitmask write
- *
- * @mc13783: Pointer to mc13783 control structure
- * @reg:    Register to access
- * @mask:   Mask of bits to change
- * @val:    Value to set for masked bits
- */
-int mc13783_set_bits(struct mc13783 *mc13783, int reg, u32 mask, u32 val)
+int mc13783_unmask(struct mc13783 *mc13783, int irq)
 {
-       u32 tmp;
        int ret;
+       unsigned int offmask = irq < 24 ? MC13783_IRQMASK0 : MC13783_IRQMASK1;
+       u32 irqbit = 1 << (irq < 24 ? irq : irq - 24);
+       u32 mask;
 
-       mutex_lock(&mc13783->io_lock);
+       if (irq < 0 || irq >= MC13783_NUM_IRQ)
+               return -EINVAL;
 
-       ret = mc13783_read(mc13783, reg, &tmp);
-       tmp = (tmp & ~mask) | val;
-       if (ret == 0)
-               ret = mc13783_write(mc13783, reg, tmp);
+       ret = mc13783_reg_read(mc13783, offmask, &mask);
+       if (ret)
+               return ret;
 
-       mutex_unlock(&mc13783->io_lock);
+       if (!(mask & irqbit))
+               /* already unmasked */
+               return 0;
 
-       return ret;
+       return mc13783_reg_write(mc13783, offmask, mask & ~irqbit);
 }
-EXPORT_SYMBOL_GPL(mc13783_set_bits);
+EXPORT_SYMBOL(mc13783_unmask);
 
-int mc13783_register_irq(struct mc13783 *mc13783, int irq,
-               void (*handler) (int, void *), void *data)
+int mc13783_irq_request_nounmask(struct mc13783 *mc13783, int irq,
+               irq_handler_t handler, const char *name, void *dev)
 {
-       if (irq < 0 || irq > MC13783_NUM_IRQ || !handler)
+       BUG_ON(!mutex_is_locked(&mc13783->lock));
+       BUG_ON(!handler);
+
+       if (irq < 0 || irq >= MC13783_NUM_IRQ)
                return -EINVAL;
 
-       if (WARN_ON(mc13783->irq_handler[irq].handler))
+       if (mc13783->irqhandler[irq])
                return -EBUSY;
 
-       mutex_lock(&mc13783->io_lock);
-       mc13783->irq_handler[irq].handler = handler;
-       mc13783->irq_handler[irq].data = data;
-       mutex_unlock(&mc13783->io_lock);
+       mc13783->irqhandler[irq] = handler;
+       mc13783->irqdata[irq] = dev;
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(mc13783_register_irq);
+EXPORT_SYMBOL(mc13783_irq_request_nounmask);
 
-int mc13783_free_irq(struct mc13783 *mc13783, int irq)
+int mc13783_irq_request(struct mc13783 *mc13783, int irq,
+               irq_handler_t handler, const char *name, void *dev)
 {
-       if (irq < 0 || irq > MC13783_NUM_IRQ)
+       int ret;
+
+       ret = mc13783_irq_request_nounmask(mc13783, irq, handler, name, dev);
+       if (ret)
+               return ret;
+
+       ret = mc13783_unmask(mc13783, irq);
+       if (ret) {
+               mc13783->irqhandler[irq] = NULL;
+               mc13783->irqdata[irq] = NULL;
+               return ret;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(mc13783_irq_request);
+
+int mc13783_irq_free(struct mc13783 *mc13783, int irq, void *dev)
+{
+       int ret;
+       BUG_ON(!mutex_is_locked(&mc13783->lock));
+
+       if (irq < 0 || irq >= MC13783_NUM_IRQ || !mc13783->irqhandler[irq] ||
+                       mc13783->irqdata[irq] != dev)
                return -EINVAL;
 
-       mutex_lock(&mc13783->io_lock);
-       mc13783->irq_handler[irq].handler = NULL;
-       mutex_unlock(&mc13783->io_lock);
+       ret = mc13783_mask(mc13783, irq);
+       if (ret)
+               return ret;
+
+       mc13783->irqhandler[irq] = NULL;
+       mc13783->irqdata[irq] = NULL;
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(mc13783_free_irq);
+EXPORT_SYMBOL(mc13783_irq_free);
 
-static void mc13783_irq_work(struct work_struct *work)
+static inline irqreturn_t mc13783_irqhandler(struct mc13783 *mc13783, int irq)
 {
-       struct mc13783 *mc13783 = container_of(work, struct mc13783, work);
-       int i;
-       unsigned int adc_sts;
-
-       /* check if the adc has finished any completion */
-       mc13783_reg_read(mc13783, MC13783_REG_INTERRUPT_STATUS_0, &adc_sts);
-       mc13783_reg_write(mc13783, MC13783_REG_INTERRUPT_STATUS_0,
-                       adc_sts & MC13783_INT_STAT_ADCDONEI);
-
-       if (adc_sts & MC13783_INT_STAT_ADCDONEI)
-               complete_all(&mc13783->adc_done);
-
-       for (i = 0; i < MC13783_NUM_IRQ; i++)
-               if (mc13783->irq_handler[i].handler)
-                       mc13783->irq_handler[i].handler(i,
-                                       mc13783->irq_handler[i].data);
-       enable_irq(mc13783->irq);
+       return mc13783->irqhandler[irq](irq, mc13783->irqdata[irq]);
 }
 
-static irqreturn_t mc13783_interrupt(int irq, void *dev_id)
+int mc13783_ackirq(struct mc13783 *mc13783, int irq)
 {
-       struct mc13783 *mc13783 = dev_id;
+       unsigned int offstat = irq < 24 ? MC13783_IRQSTAT0 : MC13783_IRQSTAT1;
+       unsigned int val = 1 << (irq < 24 ? irq : irq - 24);
 
-       disable_irq_nosync(irq);
+       BUG_ON(irq < 0 || irq >= MC13783_NUM_IRQ);
 
-       schedule_work(&mc13783->work);
-       return IRQ_HANDLED;
+       return mc13783_reg_write(mc13783, offstat, val);
 }
+EXPORT_SYMBOL(mc13783_ackirq);
 
-/* set adc to ts interrupt mode, which generates touchscreen wakeup interrupt */
-static inline void mc13783_adc_set_ts_irq_mode(struct mc13783 *mc13783)
+/*
+ * returns: number of handled irqs or negative error
+ * locking: holds mc13783->lock
+ */
+static int mc13783_irq_handle(struct mc13783 *mc13783,
+               unsigned int offstat, unsigned int offmask, int baseirq)
 {
-       unsigned int reg_adc0, reg_adc1;
+       u32 stat, mask;
+       int ret = mc13783_reg_read(mc13783, offstat, &stat);
+       int num_handled = 0;
+
+       if (ret)
+               return ret;
+
+       ret = mc13783_reg_read(mc13783, offmask, &mask);
+       if (ret)
+               return ret;
+
+       while (stat & ~mask) {
+               int irq = __ffs(stat & ~mask);
+
+               stat &= ~(1 << irq);
+
+               if (likely(mc13783->irqhandler[baseirq + irq])) {
+                       irqreturn_t handled;
 
-       reg_adc0 = MC13783_ADC0_ADREFEN | MC13783_ADC0_ADREFMODE
-                       | MC13783_ADC0_TSMOD0;
-       reg_adc1 = MC13783_ADC1_ADEN | MC13783_ADC1_ADTRIGIGN;
+                       handled = mc13783_irqhandler(mc13783, baseirq + irq);
+                       if (handled == IRQ_HANDLED)
+                               num_handled++;
+               } else {
+                       dev_err(&mc13783->spidev->dev,
+                                       "BUG: irq %u but no handler\n",
+                                       baseirq + irq);
 
-       mc13783_reg_write(mc13783, MC13783_REG_ADC_0, reg_adc0);
-       mc13783_reg_write(mc13783, MC13783_REG_ADC_1, reg_adc1);
+                       mask |= 1 << irq;
+
+                       ret = mc13783_reg_write(mc13783, offmask, mask);
+               }
+       }
+
+       return num_handled;
 }
 
+static irqreturn_t mc13783_irq_thread(int irq, void *data)
+{
+       struct mc13783 *mc13783 = data;
+       irqreturn_t ret;
+       int handled = 0;
+
+       mc13783_lock(mc13783);
+
+       ret = mc13783_irq_handle(mc13783, MC13783_IRQSTAT0,
+                       MC13783_IRQMASK0, MC13783_IRQ_ADCDONE);
+       if (ret > 0)
+               handled = 1;
+
+       ret = mc13783_irq_handle(mc13783, MC13783_IRQSTAT1,
+                       MC13783_IRQMASK1, MC13783_IRQ_1HZ);
+       if (ret > 0)
+               handled = 1;
+
+       mc13783_unlock(mc13783);
+
+       return IRQ_RETVAL(handled);
+}
+
+#define MC13783_ADC1_CHAN0_SHIFT       5
+#define MC13783_ADC1_CHAN1_SHIFT       8
+
+struct mc13783_adcdone_data {
+       struct mc13783 *mc13783;
+       struct completion done;
+};
+
+static irqreturn_t mc13783_handler_adcdone(int irq, void *data)
+{
+       struct mc13783_adcdone_data *adcdone_data = data;
+
+       mc13783_ackirq(adcdone_data->mc13783, irq);
+
+       complete_all(&adcdone_data->done);
+
+       return IRQ_HANDLED;
+}
+
+#define MC13783_ADC_WORKING (1 << 16)
+
 int mc13783_adc_do_conversion(struct mc13783 *mc13783, unsigned int mode,
                unsigned int channel, unsigned int *sample)
 {
-       unsigned int reg_adc0, reg_adc1;
-       int i;
+       u32 adc0, adc1, old_adc0;
+       int i, ret;
+       struct mc13783_adcdone_data adcdone_data = {
+               .mc13783 = mc13783,
+       };
+       init_completion(&adcdone_data.done);
+
+       dev_dbg(&mc13783->spidev->dev, "%s\n", __func__);
+
+       mc13783_lock(mc13783);
+
+       if (mc13783->flags & MC13783_ADC_WORKING) {
+               ret = -EBUSY;
+               goto out;
+       }
+
+       mc13783->flags |= MC13783_ADC_WORKING;
 
-       mutex_lock(&mc13783->adc_conv_lock);
+       mc13783_reg_read(mc13783, MC13783_ADC0, &old_adc0);
 
-       /* set up auto incrementing anyway to make quick read */
-       reg_adc0 =  MC13783_ADC0_ADINC1 | MC13783_ADC0_ADINC2;
-       /* enable the adc, ignore external triggering and set ASC to trigger
-        * conversion */
-       reg_adc1 =  MC13783_ADC1_ADEN | MC13783_ADC1_ADTRIGIGN
-               | MC13783_ADC1_ASC;
+       adc0 = MC13783_ADC0_ADINC1 | MC13783_ADC0_ADINC2;
+       adc1 = MC13783_ADC1_ADEN | MC13783_ADC1_ADTRIGIGN | MC13783_ADC1_ASC;
 
-       /* setup channel number */
        if (channel > 7)
-               reg_adc1 |= MC13783_ADC1_ADSEL;
+               adc1 |= MC13783_ADC1_ADSEL;
 
        switch (mode) {
        case MC13783_ADC_MODE_TS:
-               /* enables touch screen reference mode and set touchscreen mode
-                * to position mode */
-               reg_adc0 |= MC13783_ADC0_ADREFEN | MC13783_ADC0_ADREFMODE
-                       | MC13783_ADC0_TSMOD0 | MC13783_ADC0_TSMOD1;
-               reg_adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT;
+               adc0 |= MC13783_ADC0_ADREFEN | MC13783_ADC0_TSMOD0 |
+                       MC13783_ADC0_TSMOD1;
+               adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT;
                break;
+
        case MC13783_ADC_MODE_SINGLE_CHAN:
-               reg_adc1 |= (channel & 0x7) << MC13783_ADC1_CHAN0_SHIFT;
-               reg_adc1 |= MC13783_ADC1_RAND;
+               adc0 |= old_adc0 & MC13783_ADC0_TSMOD_MASK;
+               adc1 |= (channel & 0x7) << MC13783_ADC1_CHAN0_SHIFT;
+               adc1 |= MC13783_ADC1_RAND;
                break;
+
        case MC13783_ADC_MODE_MULT_CHAN:
-               reg_adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT;
+               adc0 |= old_adc0 & MC13783_ADC0_TSMOD_MASK;
+               adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT;
                break;
+
        default:
+               mc13783_unlock(mc13783);
                return -EINVAL;
        }
 
-       mc13783_reg_write(mc13783, MC13783_REG_ADC_0, reg_adc0);
-       mc13783_reg_write(mc13783, MC13783_REG_ADC_1, reg_adc1);
+       dev_dbg(&mc13783->spidev->dev, "%s: request irq\n", __func__);
+       mc13783_irq_request(mc13783, MC13783_IRQ_ADCDONE,
+                       mc13783_handler_adcdone, __func__, &adcdone_data);
+       mc13783_ackirq(mc13783, MC13783_IRQ_ADCDONE);
 
-       wait_for_completion_interruptible(&mc13783->adc_done);
+       mc13783_reg_write(mc13783, MC13783_REG_ADC_0, adc0);
+       mc13783_reg_write(mc13783, MC13783_REG_ADC_1, adc1);
 
-       for (i = 0; i < 4; i++)
-               mc13783_reg_read(mc13783, MC13783_REG_ADC_2, &sample[i]);
+       mc13783_unlock(mc13783);
 
-       if (mc13783->ts_active)
-               mc13783_adc_set_ts_irq_mode(mc13783);
+       ret = wait_for_completion_interruptible_timeout(&adcdone_data.done, HZ);
 
-       mutex_unlock(&mc13783->adc_conv_lock);
+       if (!ret)
+               ret = -ETIMEDOUT;
 
-       return 0;
+       mc13783_lock(mc13783);
+
+       mc13783_irq_free(mc13783, MC13783_IRQ_ADCDONE, &adcdone_data);
+
+       if (ret > 0)
+               for (i = 0; i < 4; ++i) {
+                       ret = mc13783_reg_read(mc13783,
+                                       MC13783_REG_ADC_2, &sample[i]);
+                       if (ret)
+                               break;
+               }
+
+       if (mode == MC13783_ADC_MODE_TS)
+               /* restore TSMOD */
+               mc13783_reg_write(mc13783, MC13783_REG_ADC_0, old_adc0);
+
+       mc13783->flags &= ~MC13783_ADC_WORKING;
+out:
+       mc13783_unlock(mc13783);
+
+       return ret;
 }
 EXPORT_SYMBOL_GPL(mc13783_adc_do_conversion);
 
-void mc13783_adc_set_ts_status(struct mc13783 *mc13783, unsigned int status)
+static int mc13783_add_subdevice_pdata(struct mc13783 *mc13783,
+               const char *name, void *pdata, size_t pdata_size)
 {
-       mc13783->ts_active = status;
+       struct mfd_cell cell = {
+               .name = name,
+               .platform_data = pdata,
+               .data_size = pdata_size,
+       };
+
+       return mfd_add_devices(&mc13783->spidev->dev, -1, &cell, 1, NULL, 0);
+}
+
+static int mc13783_add_subdevice(struct mc13783 *mc13783, const char *name)
+{
+       return mc13783_add_subdevice_pdata(mc13783, name, NULL, 0);
 }
-EXPORT_SYMBOL_GPL(mc13783_adc_set_ts_status);
 
 static int mc13783_check_revision(struct mc13783 *mc13783)
 {
        u32 rev_id, rev1, rev2, finid, icid;
 
-       mc13783_read(mc13783, MC13783_REG_REVISION, &rev_id);
+       mc13783_reg_read(mc13783, MC13783_REG_REVISION, &rev_id);
 
        rev1 = (rev_id & 0x018) >> 3;
        rev2 = (rev_id & 0x007);
@@ -292,38 +555,24 @@ static int mc13783_check_revision(struct mc13783 *mc13783)
                rev1 = 3;
 
        if (rev1 == 0 || icid != 2) {
-               dev_err(mc13783->dev, "No MC13783 detected.\n");
+               dev_err(&mc13783->spidev->dev, "No MC13783 detected.\n");
                return -ENODEV;
        }
 
-       mc13783->revision = ((rev1 * 10) + rev2);
-       dev_info(mc13783->dev, "MC13783 Rev %d.%d FinVer %x detected\n", rev1,
-              rev2, finid);
+       dev_info(&mc13783->spidev->dev,
+                       "MC13783 Rev %d.%d FinVer %x detected\n",
+                       rev1, rev2, finid);
 
        return 0;
 }
 
-/*
- * Register a client device.  This is non-fatal since there is no need to
- * fail the entire device init due to a single platform device failing.
- */
-static void mc13783_client_dev_register(struct mc13783 *mc13783,
-                                      const char *name)
-{
-       struct mfd_cell cell = {};
-
-       cell.name = name;
-
-       mfd_add_devices(mc13783->dev, -1, &cell, 1, NULL, 0);
-}
-
-static int __devinit mc13783_probe(struct spi_device *spi)
+static int mc13783_probe(struct spi_device *spi)
 {
        struct mc13783 *mc13783;
-       struct mc13783_platform_data *pdata = spi->dev.platform_data;
+       struct mc13783_platform_data *pdata = dev_get_platdata(&spi->dev);
        int ret;
 
-       mc13783 = kzalloc(sizeof(struct mc13783), GFP_KERNEL);
+       mc13783 = kzalloc(sizeof(*mc13783), GFP_KERNEL);
        if (!mc13783)
                return -ENOMEM;
 
@@ -332,96 +581,104 @@ static int __devinit mc13783_probe(struct spi_device *spi)
        spi->bits_per_word = 32;
        spi_setup(spi);
 
-       mc13783->spi_device = spi;
-       mc13783->dev = &spi->dev;
-       mc13783->irq = spi->irq;
+       mc13783->spidev = spi;
+
+       mutex_init(&mc13783->lock);
+       mc13783_lock(mc13783);
+
+       ret = mc13783_check_revision(mc13783);
+       if (ret)
+               goto err_revision;
+
+       /* mask all irqs */
+       ret = mc13783_reg_write(mc13783, MC13783_IRQMASK0, 0x00ffffff);
+       if (ret)
+               goto err_mask;
 
-       INIT_WORK(&mc13783->work, mc13783_irq_work);
-       mutex_init(&mc13783->io_lock);
-       mutex_init(&mc13783->adc_conv_lock);
-       init_completion(&mc13783->adc_done);
+       ret = mc13783_reg_write(mc13783, MC13783_IRQMASK1, 0x00ffffff);
+       if (ret)
+               goto err_mask;
+
+       ret = request_threaded_irq(spi->irq, NULL, mc13783_irq_thread,
+                       IRQF_ONESHOT | IRQF_TRIGGER_HIGH, "mc13783", mc13783);
+
+       if (ret) {
+err_mask:
+err_revision:
+               mutex_unlock(&mc13783->lock);
+               dev_set_drvdata(&spi->dev, NULL);
+               kfree(mc13783);
+               return ret;
+       }
 
+       /* This should go away (BEGIN) */
        if (pdata) {
                mc13783->flags = pdata->flags;
                mc13783->regulators = pdata->regulators;
                mc13783->num_regulators = pdata->num_regulators;
        }
+       /* This should go away (END) */
 
-       if (mc13783_check_revision(mc13783)) {
-               ret = -ENODEV;
-               goto err_out;
+       if (pdata->flags & MC13783_USE_ADC)
+               mc13783_add_subdevice(mc13783, "mc13783-adc");
+
+       if (pdata->flags & MC13783_USE_CODEC)
+               mc13783_add_subdevice(mc13783, "mc13783-codec");
+
+       if (pdata->flags & MC13783_USE_REGULATOR) {
+               struct mc13783_regulator_platform_data regulator_pdata = {
+                       .num_regulators = pdata->num_regulators,
+                       .regulators = pdata->regulators,
+               };
+
+               mc13783_add_subdevice_pdata(mc13783, "mc13783-regulator",
+                               &regulator_pdata, sizeof(regulator_pdata));
        }
 
-       /* clear and mask all interrupts */
-       mc13783_reg_write(mc13783, MC13783_REG_INTERRUPT_STATUS_0, 0x00ffffff);
-       mc13783_reg_write(mc13783, MC13783_REG_INTERRUPT_MASK_0, 0x00ffffff);
-       mc13783_reg_write(mc13783, MC13783_REG_INTERRUPT_STATUS_1, 0x00ffffff);
-       mc13783_reg_write(mc13783, MC13783_REG_INTERRUPT_MASK_1, 0x00ffffff);
+       if (pdata->flags & MC13783_USE_RTC)
+               mc13783_add_subdevice(mc13783, "mc13783-rtc");
 
-       /* unmask adcdone interrupts */
-       mc13783_set_bits(mc13783, MC13783_REG_INTERRUPT_MASK_0,
-                       MC13783_INT_MASK_ADCDONEM, 0);
+       if (pdata->flags & MC13783_USE_TOUCHSCREEN)
+               mc13783_add_subdevice(mc13783, "mc13783-ts");
 
-       ret = request_irq(mc13783->irq, mc13783_interrupt,
-                       IRQF_DISABLED | IRQF_TRIGGER_HIGH, "mc13783",
-                       mc13783);
-       if (ret)
-               goto err_out;
-
-       if (mc13783->flags & MC13783_USE_CODEC)
-               mc13783_client_dev_register(mc13783, "mc13783-codec");
-       if (mc13783->flags & MC13783_USE_ADC)
-               mc13783_client_dev_register(mc13783, "mc13783-adc");
-       if (mc13783->flags & MC13783_USE_RTC)
-               mc13783_client_dev_register(mc13783, "mc13783-rtc");
-       if (mc13783->flags & MC13783_USE_REGULATOR)
-               mc13783_client_dev_register(mc13783, "mc13783-regulator");
-       if (mc13783->flags & MC13783_USE_TOUCHSCREEN)
-               mc13783_client_dev_register(mc13783, "mc13783-ts");
+       mc13783_unlock(mc13783);
 
        return 0;
-
-err_out:
-       kfree(mc13783);
-       return ret;
 }
 
 static int __devexit mc13783_remove(struct spi_device *spi)
 {
-       struct mc13783 *mc13783;
+       struct mc13783 *mc13783 = dev_get_drvdata(&spi->dev);
 
-       mc13783 = dev_get_drvdata(&spi->dev);
-
-       free_irq(mc13783->irq, mc13783);
+       free_irq(mc13783->spidev->irq, mc13783);
 
        mfd_remove_devices(&spi->dev);
 
        return 0;
 }
 
-static struct spi_driver pmic_driver = {
+static struct spi_driver mc13783_driver = {
        .driver = {
-                  .name = "mc13783",
-                  .bus = &spi_bus_type,
-                  .owner = THIS_MODULE,
+               .name = "mc13783",
+               .bus = &spi_bus_type,
+               .owner = THIS_MODULE,
        },
        .probe = mc13783_probe,
        .remove = __devexit_p(mc13783_remove),
 };
 
-static int __init pmic_init(void)
+static int __init mc13783_init(void)
 {
-       return spi_register_driver(&pmic_driver);
+       return spi_register_driver(&mc13783_driver);
 }
-subsys_initcall(pmic_init);
+subsys_initcall(mc13783_init);
 
-static void __exit pmic_exit(void)
+static void __exit mc13783_exit(void)
 {
-       spi_unregister_driver(&pmic_driver);
+       spi_unregister_driver(&mc13783_driver);
 }
-module_exit(pmic_exit);
-
-MODULE_DESCRIPTION("Core/Protocol driver for Freescale MC13783 PMIC");
-MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
-MODULE_LICENSE("GPL");
+module_exit(mc13783_exit);
 
+MODULE_DESCRIPTION("Core driver for Freescale MC13783 PMIC");
+MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
+MODULE_LICENSE("GPL v2");
index 3d31e97d6a4553ab18f1752deec8ef5a76ce12de..6d2e8466df1dd804d2943144f9a8564309f76f96 100644 (file)
@@ -209,17 +209,16 @@ static void pcf50633_adc_irq(int irq, void *data)
 
 static int __devinit pcf50633_adc_probe(struct platform_device *pdev)
 {
-       struct pcf50633_subdev_pdata *pdata = pdev->dev.platform_data;
        struct pcf50633_adc *adc;
 
        adc = kzalloc(sizeof(*adc), GFP_KERNEL);
        if (!adc)
                return -ENOMEM;
 
-       adc->pcf = pdata->pcf;
+       adc->pcf = dev_to_pcf50633(pdev->dev.parent);
        platform_set_drvdata(pdev, adc);
 
-       pcf50633_register_irq(pdata->pcf, PCF50633_IRQ_ADCRDY,
+       pcf50633_register_irq(adc->pcf, PCF50633_IRQ_ADCRDY,
                                        pcf50633_adc_irq, adc);
 
        mutex_init(&adc->queue_mutex);
index d26d7747175ef107c9a34d08f44fab4d692114a7..03dcc92007070605b2ec0e7f7a8164eeca00183a 100644 (file)
@@ -290,7 +290,7 @@ out:
 
 int pcf50633_irq_mask(struct pcf50633 *pcf, int irq)
 {
-       dev_info(pcf->dev, "Masking IRQ %d\n", irq);
+       dev_dbg(pcf->dev, "Masking IRQ %d\n", irq);
 
        return __pcf50633_irq_mask_set(pcf, irq, 1);
 }
@@ -298,7 +298,7 @@ EXPORT_SYMBOL_GPL(pcf50633_irq_mask);
 
 int pcf50633_irq_unmask(struct pcf50633 *pcf, int irq)
 {
-       dev_info(pcf->dev, "Unmasking IRQ %d\n", irq);
+       dev_dbg(pcf->dev, "Unmasking IRQ %d\n", irq);
 
        return __pcf50633_irq_mask_set(pcf, irq, 0);
 }
@@ -345,6 +345,9 @@ static void pcf50633_irq_worker(struct work_struct *work)
                goto out;
        }
 
+       /* defeat 8s death from lowsys on A5 */
+       pcf50633_reg_write(pcf, PCF50633_REG_OOCSHDWN,  0x04);
+
        /* We immediately read the usb and adapter status. We thus make sure
         * only of USBINS/USBREM IRQ handlers are called */
        if (pcf_int[0] & (PCF50633_INT1_USBINS | PCF50633_INT1_USBREM)) {
@@ -453,7 +456,6 @@ static void
 pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name,
                                                struct platform_device **pdev)
 {
-       struct pcf50633_subdev_pdata *subdev_pdata;
        int ret;
 
        *pdev = platform_device_alloc(name, -1);
@@ -462,15 +464,6 @@ pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name,
                return;
        }
 
-       subdev_pdata = kmalloc(sizeof(*subdev_pdata), GFP_KERNEL);
-       if (!subdev_pdata) {
-               dev_err(pcf->dev, "Error allocating subdev pdata\n");
-               platform_device_put(*pdev);
-       }
-
-       subdev_pdata->pcf = pcf;
-       platform_device_add_data(*pdev, subdev_pdata, sizeof(*subdev_pdata));
-
        (*pdev)->dev.parent = pcf->dev;
 
        ret = platform_device_add(*pdev);
@@ -482,13 +475,13 @@ pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name,
 }
 
 #ifdef CONFIG_PM
-static int pcf50633_suspend(struct device *dev, pm_message_t state)
+static int pcf50633_suspend(struct i2c_client *client, pm_message_t state)
 {
        struct pcf50633 *pcf;
        int ret = 0, i;
        u8 res[5];
 
-       pcf = dev_get_drvdata(dev);
+       pcf = i2c_get_clientdata(client);
 
        /* Make sure our interrupt handlers are not called
         * henceforth */
@@ -523,12 +516,12 @@ out:
        return ret;
 }
 
-static int pcf50633_resume(struct device *dev)
+static int pcf50633_resume(struct i2c_client *client)
 {
        struct pcf50633 *pcf;
        int ret;
 
-       pcf = dev_get_drvdata(dev);
+       pcf = i2c_get_clientdata(client);
 
        /* Write the saved mask registers */
        ret = pcf50633_write_block(pcf, PCF50633_REG_INT1M,
@@ -560,9 +553,14 @@ static int __devinit pcf50633_probe(struct i2c_client *client,
 {
        struct pcf50633 *pcf;
        struct pcf50633_platform_data *pdata = client->dev.platform_data;
-       int i, ret = 0;
+       int i, ret;
        int version, variant;
 
+       if (!client->irq) {
+               dev_err(&client->dev, "Missing IRQ\n");
+               return -ENOENT;
+       }
+
        pcf = kzalloc(sizeof(*pcf), GFP_KERNEL);
        if (!pcf)
                return -ENOMEM;
@@ -577,6 +575,12 @@ static int __devinit pcf50633_probe(struct i2c_client *client,
        pcf->irq = client->irq;
        pcf->work_queue = create_singlethread_workqueue("pcf50633");
 
+       if (!pcf->work_queue) {
+               dev_err(&client->dev, "Failed to alloc workqueue\n");
+               ret = -ENOMEM;
+               goto err_free;
+       }
+
        INIT_WORK(&pcf->irq_work, pcf50633_irq_worker);
 
        version = pcf50633_reg_read(pcf, 0);
@@ -584,7 +588,7 @@ static int __devinit pcf50633_probe(struct i2c_client *client,
        if (version < 0 || variant < 0) {
                dev_err(pcf->dev, "Unable to probe pcf50633\n");
                ret = -ENODEV;
-               goto err;
+               goto err_destroy_workqueue;
        }
 
        dev_info(pcf->dev, "Probed device version %d variant %d\n",
@@ -598,6 +602,14 @@ static int __devinit pcf50633_probe(struct i2c_client *client,
        pcf50633_reg_write(pcf, PCF50633_REG_INT4M, 0x00);
        pcf50633_reg_write(pcf, PCF50633_REG_INT5M, 0x00);
 
+       ret = request_irq(client->irq, pcf50633_irq,
+                                       IRQF_TRIGGER_LOW, "pcf50633", pcf);
+
+       if (ret) {
+               dev_err(pcf->dev, "Failed to request IRQ %d\n", ret);
+               goto err_destroy_workqueue;
+       }
+
        /* Create sub devices */
        pcf50633_client_dev_register(pcf, "pcf50633-input",
                                                &pcf->input_pdev);
@@ -613,31 +625,18 @@ static int __devinit pcf50633_probe(struct i2c_client *client,
 
                pdev = platform_device_alloc("pcf50633-regltr", i);
                if (!pdev) {
-                       dev_err(pcf->dev, "Cannot create regulator\n");
+                       dev_err(pcf->dev, "Cannot create regulator %d\n", i);
                        continue;
                }
 
                pdev->dev.parent = pcf->dev;
-               pdev->dev.platform_data = &pdata->reg_init_data[i];
-               dev_set_drvdata(&pdev->dev, pcf);
+               platform_device_add_data(pdev, &pdata->reg_init_data[i],
+                                       sizeof(pdata->reg_init_data[i]));
                pcf->regulator_pdev[i] = pdev;
 
                platform_device_add(pdev);
        }
 
-       if (client->irq) {
-               ret = request_irq(client->irq, pcf50633_irq,
-                               IRQF_TRIGGER_LOW, "pcf50633", pcf);
-
-               if (ret) {
-                       dev_err(pcf->dev, "Failed to request IRQ %d\n", ret);
-                       goto err;
-               }
-       } else {
-               dev_err(pcf->dev, "No IRQ configured\n");
-               goto err;
-       }
-
        if (enable_irq_wake(client->irq) < 0)
                dev_err(pcf->dev, "IRQ %u cannot be enabled as wake-up source"
                        "in this hardware revision", client->irq);
@@ -651,9 +650,12 @@ static int __devinit pcf50633_probe(struct i2c_client *client,
 
        return 0;
 
-err:
+err_destroy_workqueue:
        destroy_workqueue(pcf->work_queue);
+err_free:
+       i2c_set_clientdata(client, NULL);
        kfree(pcf);
+
        return ret;
 }
 
@@ -686,12 +688,12 @@ static struct i2c_device_id pcf50633_id_table[] = {
 static struct i2c_driver pcf50633_driver = {
        .driver = {
                .name   = "pcf50633",
-               .suspend = pcf50633_suspend,
-               .resume = pcf50633_resume,
        },
        .id_table = pcf50633_id_table,
        .probe = pcf50633_probe,
        .remove = __devexit_p(pcf50633_remove),
+       .suspend = pcf50633_suspend,
+       .resume = pcf50633_resume,
 };
 
 static int __init pcf50633_init(void)
index acf8b9d5f575fec8cfe3d2578ab909c0956ce178..e5955306c2fa3397d97c5dba149adf1c67213159 100644 (file)
@@ -637,7 +637,7 @@ static int tps65010_probe(struct i2c_client *client,
                                tps, DEBUG_FOPS);
 
        /* optionally register GPIOs */
-       if (board && board->base > 0) {
+       if (board && board->base != 0) {
                tps->outmask = board->outmask;
 
                tps->chip.label = client->name;
@@ -964,6 +964,34 @@ int tps65010_config_vregs1(unsigned value)
 }
 EXPORT_SYMBOL(tps65010_config_vregs1);
 
+int tps65010_config_vdcdc2(unsigned value)
+{
+       struct i2c_client *c;
+       int      status;
+
+       if (!the_tps)
+               return -ENODEV;
+
+       c = the_tps->client;
+       mutex_lock(&the_tps->lock);
+
+       pr_debug("%s: vdcdc2 0x%02x\n", DRIVER_NAME,
+                i2c_smbus_read_byte_data(c, TPS_VDCDC2));
+
+       status = i2c_smbus_write_byte_data(c, TPS_VDCDC2, value);
+
+       if (status != 0)
+               printk(KERN_ERR "%s: Failed to write vdcdc2 register\n",
+                       DRIVER_NAME);
+       else
+               pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME,
+                        i2c_smbus_read_byte_data(c, TPS_VDCDC2));
+
+       mutex_unlock(&the_tps->lock);
+       return status;
+}
+EXPORT_SYMBOL(tps65010_config_vdcdc2);
+
 /*-------------------------------------------------------------------------*/
 /* tps65013_set_low_pwr parameter:
  * mode: ON or OFF
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
new file mode 100644 (file)
index 0000000..2a76065
--- /dev/null
@@ -0,0 +1,1076 @@
+/*
+ * twl_core.c - driver for TWL4030/TWL5030/TWL60X0/TPS659x0 PM
+ * and audio CODEC devices
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * Modifications to defer interrupt handling to a kernel thread:
+ * Copyright (C) 2006 MontaVista Software, Inc.
+ *
+ * Based on tlv320aic23.c:
+ * Copyright (c) by Kai Svahn <kai.svahn@nokia.com>
+ *
+ * Code cleanup and modifications to IRQ handler.
+ * by syed khasim <x0khasim@ti.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/init.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+#include <linux/regulator/machine.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c/twl.h>
+
+#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+#include <plat/cpu.h>
+#endif
+
+/*
+ * The TWL4030 "Triton 2" is one of a family of a multi-function "Power
+ * Management and System Companion Device" chips originally designed for
+ * use in OMAP2 and OMAP 3 based systems.  Its control interfaces use I2C,
+ * often at around 3 Mbit/sec, including for interrupt handling.
+ *
+ * This driver core provides genirq support for the interrupts emitted,
+ * by the various modules, and exports register access primitives.
+ *
+ * FIXME this driver currently requires use of the first interrupt line
+ * (and associated registers).
+ */
+
+#define DRIVER_NAME                    "twl"
+
+#if defined(CONFIG_TWL4030_BCI_BATTERY) || \
+       defined(CONFIG_TWL4030_BCI_BATTERY_MODULE)
+#define twl_has_bci()          true
+#else
+#define twl_has_bci()          false
+#endif
+
+#if defined(CONFIG_KEYBOARD_TWL4030) || defined(CONFIG_KEYBOARD_TWL4030_MODULE)
+#define twl_has_keypad()       true
+#else
+#define twl_has_keypad()       false
+#endif
+
+#if defined(CONFIG_GPIO_TWL4030) || defined(CONFIG_GPIO_TWL4030_MODULE)
+#define twl_has_gpio() true
+#else
+#define twl_has_gpio() false
+#endif
+
+#if defined(CONFIG_REGULATOR_TWL4030) \
+       || defined(CONFIG_REGULATOR_TWL4030_MODULE)
+#define twl_has_regulator()    true
+#else
+#define twl_has_regulator()    false
+#endif
+
+#if defined(CONFIG_TWL4030_MADC) || defined(CONFIG_TWL4030_MADC_MODULE)
+#define twl_has_madc() true
+#else
+#define twl_has_madc() false
+#endif
+
+#ifdef CONFIG_TWL4030_POWER
+#define twl_has_power()        true
+#else
+#define twl_has_power()        false
+#endif
+
+#if defined(CONFIG_RTC_DRV_TWL4030) || defined(CONFIG_RTC_DRV_TWL4030_MODULE)
+#define twl_has_rtc()  true
+#else
+#define twl_has_rtc()  false
+#endif
+
+#if defined(CONFIG_TWL4030_USB) || defined(CONFIG_TWL4030_USB_MODULE)
+#define twl_has_usb()  true
+#else
+#define twl_has_usb()  false
+#endif
+
+#if defined(CONFIG_TWL4030_WATCHDOG) || \
+       defined(CONFIG_TWL4030_WATCHDOG_MODULE)
+#define twl_has_watchdog()        true
+#else
+#define twl_has_watchdog()        false
+#endif
+
+#if defined(CONFIG_TWL4030_CODEC) || defined(CONFIG_TWL4030_CODEC_MODULE)
+#define twl_has_codec()        true
+#else
+#define twl_has_codec()        false
+#endif
+
+/* Triton Core internal information (BEGIN) */
+
+/* Last - for index max*/
+#define TWL4030_MODULE_LAST            TWL4030_MODULE_SECURED_REG
+
+#define TWL_NUM_SLAVES         4
+
+#if defined(CONFIG_INPUT_TWL4030_PWRBUTTON) \
+       || defined(CONFIG_INPUT_TWL4030_PWBUTTON_MODULE)
+#define twl_has_pwrbutton()    true
+#else
+#define twl_has_pwrbutton()    false
+#endif
+
+#define SUB_CHIP_ID0 0
+#define SUB_CHIP_ID1 1
+#define SUB_CHIP_ID2 2
+#define SUB_CHIP_ID3 3
+
+#define TWL_MODULE_LAST TWL4030_MODULE_LAST
+
+/* Base Address defns for twl4030_map[] */
+
+/* subchip/slave 0 - USB ID */
+#define TWL4030_BASEADD_USB            0x0000
+
+/* subchip/slave 1 - AUD ID */
+#define TWL4030_BASEADD_AUDIO_VOICE    0x0000
+#define TWL4030_BASEADD_GPIO           0x0098
+#define TWL4030_BASEADD_INTBR          0x0085
+#define TWL4030_BASEADD_PIH            0x0080
+#define TWL4030_BASEADD_TEST           0x004C
+
+/* subchip/slave 2 - AUX ID */
+#define TWL4030_BASEADD_INTERRUPTS     0x00B9
+#define TWL4030_BASEADD_LED            0x00EE
+#define TWL4030_BASEADD_MADC           0x0000
+#define TWL4030_BASEADD_MAIN_CHARGE    0x0074
+#define TWL4030_BASEADD_PRECHARGE      0x00AA
+#define TWL4030_BASEADD_PWM0           0x00F8
+#define TWL4030_BASEADD_PWM1           0x00FB
+#define TWL4030_BASEADD_PWMA           0x00EF
+#define TWL4030_BASEADD_PWMB           0x00F1
+#define TWL4030_BASEADD_KEYPAD         0x00D2
+
+#define TWL5031_BASEADD_ACCESSORY      0x0074 /* Replaces Main Charge */
+#define TWL5031_BASEADD_INTERRUPTS     0x00B9 /* Different than TWL4030's
+                                                 one */
+
+/* subchip/slave 3 - POWER ID */
+#define TWL4030_BASEADD_BACKUP         0x0014
+#define TWL4030_BASEADD_INT            0x002E
+#define TWL4030_BASEADD_PM_MASTER      0x0036
+#define TWL4030_BASEADD_PM_RECEIVER    0x005B
+#define TWL4030_BASEADD_RTC            0x001C
+#define TWL4030_BASEADD_SECURED_REG    0x0000
+
+/* Triton Core internal information (END) */
+
+
+/* subchip/slave 0 0x48 - POWER */
+#define TWL6030_BASEADD_RTC            0x0000
+#define TWL6030_BASEADD_MEM            0x0017
+#define TWL6030_BASEADD_PM_MASTER      0x001F
+#define TWL6030_BASEADD_PM_SLAVE_MISC  0x0030 /* PM_RECEIVER */
+#define TWL6030_BASEADD_PM_MISC                0x00E2
+#define TWL6030_BASEADD_PM_PUPD                0x00F0
+
+/* subchip/slave 1 0x49 - FEATURE */
+#define TWL6030_BASEADD_USB            0x0000
+#define TWL6030_BASEADD_GPADC_CTRL     0x002E
+#define TWL6030_BASEADD_AUX            0x0090
+#define TWL6030_BASEADD_PWM            0x00BA
+#define TWL6030_BASEADD_GASGAUGE       0x00C0
+#define TWL6030_BASEADD_PIH            0x00D0
+#define TWL6030_BASEADD_CHARGER                0x00E0
+
+/* subchip/slave 2 0x4A - DFT */
+#define TWL6030_BASEADD_DIEID          0x00C0
+
+/* subchip/slave 3 0x4B - AUDIO */
+#define TWL6030_BASEADD_AUDIO          0x0000
+#define TWL6030_BASEADD_RSV            0x0000
+
+/* Few power values */
+#define R_CFG_BOOT                     0x05
+#define R_PROTECT_KEY                  0x0E
+
+/* access control values for R_PROTECT_KEY */
+#define KEY_UNLOCK1                    0xce
+#define KEY_UNLOCK2                    0xec
+#define KEY_LOCK                       0x00
+
+/* some fields in R_CFG_BOOT */
+#define HFCLK_FREQ_19p2_MHZ            (1 << 0)
+#define HFCLK_FREQ_26_MHZ              (2 << 0)
+#define HFCLK_FREQ_38p4_MHZ            (3 << 0)
+#define HIGH_PERF_SQ                   (1 << 3)
+#define CK32K_LOWPWR_EN                        (1 << 7)
+
+
+/* chip-specific feature flags, for i2c_device_id.driver_data */
+#define TWL4030_VAUX2          BIT(0)  /* pre-5030 voltage ranges */
+#define TPS_SUBSET             BIT(1)  /* tps659[23]0 have fewer LDOs */
+#define TWL5031                        BIT(2)  /* twl5031 has different registers */
+#define TWL6030_CLASS          BIT(3)  /* TWL6030 class */
+
+/*----------------------------------------------------------------------*/
+
+/* is driver active, bound to a chip? */
+static bool inuse;
+
+static unsigned int twl_id;
+unsigned int twl_rev(void)
+{
+       return twl_id;
+}
+EXPORT_SYMBOL(twl_rev);
+
+/* Structure for each TWL4030/TWL6030 Slave */
+struct twl_client {
+       struct i2c_client *client;
+       u8 address;
+
+       /* max numb of i2c_msg required is for read =2 */
+       struct i2c_msg xfer_msg[2];
+
+       /* To lock access to xfer_msg */
+       struct mutex xfer_lock;
+};
+
+static struct twl_client twl_modules[TWL_NUM_SLAVES];
+
+
+/* mapping the module id to slave id and base address */
+struct twl_mapping {
+       unsigned char sid;      /* Slave ID */
+       unsigned char base;     /* base address */
+};
+struct twl_mapping *twl_map;
+
+static struct twl_mapping twl4030_map[TWL4030_MODULE_LAST + 1] = {
+       /*
+        * NOTE:  don't change this table without updating the
+        * <linux/i2c/twl.h> defines for TWL4030_MODULE_*
+        * so they continue to match the order in this table.
+        */
+
+       { 0, TWL4030_BASEADD_USB },
+
+       { 1, TWL4030_BASEADD_AUDIO_VOICE },
+       { 1, TWL4030_BASEADD_GPIO },
+       { 1, TWL4030_BASEADD_INTBR },
+       { 1, TWL4030_BASEADD_PIH },
+       { 1, TWL4030_BASEADD_TEST },
+
+       { 2, TWL4030_BASEADD_KEYPAD },
+       { 2, TWL4030_BASEADD_MADC },
+       { 2, TWL4030_BASEADD_INTERRUPTS },
+       { 2, TWL4030_BASEADD_LED },
+       { 2, TWL4030_BASEADD_MAIN_CHARGE },
+       { 2, TWL4030_BASEADD_PRECHARGE },
+       { 2, TWL4030_BASEADD_PWM0 },
+       { 2, TWL4030_BASEADD_PWM1 },
+       { 2, TWL4030_BASEADD_PWMA },
+       { 2, TWL4030_BASEADD_PWMB },
+       { 2, TWL5031_BASEADD_ACCESSORY },
+       { 2, TWL5031_BASEADD_INTERRUPTS },
+
+       { 3, TWL4030_BASEADD_BACKUP },
+       { 3, TWL4030_BASEADD_INT },
+       { 3, TWL4030_BASEADD_PM_MASTER },
+       { 3, TWL4030_BASEADD_PM_RECEIVER },
+       { 3, TWL4030_BASEADD_RTC },
+       { 3, TWL4030_BASEADD_SECURED_REG },
+};
+
+static struct twl_mapping twl6030_map[] = {
+       /*
+        * NOTE:  don't change this table without updating the
+        * <linux/i2c/twl.h> defines for TWL4030_MODULE_*
+        * so they continue to match the order in this table.
+        */
+       { SUB_CHIP_ID1, TWL6030_BASEADD_USB },
+       { SUB_CHIP_ID3, TWL6030_BASEADD_AUDIO },
+       { SUB_CHIP_ID2, TWL6030_BASEADD_DIEID },
+       { SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
+       { SUB_CHIP_ID1, TWL6030_BASEADD_PIH },
+
+       { SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
+       { SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
+       { SUB_CHIP_ID1, TWL6030_BASEADD_GPADC_CTRL },
+       { SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
+       { SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
+
+       { SUB_CHIP_ID1, TWL6030_BASEADD_CHARGER },
+       { SUB_CHIP_ID1, TWL6030_BASEADD_GASGAUGE },
+       { SUB_CHIP_ID1, TWL6030_BASEADD_PWM },
+       { SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
+       { SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
+
+       { SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
+       { SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
+       { SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
+       { SUB_CHIP_ID0, TWL6030_BASEADD_PM_MASTER },
+       { SUB_CHIP_ID0, TWL6030_BASEADD_PM_SLAVE_MISC },
+
+       { SUB_CHIP_ID0, TWL6030_BASEADD_RTC },
+       { SUB_CHIP_ID0, TWL6030_BASEADD_MEM },
+};
+
+/*----------------------------------------------------------------------*/
+
+/* Exported Functions */
+
+/**
+ * twl_i2c_write - Writes a n bit register in TWL4030/TWL5030/TWL60X0
+ * @mod_no: module number
+ * @value: an array of num_bytes+1 containing data to write
+ * @reg: register address (just offset will do)
+ * @num_bytes: number of bytes to transfer
+ *
+ * IMPORTANT: for 'value' parameter: Allocate value num_bytes+1 and
+ * valid data starts at Offset 1.
+ *
+ * Returns the result of operation - 0 is success
+ */
+int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
+{
+       int ret;
+       int sid;
+       struct twl_client *twl;
+       struct i2c_msg *msg;
+
+       if (unlikely(mod_no > TWL_MODULE_LAST)) {
+               pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no);
+               return -EPERM;
+       }
+       sid = twl_map[mod_no].sid;
+       twl = &twl_modules[sid];
+
+       if (unlikely(!inuse)) {
+               pr_err("%s: client %d is not initialized\n", DRIVER_NAME, sid);
+               return -EPERM;
+       }
+       mutex_lock(&twl->xfer_lock);
+       /*
+        * [MSG1]: fill the register address data
+        * fill the data Tx buffer
+        */
+       msg = &twl->xfer_msg[0];
+       msg->addr = twl->address;
+       msg->len = num_bytes + 1;
+       msg->flags = 0;
+       msg->buf = value;
+       /* over write the first byte of buffer with the register address */
+       *value = twl_map[mod_no].base + reg;
+       ret = i2c_transfer(twl->client->adapter, twl->xfer_msg, 1);
+       mutex_unlock(&twl->xfer_lock);
+
+       /* i2c_transfer returns number of messages transferred */
+       if (ret != 1) {
+               pr_err("%s: i2c_write failed to transfer all messages\n",
+                       DRIVER_NAME);
+               if (ret < 0)
+                       return ret;
+               else
+                       return -EIO;
+       } else {
+               return 0;
+       }
+}
+EXPORT_SYMBOL(twl_i2c_write);
+
+/**
+ * twl_i2c_read - Reads a n bit register in TWL4030/TWL5030/TWL60X0
+ * @mod_no: module number
+ * @value: an array of num_bytes containing data to be read
+ * @reg: register address (just offset will do)
+ * @num_bytes: number of bytes to transfer
+ *
+ * Returns result of operation - num_bytes is success else failure.
+ */
+int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
+{
+       int ret;
+       u8 val;
+       int sid;
+       struct twl_client *twl;
+       struct i2c_msg *msg;
+
+       if (unlikely(mod_no > TWL_MODULE_LAST)) {
+               pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no);
+               return -EPERM;
+       }
+       sid = twl_map[mod_no].sid;
+       twl = &twl_modules[sid];
+
+       if (unlikely(!inuse)) {
+               pr_err("%s: client %d is not initialized\n", DRIVER_NAME, sid);
+               return -EPERM;
+       }
+       mutex_lock(&twl->xfer_lock);
+       /* [MSG1] fill the register address data */
+       msg = &twl->xfer_msg[0];
+       msg->addr = twl->address;
+       msg->len = 1;
+       msg->flags = 0; /* Read the register value */
+       val = twl_map[mod_no].base + reg;
+       msg->buf = &val;
+       /* [MSG2] fill the data rx buffer */
+       msg = &twl->xfer_msg[1];
+       msg->addr = twl->address;
+       msg->flags = I2C_M_RD;  /* Read the register value */
+       msg->len = num_bytes;   /* only n bytes */
+       msg->buf = value;
+       ret = i2c_transfer(twl->client->adapter, twl->xfer_msg, 2);
+       mutex_unlock(&twl->xfer_lock);
+
+       /* i2c_transfer returns number of messages transferred */
+       if (ret != 2) {
+               pr_err("%s: i2c_read failed to transfer all messages\n",
+                       DRIVER_NAME);
+               if (ret < 0)
+                       return ret;
+               else
+                       return -EIO;
+       } else {
+               return 0;
+       }
+}
+EXPORT_SYMBOL(twl_i2c_read);
+
+/**
+ * twl_i2c_write_u8 - Writes a 8 bit register in TWL4030/TWL5030/TWL60X0
+ * @mod_no: module number
+ * @value: the value to be written 8 bit
+ * @reg: register address (just offset will do)
+ *
+ * Returns result of operation - 0 is success
+ */
+int twl_i2c_write_u8(u8 mod_no, u8 value, u8 reg)
+{
+
+       /* 2 bytes offset 1 contains the data offset 0 is used by i2c_write */
+       u8 temp_buffer[2] = { 0 };
+       /* offset 1 contains the data */
+       temp_buffer[1] = value;
+       return twl_i2c_write(mod_no, temp_buffer, reg, 1);
+}
+EXPORT_SYMBOL(twl_i2c_write_u8);
+
+/**
+ * twl_i2c_read_u8 - Reads a 8 bit register from TWL4030/TWL5030/TWL60X0
+ * @mod_no: module number
+ * @value: the value read 8 bit
+ * @reg: register address (just offset will do)
+ *
+ * Returns result of operation - 0 is success
+ */
+int twl_i2c_read_u8(u8 mod_no, u8 *value, u8 reg)
+{
+       return twl_i2c_read(mod_no, value, reg, 1);
+}
+EXPORT_SYMBOL(twl_i2c_read_u8);
+
+/*----------------------------------------------------------------------*/
+
+static struct device *
+add_numbered_child(unsigned chip, const char *name, int num,
+               void *pdata, unsigned pdata_len,
+               bool can_wakeup, int irq0, int irq1)
+{
+       struct platform_device  *pdev;
+       struct twl_client       *twl = &twl_modules[chip];
+       int                     status;
+
+       pdev = platform_device_alloc(name, num);
+       if (!pdev) {
+               dev_dbg(&twl->client->dev, "can't alloc dev\n");
+               status = -ENOMEM;
+               goto err;
+       }
+
+       device_init_wakeup(&pdev->dev, can_wakeup);
+       pdev->dev.parent = &twl->client->dev;
+
+       if (pdata) {
+               status = platform_device_add_data(pdev, pdata, pdata_len);
+               if (status < 0) {
+                       dev_dbg(&pdev->dev, "can't add platform_data\n");
+                       goto err;
+               }
+       }
+
+       if (irq0) {
+               struct resource r[2] = {
+                       { .start = irq0, .flags = IORESOURCE_IRQ, },
+                       { .start = irq1, .flags = IORESOURCE_IRQ, },
+               };
+
+               status = platform_device_add_resources(pdev, r, irq1 ? 2 : 1);
+               if (status < 0) {
+                       dev_dbg(&pdev->dev, "can't add irqs\n");
+                       goto err;
+               }
+       }
+
+       status = platform_device_add(pdev);
+
+err:
+       if (status < 0) {
+               platform_device_put(pdev);
+               dev_err(&twl->client->dev, "can't add %s dev\n", name);
+               return ERR_PTR(status);
+       }
+       return &pdev->dev;
+}
+
+static inline struct device *add_child(unsigned chip, const char *name,
+               void *pdata, unsigned pdata_len,
+               bool can_wakeup, int irq0, int irq1)
+{
+       return add_numbered_child(chip, name, -1, pdata, pdata_len,
+               can_wakeup, irq0, irq1);
+}
+
+static struct device *
+add_regulator_linked(int num, struct regulator_init_data *pdata,
+               struct regulator_consumer_supply *consumers,
+               unsigned num_consumers)
+{
+       unsigned sub_chip_id;
+       /* regulator framework demands init_data ... */
+       if (!pdata)
+               return NULL;
+
+       if (consumers) {
+               pdata->consumer_supplies = consumers;
+               pdata->num_consumer_supplies = num_consumers;
+       }
+
+       /* NOTE:  we currently ignore regulator IRQs, e.g. for short circuits */
+       sub_chip_id = twl_map[TWL_MODULE_PM_MASTER].sid;
+       return add_numbered_child(sub_chip_id, "twl_reg", num,
+               pdata, sizeof(*pdata), false, 0, 0);
+}
+
+static struct device *
+add_regulator(int num, struct regulator_init_data *pdata)
+{
+       return add_regulator_linked(num, pdata, NULL, 0);
+}
+
+/*
+ * NOTE:  We know the first 8 IRQs after pdata->base_irq are
+ * for the PIH, and the next are for the PWR_INT SIH, since
+ * that's how twl_init_irq() sets things up.
+ */
+
+static int
+add_children(struct twl4030_platform_data *pdata, unsigned long features)
+{
+       struct device   *child;
+       unsigned sub_chip_id;
+
+       if (twl_has_bci() && pdata->bci &&
+           !(features & (TPS_SUBSET | TWL5031))) {
+               child = add_child(3, "twl4030_bci",
+                               pdata->bci, sizeof(*pdata->bci),
+                               false,
+                               /* irq0 = CHG_PRES, irq1 = BCI */
+                               pdata->irq_base + BCI_PRES_INTR_OFFSET,
+                               pdata->irq_base + BCI_INTR_OFFSET);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+       }
+
+       if (twl_has_gpio() && pdata->gpio) {
+               child = add_child(SUB_CHIP_ID1, "twl4030_gpio",
+                               pdata->gpio, sizeof(*pdata->gpio),
+                               false, pdata->irq_base + GPIO_INTR_OFFSET, 0);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+       }
+
+       if (twl_has_keypad() && pdata->keypad) {
+               child = add_child(SUB_CHIP_ID2, "twl4030_keypad",
+                               pdata->keypad, sizeof(*pdata->keypad),
+                               true, pdata->irq_base + KEYPAD_INTR_OFFSET, 0);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+       }
+
+       if (twl_has_madc() && pdata->madc) {
+               child = add_child(2, "twl4030_madc",
+                               pdata->madc, sizeof(*pdata->madc),
+                               true, pdata->irq_base + MADC_INTR_OFFSET, 0);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+       }
+
+       if (twl_has_rtc()) {
+               /*
+                * REVISIT platform_data here currently might expose the
+                * "msecure" line ... but for now we just expect board
+                * setup to tell the chip "it's always ok to SET_TIME".
+                * Eventually, Linux might become more aware of such
+                * HW security concerns, and "least privilege".
+                */
+               sub_chip_id = twl_map[TWL_MODULE_RTC].sid;
+               child = add_child(sub_chip_id, "twl_rtc",
+                               NULL, 0,
+                               true, pdata->irq_base + RTC_INTR_OFFSET, 0);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+       }
+
+       if (twl_has_usb() && pdata->usb && twl_class_is_4030()) {
+
+               static struct regulator_consumer_supply usb1v5 = {
+                       .supply =       "usb1v5",
+               };
+               static struct regulator_consumer_supply usb1v8 = {
+                       .supply =       "usb1v8",
+               };
+               static struct regulator_consumer_supply usb3v1 = {
+                       .supply =       "usb3v1",
+               };
+
+       /* First add the regulators so that they can be used by transceiver */
+               if (twl_has_regulator()) {
+                       /* this is a template that gets copied */
+                       struct regulator_init_data usb_fixed = {
+                               .constraints.valid_modes_mask =
+                                       REGULATOR_MODE_NORMAL
+                                       | REGULATOR_MODE_STANDBY,
+                               .constraints.valid_ops_mask =
+                                       REGULATOR_CHANGE_MODE
+                                       | REGULATOR_CHANGE_STATUS,
+                       };
+
+                       child = add_regulator_linked(TWL4030_REG_VUSB1V5,
+                                                     &usb_fixed, &usb1v5, 1);
+                       if (IS_ERR(child))
+                               return PTR_ERR(child);
+
+                       child = add_regulator_linked(TWL4030_REG_VUSB1V8,
+                                                     &usb_fixed, &usb1v8, 1);
+                       if (IS_ERR(child))
+                               return PTR_ERR(child);
+
+                       child = add_regulator_linked(TWL4030_REG_VUSB3V1,
+                                                     &usb_fixed, &usb3v1, 1);
+                       if (IS_ERR(child))
+                               return PTR_ERR(child);
+
+               }
+
+               child = add_child(0, "twl4030_usb",
+                               pdata->usb, sizeof(*pdata->usb),
+                               true,
+                               /* irq0 = USB_PRES, irq1 = USB */
+                               pdata->irq_base + USB_PRES_INTR_OFFSET,
+                               pdata->irq_base + USB_INTR_OFFSET);
+
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               /* we need to connect regulators to this transceiver */
+               if (twl_has_regulator() && child) {
+                       usb1v5.dev = child;
+                       usb1v8.dev = child;
+                       usb3v1.dev = child;
+               }
+       }
+
+       if (twl_has_watchdog()) {
+               child = add_child(0, "twl4030_wdt", NULL, 0, false, 0, 0);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+       }
+
+       if (twl_has_pwrbutton()) {
+               child = add_child(1, "twl4030_pwrbutton",
+                               NULL, 0, true, pdata->irq_base + 8 + 0, 0);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+       }
+
+       if (twl_has_codec() && pdata->codec) {
+               child = add_child(1, "twl4030_codec",
+                               pdata->codec, sizeof(*pdata->codec),
+                               false, 0, 0);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+       }
+
+       /* twl4030 regulators */
+       if (twl_has_regulator() && twl_class_is_4030()) {
+               child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL4030_REG_VIO, pdata->vio);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL4030_REG_VDD1, pdata->vdd1);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL4030_REG_VDD2, pdata->vdd2);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL4030_REG_VMMC1, pdata->vmmc1);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL4030_REG_VDAC, pdata->vdac);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator((features & TWL4030_VAUX2)
+                                       ? TWL4030_REG_VAUX2_4030
+                                       : TWL4030_REG_VAUX2,
+                               pdata->vaux2);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL4030_REG_VINTANA1, pdata->vintana1);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL4030_REG_VINTANA2, pdata->vintana2);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL4030_REG_VINTDIG, pdata->vintdig);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+       }
+
+       /* maybe add LDOs that are omitted on cost-reduced parts */
+       if (twl_has_regulator() && !(features & TPS_SUBSET)
+         && twl_class_is_4030()) {
+               child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL4030_REG_VMMC2, pdata->vmmc2);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL4030_REG_VSIM, pdata->vsim);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL4030_REG_VAUX1, pdata->vaux1);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL4030_REG_VAUX3, pdata->vaux3);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL4030_REG_VAUX4, pdata->vaux4);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+       }
+
+       /* twl6030 regulators */
+       if (twl_has_regulator() && twl_class_is_6030()) {
+               child = add_regulator(TWL6030_REG_VMMC, pdata->vmmc);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL6030_REG_VPP, pdata->vpp);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL6030_REG_VUSIM, pdata->vusim);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL6030_REG_VANA, pdata->vana);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL6030_REG_VCXIO, pdata->vcxio);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL6030_REG_VDAC, pdata->vdac);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL6030_REG_VUSB, pdata->vusb);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL6030_REG_VAUX1_6030, pdata->vaux1);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL6030_REG_VAUX2_6030, pdata->vaux2);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL6030_REG_VAUX3_6030, pdata->vaux3);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+       }
+
+       return 0;
+}
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * These three functions initialize the on-chip clock framework,
+ * letting it generate the right frequencies for USB, MADC, and
+ * other purposes.
+ */
+static inline int __init protect_pm_master(void)
+{
+       int e = 0;
+
+       e = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, KEY_LOCK,
+                       R_PROTECT_KEY);
+       return e;
+}
+
+static inline int __init unprotect_pm_master(void)
+{
+       int e = 0;
+
+       e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, KEY_UNLOCK1,
+                       R_PROTECT_KEY);
+       e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, KEY_UNLOCK2,
+                       R_PROTECT_KEY);
+       return e;
+}
+
+static void clocks_init(struct device *dev,
+                       struct twl4030_clock_init_data *clock)
+{
+       int e = 0;
+       struct clk *osc;
+       u32 rate;
+       u8 ctrl = HFCLK_FREQ_26_MHZ;
+
+#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+       if (cpu_is_omap2430())
+               osc = clk_get(dev, "osc_ck");
+       else
+               osc = clk_get(dev, "osc_sys_ck");
+
+       if (IS_ERR(osc)) {
+               printk(KERN_WARNING "Skipping twl internal clock init and "
+                               "using bootloader value (unknown osc rate)\n");
+               return;
+       }
+
+       rate = clk_get_rate(osc);
+       clk_put(osc);
+
+#else
+       /* REVISIT for non-OMAP systems, pass the clock rate from
+        * board init code, using platform_data.
+        */
+       osc = ERR_PTR(-EIO);
+
+       printk(KERN_WARNING "Skipping twl internal clock init and "
+              "using bootloader value (unknown osc rate)\n");
+
+       return;
+#endif
+
+       switch (rate) {
+       case 19200000:
+               ctrl = HFCLK_FREQ_19p2_MHZ;
+               break;
+       case 26000000:
+               ctrl = HFCLK_FREQ_26_MHZ;
+               break;
+       case 38400000:
+               ctrl = HFCLK_FREQ_38p4_MHZ;
+               break;
+       }
+
+       ctrl |= HIGH_PERF_SQ;
+       if (clock && clock->ck32k_lowpwr_enable)
+               ctrl |= CK32K_LOWPWR_EN;
+
+       e |= unprotect_pm_master();
+       /* effect->MADC+USB ck en */
+       e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, ctrl, R_CFG_BOOT);
+       e |= protect_pm_master();
+
+       if (e < 0)
+               pr_err("%s: clock init err [%d]\n", DRIVER_NAME, e);
+}
+
+/*----------------------------------------------------------------------*/
+
+int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end);
+int twl4030_exit_irq(void);
+int twl4030_init_chip_irq(const char *chip);
+int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end);
+int twl6030_exit_irq(void);
+
+static int twl_remove(struct i2c_client *client)
+{
+       unsigned i;
+       int status;
+
+       if (twl_class_is_4030())
+               status = twl4030_exit_irq();
+       else
+               status = twl6030_exit_irq();
+
+       if (status < 0)
+               return status;
+
+       for (i = 0; i < TWL_NUM_SLAVES; i++) {
+               struct twl_client       *twl = &twl_modules[i];
+
+               if (twl->client && twl->client != client)
+                       i2c_unregister_device(twl->client);
+               twl_modules[i].client = NULL;
+       }
+       inuse = false;
+       return 0;
+}
+
+/* NOTE:  this driver only handles a single twl4030/tps659x0 chip */
+static int __init
+twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+       int                             status;
+       unsigned                        i;
+       struct twl4030_platform_data    *pdata = client->dev.platform_data;
+
+       if (!pdata) {
+               dev_dbg(&client->dev, "no platform data?\n");
+               return -EINVAL;
+       }
+
+       if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
+               dev_dbg(&client->dev, "can't talk I2C?\n");
+               return -EIO;
+       }
+
+       if (inuse) {
+               dev_dbg(&client->dev, "driver is already in use\n");
+               return -EBUSY;
+       }
+
+       for (i = 0; i < TWL_NUM_SLAVES; i++) {
+               struct twl_client       *twl = &twl_modules[i];
+
+               twl->address = client->addr + i;
+               if (i == 0)
+                       twl->client = client;
+               else {
+                       twl->client = i2c_new_dummy(client->adapter,
+                                       twl->address);
+                       if (!twl->client) {
+                               dev_err(&client->dev,
+                                       "can't attach client %d\n", i);
+                               status = -ENOMEM;
+                               goto fail;
+                       }
+               }
+               mutex_init(&twl->xfer_lock);
+       }
+       inuse = true;
+       if ((id->driver_data) & TWL6030_CLASS) {
+               twl_id = TWL6030_CLASS_ID;
+               twl_map = &twl6030_map[0];
+       } else {
+               twl_id = TWL4030_CLASS_ID;
+               twl_map = &twl4030_map[0];
+       }
+
+       /* setup clock framework */
+       clocks_init(&client->dev, pdata->clock);
+
+       /* load power event scripts */
+       if (twl_has_power() && pdata->power)
+               twl4030_power_init(pdata->power);
+
+       /* Maybe init the T2 Interrupt subsystem */
+       if (client->irq
+                       && pdata->irq_base
+                       && pdata->irq_end > pdata->irq_base) {
+               if (twl_class_is_4030()) {
+                       twl4030_init_chip_irq(id->name);
+                       status = twl4030_init_irq(client->irq, pdata->irq_base,
+                       pdata->irq_end);
+               } else {
+                       status = twl6030_init_irq(client->irq, pdata->irq_base,
+                       pdata->irq_end);
+               }
+
+               if (status < 0)
+                       goto fail;
+       }
+
+       status = add_children(pdata, id->driver_data);
+fail:
+       if (status < 0)
+               twl_remove(client);
+       return status;
+}
+
+static const struct i2c_device_id twl_ids[] = {
+       { "twl4030", TWL4030_VAUX2 },   /* "Triton 2" */
+       { "twl5030", 0 },               /* T2 updated */
+       { "twl5031", TWL5031 },         /* TWL5030 updated */
+       { "tps65950", 0 },              /* catalog version of twl5030 */
+       { "tps65930", TPS_SUBSET },     /* fewer LDOs and DACs; no charger */
+       { "tps65920", TPS_SUBSET },     /* fewer LDOs; no codec or charger */
+       { "twl6030", TWL6030_CLASS },   /* "Phoenix power chip" */
+       { /* end of list */ },
+};
+MODULE_DEVICE_TABLE(i2c, twl_ids);
+
+/* One Client Driver , 4 Clients */
+static struct i2c_driver twl_driver = {
+       .driver.name    = DRIVER_NAME,
+       .id_table       = twl_ids,
+       .probe          = twl_probe,
+       .remove         = twl_remove,
+};
+
+static int __init twl_init(void)
+{
+       return i2c_add_driver(&twl_driver);
+}
+subsys_initcall(twl_init);
+
+static void __exit twl_exit(void)
+{
+       i2c_del_driver(&twl_driver);
+}
+module_exit(twl_exit);
+
+MODULE_AUTHOR("Texas Instruments, Inc.");
+MODULE_DESCRIPTION("I2C Core interface for TWL");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/twl4030-core.c b/drivers/mfd/twl4030-core.c
deleted file mode 100644 (file)
index 40449cd..0000000
+++ /dev/null
@@ -1,879 +0,0 @@
-/*
- * twl4030_core.c - driver for TWL4030/TPS659x0 PM and audio CODEC devices
- *
- * Copyright (C) 2005-2006 Texas Instruments, Inc.
- *
- * Modifications to defer interrupt handling to a kernel thread:
- * Copyright (C) 2006 MontaVista Software, Inc.
- *
- * Based on tlv320aic23.c:
- * Copyright (c) by Kai Svahn <kai.svahn@nokia.com>
- *
- * Code cleanup and modifications to IRQ handler.
- * by syed khasim <x0khasim@ti.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/init.h>
-#include <linux/mutex.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-
-#include <linux/regulator/machine.h>
-
-#include <linux/i2c.h>
-#include <linux/i2c/twl4030.h>
-
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
-#include <plat/cpu.h>
-#endif
-
-/*
- * The TWL4030 "Triton 2" is one of a family of a multi-function "Power
- * Management and System Companion Device" chips originally designed for
- * use in OMAP2 and OMAP 3 based systems.  Its control interfaces use I2C,
- * often at around 3 Mbit/sec, including for interrupt handling.
- *
- * This driver core provides genirq support for the interrupts emitted,
- * by the various modules, and exports register access primitives.
- *
- * FIXME this driver currently requires use of the first interrupt line
- * (and associated registers).
- */
-
-#define DRIVER_NAME                    "twl4030"
-
-#if defined(CONFIG_TWL4030_BCI_BATTERY) || \
-       defined(CONFIG_TWL4030_BCI_BATTERY_MODULE)
-#define twl_has_bci()          true
-#else
-#define twl_has_bci()          false
-#endif
-
-#if defined(CONFIG_KEYBOARD_TWL4030) || defined(CONFIG_KEYBOARD_TWL4030_MODULE)
-#define twl_has_keypad()       true
-#else
-#define twl_has_keypad()       false
-#endif
-
-#if defined(CONFIG_GPIO_TWL4030) || defined(CONFIG_GPIO_TWL4030_MODULE)
-#define twl_has_gpio() true
-#else
-#define twl_has_gpio() false
-#endif
-
-#if defined(CONFIG_REGULATOR_TWL4030) \
-       || defined(CONFIG_REGULATOR_TWL4030_MODULE)
-#define twl_has_regulator()    true
-#else
-#define twl_has_regulator()    false
-#endif
-
-#if defined(CONFIG_TWL4030_MADC) || defined(CONFIG_TWL4030_MADC_MODULE)
-#define twl_has_madc() true
-#else
-#define twl_has_madc() false
-#endif
-
-#ifdef CONFIG_TWL4030_POWER
-#define twl_has_power()        true
-#else
-#define twl_has_power()        false
-#endif
-
-#if defined(CONFIG_RTC_DRV_TWL4030) || defined(CONFIG_RTC_DRV_TWL4030_MODULE)
-#define twl_has_rtc()  true
-#else
-#define twl_has_rtc()  false
-#endif
-
-#if defined(CONFIG_TWL4030_USB) || defined(CONFIG_TWL4030_USB_MODULE)
-#define twl_has_usb()  true
-#else
-#define twl_has_usb()  false
-#endif
-
-#if defined(CONFIG_TWL4030_WATCHDOG) || \
-       defined(CONFIG_TWL4030_WATCHDOG_MODULE)
-#define twl_has_watchdog()        true
-#else
-#define twl_has_watchdog()        false
-#endif
-
-#if defined(CONFIG_TWL4030_CODEC) || defined(CONFIG_TWL4030_CODEC_MODULE)
-#define twl_has_codec()        true
-#else
-#define twl_has_codec()        false
-#endif
-
-/* Triton Core internal information (BEGIN) */
-
-/* Last - for index max*/
-#define TWL4030_MODULE_LAST            TWL4030_MODULE_SECURED_REG
-
-#define TWL4030_NUM_SLAVES             4
-
-#if defined(CONFIG_INPUT_TWL4030_PWRBUTTON) \
-       || defined(CONFIG_INPUT_TWL4030_PWBUTTON_MODULE)
-#define twl_has_pwrbutton()    true
-#else
-#define twl_has_pwrbutton()    false
-#endif
-
-/* Base Address defns for twl4030_map[] */
-
-/* subchip/slave 0 - USB ID */
-#define TWL4030_BASEADD_USB            0x0000
-
-/* subchip/slave 1 - AUD ID */
-#define TWL4030_BASEADD_AUDIO_VOICE    0x0000
-#define TWL4030_BASEADD_GPIO           0x0098
-#define TWL4030_BASEADD_INTBR          0x0085
-#define TWL4030_BASEADD_PIH            0x0080
-#define TWL4030_BASEADD_TEST           0x004C
-
-/* subchip/slave 2 - AUX ID */
-#define TWL4030_BASEADD_INTERRUPTS     0x00B9
-#define TWL4030_BASEADD_LED            0x00EE
-#define TWL4030_BASEADD_MADC           0x0000
-#define TWL4030_BASEADD_MAIN_CHARGE    0x0074
-#define TWL4030_BASEADD_PRECHARGE      0x00AA
-#define TWL4030_BASEADD_PWM0           0x00F8
-#define TWL4030_BASEADD_PWM1           0x00FB
-#define TWL4030_BASEADD_PWMA           0x00EF
-#define TWL4030_BASEADD_PWMB           0x00F1
-#define TWL4030_BASEADD_KEYPAD         0x00D2
-
-/* subchip/slave 3 - POWER ID */
-#define TWL4030_BASEADD_BACKUP         0x0014
-#define TWL4030_BASEADD_INT            0x002E
-#define TWL4030_BASEADD_PM_MASTER      0x0036
-#define TWL4030_BASEADD_PM_RECEIVER    0x005B
-#define TWL4030_BASEADD_RTC            0x001C
-#define TWL4030_BASEADD_SECURED_REG    0x0000
-
-/* Triton Core internal information (END) */
-
-
-/* Few power values */
-#define R_CFG_BOOT                     0x05
-#define R_PROTECT_KEY                  0x0E
-
-/* access control values for R_PROTECT_KEY */
-#define KEY_UNLOCK1                    0xce
-#define KEY_UNLOCK2                    0xec
-#define KEY_LOCK                       0x00
-
-/* some fields in R_CFG_BOOT */
-#define HFCLK_FREQ_19p2_MHZ            (1 << 0)
-#define HFCLK_FREQ_26_MHZ              (2 << 0)
-#define HFCLK_FREQ_38p4_MHZ            (3 << 0)
-#define HIGH_PERF_SQ                   (1 << 3)
-
-
-/* chip-specific feature flags, for i2c_device_id.driver_data */
-#define TWL4030_VAUX2          BIT(0)  /* pre-5030 voltage ranges */
-#define TPS_SUBSET             BIT(1)  /* tps659[23]0 have fewer LDOs */
-
-/*----------------------------------------------------------------------*/
-
-/* is driver active, bound to a chip? */
-static bool inuse;
-
-/* Structure for each TWL4030 Slave */
-struct twl4030_client {
-       struct i2c_client *client;
-       u8 address;
-
-       /* max numb of i2c_msg required is for read =2 */
-       struct i2c_msg xfer_msg[2];
-
-       /* To lock access to xfer_msg */
-       struct mutex xfer_lock;
-};
-
-static struct twl4030_client twl4030_modules[TWL4030_NUM_SLAVES];
-
-
-/* mapping the module id to slave id and base address */
-struct twl4030mapping {
-       unsigned char sid;      /* Slave ID */
-       unsigned char base;     /* base address */
-};
-
-static struct twl4030mapping twl4030_map[TWL4030_MODULE_LAST + 1] = {
-       /*
-        * NOTE:  don't change this table without updating the
-        * <linux/i2c/twl4030.h> defines for TWL4030_MODULE_*
-        * so they continue to match the order in this table.
-        */
-
-       { 0, TWL4030_BASEADD_USB },
-
-       { 1, TWL4030_BASEADD_AUDIO_VOICE },
-       { 1, TWL4030_BASEADD_GPIO },
-       { 1, TWL4030_BASEADD_INTBR },
-       { 1, TWL4030_BASEADD_PIH },
-       { 1, TWL4030_BASEADD_TEST },
-
-       { 2, TWL4030_BASEADD_KEYPAD },
-       { 2, TWL4030_BASEADD_MADC },
-       { 2, TWL4030_BASEADD_INTERRUPTS },
-       { 2, TWL4030_BASEADD_LED },
-       { 2, TWL4030_BASEADD_MAIN_CHARGE },
-       { 2, TWL4030_BASEADD_PRECHARGE },
-       { 2, TWL4030_BASEADD_PWM0 },
-       { 2, TWL4030_BASEADD_PWM1 },
-       { 2, TWL4030_BASEADD_PWMA },
-       { 2, TWL4030_BASEADD_PWMB },
-
-       { 3, TWL4030_BASEADD_BACKUP },
-       { 3, TWL4030_BASEADD_INT },
-       { 3, TWL4030_BASEADD_PM_MASTER },
-       { 3, TWL4030_BASEADD_PM_RECEIVER },
-       { 3, TWL4030_BASEADD_RTC },
-       { 3, TWL4030_BASEADD_SECURED_REG },
-};
-
-/*----------------------------------------------------------------------*/
-
-/* Exported Functions */
-
-/**
- * twl4030_i2c_write - Writes a n bit register in TWL4030
- * @mod_no: module number
- * @value: an array of num_bytes+1 containing data to write
- * @reg: register address (just offset will do)
- * @num_bytes: number of bytes to transfer
- *
- * IMPORTANT: for 'value' parameter: Allocate value num_bytes+1 and
- * valid data starts at Offset 1.
- *
- * Returns the result of operation - 0 is success
- */
-int twl4030_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
-{
-       int ret;
-       int sid;
-       struct twl4030_client *twl;
-       struct i2c_msg *msg;
-
-       if (unlikely(mod_no > TWL4030_MODULE_LAST)) {
-               pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no);
-               return -EPERM;
-       }
-       sid = twl4030_map[mod_no].sid;
-       twl = &twl4030_modules[sid];
-
-       if (unlikely(!inuse)) {
-               pr_err("%s: client %d is not initialized\n", DRIVER_NAME, sid);
-               return -EPERM;
-       }
-       mutex_lock(&twl->xfer_lock);
-       /*
-        * [MSG1]: fill the register address data
-        * fill the data Tx buffer
-        */
-       msg = &twl->xfer_msg[0];
-       msg->addr = twl->address;
-       msg->len = num_bytes + 1;
-       msg->flags = 0;
-       msg->buf = value;
-       /* over write the first byte of buffer with the register address */
-       *value = twl4030_map[mod_no].base + reg;
-       ret = i2c_transfer(twl->client->adapter, twl->xfer_msg, 1);
-       mutex_unlock(&twl->xfer_lock);
-
-       /* i2cTransfer returns num messages.translate it pls.. */
-       if (ret >= 0)
-               ret = 0;
-       return ret;
-}
-EXPORT_SYMBOL(twl4030_i2c_write);
-
-/**
- * twl4030_i2c_read - Reads a n bit register in TWL4030
- * @mod_no: module number
- * @value: an array of num_bytes containing data to be read
- * @reg: register address (just offset will do)
- * @num_bytes: number of bytes to transfer
- *
- * Returns result of operation - num_bytes is success else failure.
- */
-int twl4030_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
-{
-       int ret;
-       u8 val;
-       int sid;
-       struct twl4030_client *twl;
-       struct i2c_msg *msg;
-
-       if (unlikely(mod_no > TWL4030_MODULE_LAST)) {
-               pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no);
-               return -EPERM;
-       }
-       sid = twl4030_map[mod_no].sid;
-       twl = &twl4030_modules[sid];
-
-       if (unlikely(!inuse)) {
-               pr_err("%s: client %d is not initialized\n", DRIVER_NAME, sid);
-               return -EPERM;
-       }
-       mutex_lock(&twl->xfer_lock);
-       /* [MSG1] fill the register address data */
-       msg = &twl->xfer_msg[0];
-       msg->addr = twl->address;
-       msg->len = 1;
-       msg->flags = 0; /* Read the register value */
-       val = twl4030_map[mod_no].base + reg;
-       msg->buf = &val;
-       /* [MSG2] fill the data rx buffer */
-       msg = &twl->xfer_msg[1];
-       msg->addr = twl->address;
-       msg->flags = I2C_M_RD;  /* Read the register value */
-       msg->len = num_bytes;   /* only n bytes */
-       msg->buf = value;
-       ret = i2c_transfer(twl->client->adapter, twl->xfer_msg, 2);
-       mutex_unlock(&twl->xfer_lock);
-
-       /* i2cTransfer returns num messages.translate it pls.. */
-       if (ret >= 0)
-               ret = 0;
-       return ret;
-}
-EXPORT_SYMBOL(twl4030_i2c_read);
-
-/**
- * twl4030_i2c_write_u8 - Writes a 8 bit register in TWL4030
- * @mod_no: module number
- * @value: the value to be written 8 bit
- * @reg: register address (just offset will do)
- *
- * Returns result of operation - 0 is success
- */
-int twl4030_i2c_write_u8(u8 mod_no, u8 value, u8 reg)
-{
-
-       /* 2 bytes offset 1 contains the data offset 0 is used by i2c_write */
-       u8 temp_buffer[2] = { 0 };
-       /* offset 1 contains the data */
-       temp_buffer[1] = value;
-       return twl4030_i2c_write(mod_no, temp_buffer, reg, 1);
-}
-EXPORT_SYMBOL(twl4030_i2c_write_u8);
-
-/**
- * twl4030_i2c_read_u8 - Reads a 8 bit register from TWL4030
- * @mod_no: module number
- * @value: the value read 8 bit
- * @reg: register address (just offset will do)
- *
- * Returns result of operation - 0 is success
- */
-int twl4030_i2c_read_u8(u8 mod_no, u8 *value, u8 reg)
-{
-       return twl4030_i2c_read(mod_no, value, reg, 1);
-}
-EXPORT_SYMBOL(twl4030_i2c_read_u8);
-
-/*----------------------------------------------------------------------*/
-
-static struct device *
-add_numbered_child(unsigned chip, const char *name, int num,
-               void *pdata, unsigned pdata_len,
-               bool can_wakeup, int irq0, int irq1)
-{
-       struct platform_device  *pdev;
-       struct twl4030_client   *twl = &twl4030_modules[chip];
-       int                     status;
-
-       pdev = platform_device_alloc(name, num);
-       if (!pdev) {
-               dev_dbg(&twl->client->dev, "can't alloc dev\n");
-               status = -ENOMEM;
-               goto err;
-       }
-
-       device_init_wakeup(&pdev->dev, can_wakeup);
-       pdev->dev.parent = &twl->client->dev;
-
-       if (pdata) {
-               status = platform_device_add_data(pdev, pdata, pdata_len);
-               if (status < 0) {
-                       dev_dbg(&pdev->dev, "can't add platform_data\n");
-                       goto err;
-               }
-       }
-
-       if (irq0) {
-               struct resource r[2] = {
-                       { .start = irq0, .flags = IORESOURCE_IRQ, },
-                       { .start = irq1, .flags = IORESOURCE_IRQ, },
-               };
-
-               status = platform_device_add_resources(pdev, r, irq1 ? 2 : 1);
-               if (status < 0) {
-                       dev_dbg(&pdev->dev, "can't add irqs\n");
-                       goto err;
-               }
-       }
-
-       status = platform_device_add(pdev);
-
-err:
-       if (status < 0) {
-               platform_device_put(pdev);
-               dev_err(&twl->client->dev, "can't add %s dev\n", name);
-               return ERR_PTR(status);
-       }
-       return &pdev->dev;
-}
-
-static inline struct device *add_child(unsigned chip, const char *name,
-               void *pdata, unsigned pdata_len,
-               bool can_wakeup, int irq0, int irq1)
-{
-       return add_numbered_child(chip, name, -1, pdata, pdata_len,
-               can_wakeup, irq0, irq1);
-}
-
-static struct device *
-add_regulator_linked(int num, struct regulator_init_data *pdata,
-               struct regulator_consumer_supply *consumers,
-               unsigned num_consumers)
-{
-       /* regulator framework demands init_data ... */
-       if (!pdata)
-               return NULL;
-
-       if (consumers) {
-               pdata->consumer_supplies = consumers;
-               pdata->num_consumer_supplies = num_consumers;
-       }
-
-       /* NOTE:  we currently ignore regulator IRQs, e.g. for short circuits */
-       return add_numbered_child(3, "twl4030_reg", num,
-               pdata, sizeof(*pdata), false, 0, 0);
-}
-
-static struct device *
-add_regulator(int num, struct regulator_init_data *pdata)
-{
-       return add_regulator_linked(num, pdata, NULL, 0);
-}
-
-/*
- * NOTE:  We know the first 8 IRQs after pdata->base_irq are
- * for the PIH, and the next are for the PWR_INT SIH, since
- * that's how twl_init_irq() sets things up.
- */
-
-static int
-add_children(struct twl4030_platform_data *pdata, unsigned long features)
-{
-       struct device   *child;
-
-       if (twl_has_bci() && pdata->bci && !(features & TPS_SUBSET)) {
-               child = add_child(3, "twl4030_bci",
-                               pdata->bci, sizeof(*pdata->bci),
-                               false,
-                               /* irq0 = CHG_PRES, irq1 = BCI */
-                               pdata->irq_base + 8 + 1, pdata->irq_base + 2);
-               if (IS_ERR(child))
-                       return PTR_ERR(child);
-       }
-
-       if (twl_has_gpio() && pdata->gpio) {
-               child = add_child(1, "twl4030_gpio",
-                               pdata->gpio, sizeof(*pdata->gpio),
-                               false, pdata->irq_base + 0, 0);
-               if (IS_ERR(child))
-                       return PTR_ERR(child);
-       }
-
-       if (twl_has_keypad() && pdata->keypad) {
-               child = add_child(2, "twl4030_keypad",
-                               pdata->keypad, sizeof(*pdata->keypad),
-                               true, pdata->irq_base + 1, 0);
-               if (IS_ERR(child))
-                       return PTR_ERR(child);
-       }
-
-       if (twl_has_madc() && pdata->madc) {
-               child = add_child(2, "twl4030_madc",
-                               pdata->madc, sizeof(*pdata->madc),
-                               true, pdata->irq_base + 3, 0);
-               if (IS_ERR(child))
-                       return PTR_ERR(child);
-       }
-
-       if (twl_has_rtc()) {
-               /*
-                * REVISIT platform_data here currently might expose the
-                * "msecure" line ... but for now we just expect board
-                * setup to tell the chip "it's always ok to SET_TIME".
-                * Eventually, Linux might become more aware of such
-                * HW security concerns, and "least privilege".
-                */
-               child = add_child(3, "twl4030_rtc",
-                               NULL, 0,
-                               true, pdata->irq_base + 8 + 3, 0);
-               if (IS_ERR(child))
-                       return PTR_ERR(child);
-       }
-
-       if (twl_has_usb() && pdata->usb) {
-
-               static struct regulator_consumer_supply usb1v5 = {
-                       .supply =       "usb1v5",
-               };
-               static struct regulator_consumer_supply usb1v8 = {
-                       .supply =       "usb1v8",
-               };
-               static struct regulator_consumer_supply usb3v1 = {
-                       .supply =       "usb3v1",
-               };
-
-       /* First add the regulators so that they can be used by transceiver */
-               if (twl_has_regulator()) {
-                       /* this is a template that gets copied */
-                       struct regulator_init_data usb_fixed = {
-                               .constraints.valid_modes_mask =
-                                       REGULATOR_MODE_NORMAL
-                                       | REGULATOR_MODE_STANDBY,
-                               .constraints.valid_ops_mask =
-                                       REGULATOR_CHANGE_MODE
-                                       | REGULATOR_CHANGE_STATUS,
-                       };
-
-                       child = add_regulator_linked(TWL4030_REG_VUSB1V5,
-                                                     &usb_fixed, &usb1v5, 1);
-                       if (IS_ERR(child))
-                               return PTR_ERR(child);
-
-                       child = add_regulator_linked(TWL4030_REG_VUSB1V8,
-                                                     &usb_fixed, &usb1v8, 1);
-                       if (IS_ERR(child))
-                               return PTR_ERR(child);
-
-                       child = add_regulator_linked(TWL4030_REG_VUSB3V1,
-                                                     &usb_fixed, &usb3v1, 1);
-                       if (IS_ERR(child))
-                               return PTR_ERR(child);
-
-               }
-
-               child = add_child(0, "twl4030_usb",
-                               pdata->usb, sizeof(*pdata->usb),
-                               true,
-                               /* irq0 = USB_PRES, irq1 = USB */
-                               pdata->irq_base + 8 + 2, pdata->irq_base + 4);
-
-               if (IS_ERR(child))
-                       return PTR_ERR(child);
-
-               /* we need to connect regulators to this transceiver */
-               if (twl_has_regulator() && child) {
-                       usb1v5.dev = child;
-                       usb1v8.dev = child;
-                       usb3v1.dev = child;
-               }
-       }
-
-       if (twl_has_watchdog()) {
-               child = add_child(0, "twl4030_wdt", NULL, 0, false, 0, 0);
-               if (IS_ERR(child))
-                       return PTR_ERR(child);
-       }
-
-       if (twl_has_pwrbutton()) {
-               child = add_child(1, "twl4030_pwrbutton",
-                               NULL, 0, true, pdata->irq_base + 8 + 0, 0);
-               if (IS_ERR(child))
-                       return PTR_ERR(child);
-       }
-
-       if (twl_has_codec() && pdata->codec) {
-               child = add_child(1, "twl4030_codec",
-                               pdata->codec, sizeof(*pdata->codec),
-                               false, 0, 0);
-               if (IS_ERR(child))
-                       return PTR_ERR(child);
-       }
-
-       if (twl_has_regulator()) {
-               /*
-               child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1);
-               if (IS_ERR(child))
-                       return PTR_ERR(child);
-               */
-
-               child = add_regulator(TWL4030_REG_VMMC1, pdata->vmmc1);
-               if (IS_ERR(child))
-                       return PTR_ERR(child);
-
-               child = add_regulator(TWL4030_REG_VDAC, pdata->vdac);
-               if (IS_ERR(child))
-                       return PTR_ERR(child);
-
-               child = add_regulator((features & TWL4030_VAUX2)
-                                       ? TWL4030_REG_VAUX2_4030
-                                       : TWL4030_REG_VAUX2,
-                               pdata->vaux2);
-               if (IS_ERR(child))
-                       return PTR_ERR(child);
-       }
-
-       /* maybe add LDOs that are omitted on cost-reduced parts */
-       if (twl_has_regulator() && !(features & TPS_SUBSET)) {
-               child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2);
-               if (IS_ERR(child))
-                       return PTR_ERR(child);
-
-               child = add_regulator(TWL4030_REG_VMMC2, pdata->vmmc2);
-               if (IS_ERR(child))
-                       return PTR_ERR(child);
-
-               child = add_regulator(TWL4030_REG_VSIM, pdata->vsim);
-               if (IS_ERR(child))
-                       return PTR_ERR(child);
-
-               child = add_regulator(TWL4030_REG_VAUX1, pdata->vaux1);
-               if (IS_ERR(child))
-                       return PTR_ERR(child);
-
-               child = add_regulator(TWL4030_REG_VAUX3, pdata->vaux3);
-               if (IS_ERR(child))
-                       return PTR_ERR(child);
-
-               child = add_regulator(TWL4030_REG_VAUX4, pdata->vaux4);
-               if (IS_ERR(child))
-                       return PTR_ERR(child);
-       }
-
-       return 0;
-}
-
-/*----------------------------------------------------------------------*/
-
-/*
- * These three functions initialize the on-chip clock framework,
- * letting it generate the right frequencies for USB, MADC, and
- * other purposes.
- */
-static inline int __init protect_pm_master(void)
-{
-       int e = 0;
-
-       e = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_LOCK,
-                       R_PROTECT_KEY);
-       return e;
-}
-
-static inline int __init unprotect_pm_master(void)
-{
-       int e = 0;
-
-       e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_UNLOCK1,
-                       R_PROTECT_KEY);
-       e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_UNLOCK2,
-                       R_PROTECT_KEY);
-       return e;
-}
-
-static void clocks_init(struct device *dev)
-{
-       int e = 0;
-       struct clk *osc;
-       u32 rate;
-       u8 ctrl = HFCLK_FREQ_26_MHZ;
-
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
-       if (cpu_is_omap2430())
-               osc = clk_get(dev, "osc_ck");
-       else
-               osc = clk_get(dev, "osc_sys_ck");
-
-       if (IS_ERR(osc)) {
-               printk(KERN_WARNING "Skipping twl4030 internal clock init and "
-                               "using bootloader value (unknown osc rate)\n");
-               return;
-       }
-
-       rate = clk_get_rate(osc);
-       clk_put(osc);
-
-#else
-       /* REVISIT for non-OMAP systems, pass the clock rate from
-        * board init code, using platform_data.
-        */
-       osc = ERR_PTR(-EIO);
-
-       printk(KERN_WARNING "Skipping twl4030 internal clock init and "
-              "using bootloader value (unknown osc rate)\n");
-
-       return;
-#endif
-
-       switch (rate) {
-       case 19200000:
-               ctrl = HFCLK_FREQ_19p2_MHZ;
-               break;
-       case 26000000:
-               ctrl = HFCLK_FREQ_26_MHZ;
-               break;
-       case 38400000:
-               ctrl = HFCLK_FREQ_38p4_MHZ;
-               break;
-       }
-
-       ctrl |= HIGH_PERF_SQ;
-       e |= unprotect_pm_master();
-       /* effect->MADC+USB ck en */
-       e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, ctrl, R_CFG_BOOT);
-       e |= protect_pm_master();
-
-       if (e < 0)
-               pr_err("%s: clock init err [%d]\n", DRIVER_NAME, e);
-}
-
-/*----------------------------------------------------------------------*/
-
-int twl_init_irq(int irq_num, unsigned irq_base, unsigned irq_end);
-int twl_exit_irq(void);
-
-static int twl4030_remove(struct i2c_client *client)
-{
-       unsigned i;
-       int status;
-
-       status = twl_exit_irq();
-       if (status < 0)
-               return status;
-
-       for (i = 0; i < TWL4030_NUM_SLAVES; i++) {
-               struct twl4030_client   *twl = &twl4030_modules[i];
-
-               if (twl->client && twl->client != client)
-                       i2c_unregister_device(twl->client);
-               twl4030_modules[i].client = NULL;
-       }
-       inuse = false;
-       return 0;
-}
-
-/* NOTE:  this driver only handles a single twl4030/tps659x0 chip */
-static int __init
-twl4030_probe(struct i2c_client *client, const struct i2c_device_id *id)
-{
-       int                             status;
-       unsigned                        i;
-       struct twl4030_platform_data    *pdata = client->dev.platform_data;
-
-       if (!pdata) {
-               dev_dbg(&client->dev, "no platform data?\n");
-               return -EINVAL;
-       }
-
-       if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
-               dev_dbg(&client->dev, "can't talk I2C?\n");
-               return -EIO;
-       }
-
-       if (inuse) {
-               dev_dbg(&client->dev, "driver is already in use\n");
-               return -EBUSY;
-       }
-
-       for (i = 0; i < TWL4030_NUM_SLAVES; i++) {
-               struct twl4030_client   *twl = &twl4030_modules[i];
-
-               twl->address = client->addr + i;
-               if (i == 0)
-                       twl->client = client;
-               else {
-                       twl->client = i2c_new_dummy(client->adapter,
-                                       twl->address);
-                       if (!twl->client) {
-                               dev_err(&client->dev,
-                                       "can't attach client %d\n", i);
-                               status = -ENOMEM;
-                               goto fail;
-                       }
-                       strlcpy(twl->client->name, id->name,
-                                       sizeof(twl->client->name));
-               }
-               mutex_init(&twl->xfer_lock);
-       }
-       inuse = true;
-
-       /* setup clock framework */
-       clocks_init(&client->dev);
-
-       /* load power event scripts */
-       if (twl_has_power() && pdata->power)
-               twl4030_power_init(pdata->power);
-
-       /* Maybe init the T2 Interrupt subsystem */
-       if (client->irq
-                       && pdata->irq_base
-                       && pdata->irq_end > pdata->irq_base) {
-               status = twl_init_irq(client->irq, pdata->irq_base, pdata->irq_end);
-               if (status < 0)
-                       goto fail;
-       }
-
-       status = add_children(pdata, id->driver_data);
-fail:
-       if (status < 0)
-               twl4030_remove(client);
-       return status;
-}
-
-static const struct i2c_device_id twl4030_ids[] = {
-       { "twl4030", TWL4030_VAUX2 },   /* "Triton 2" */
-       { "twl5030", 0 },               /* T2 updated */
-       { "tps65950", 0 },              /* catalog version of twl5030 */
-       { "tps65930", TPS_SUBSET },     /* fewer LDOs and DACs; no charger */
-       { "tps65920", TPS_SUBSET },     /* fewer LDOs; no codec or charger */
-       { /* end of list */ },
-};
-MODULE_DEVICE_TABLE(i2c, twl4030_ids);
-
-/* One Client Driver , 4 Clients */
-static struct i2c_driver twl4030_driver = {
-       .driver.name    = DRIVER_NAME,
-       .id_table       = twl4030_ids,
-       .probe          = twl4030_probe,
-       .remove         = twl4030_remove,
-};
-
-static int __init twl4030_init(void)
-{
-       return i2c_add_driver(&twl4030_driver);
-}
-subsys_initcall(twl4030_init);
-
-static void __exit twl4030_exit(void)
-{
-       i2c_del_driver(&twl4030_driver);
-}
-module_exit(twl4030_exit);
-
-MODULE_AUTHOR("Texas Instruments, Inc.");
-MODULE_DESCRIPTION("I2C Core interface for TWL4030");
-MODULE_LICENSE("GPL");
index fb194fe244c1b1ce2a0c487e6463af19d87a7693..20d29bafc9f5bc79477fcca4da0e567f17a58563 100644 (file)
@@ -32,7 +32,7 @@
 #include <linux/irq.h>
 #include <linux/kthread.h>
 
-#include <linux/i2c/twl4030.h>
+#include <linux/i2c/twl.h>
 
 
 /*
@@ -74,6 +74,8 @@ struct sih {
        u8      edr_offset;
        u8      bytes_edr;              /* bytelen of EDR */
 
+       u8      irq_lines;              /* number of supported irq lines */
+
        /* SIR ignored -- set interrupt, for testing only */
        struct irq_data {
                u8      isr_offset;
@@ -82,6 +84,9 @@ struct sih {
        /* + 2 bytes padding */
 };
 
+static const struct sih *sih_modules;
+static int nr_sih_modules;
+
 #define SIH_INITIALIZER(modname, nbits) \
        .module         = TWL4030_MODULE_ ## modname, \
        .control_offset = TWL4030_ ## modname ## _SIH_CTRL, \
@@ -89,6 +94,7 @@ struct sih {
        .bytes_ixr      = DIV_ROUND_UP(nbits, 8), \
        .edr_offset     = TWL4030_ ## modname ## _EDR, \
        .bytes_edr      = DIV_ROUND_UP((2*(nbits)), 8), \
+       .irq_lines      = 2, \
        .mask = { { \
                .isr_offset     = TWL4030_ ## modname ## _ISR1, \
                .imr_offset     = TWL4030_ ## modname ## _IMR1, \
@@ -107,7 +113,8 @@ struct sih {
 /* Order in this table matches order in PIH_ISR.  That is,
  * BIT(n) in PIH_ISR is sih_modules[n].
  */
-static const struct sih sih_modules[6] = {
+/* sih_modules_twl4030 is used both in twl4030 and twl5030 */
+static const struct sih sih_modules_twl4030[6] = {
        [0] = {
                .name           = "gpio",
                .module         = TWL4030_MODULE_GPIO,
@@ -118,6 +125,7 @@ static const struct sih sih_modules[6] = {
                /* Note: *all* of these IRQs default to no-trigger */
                .edr_offset     = REG_GPIO_EDR1,
                .bytes_edr      = 5,
+               .irq_lines      = 2,
                .mask = { {
                        .isr_offset     = REG_GPIO_ISR1A,
                        .imr_offset     = REG_GPIO_IMR1A,
@@ -140,6 +148,7 @@ static const struct sih sih_modules[6] = {
                .edr_offset     = TWL4030_INTERRUPTS_BCIEDR1,
                /* Note: most of these IRQs default to no-trigger */
                .bytes_edr      = 3,
+               .irq_lines      = 2,
                .mask = { {
                        .isr_offset     = TWL4030_INTERRUPTS_BCIISR1A,
                        .imr_offset     = TWL4030_INTERRUPTS_BCIIMR1A,
@@ -164,6 +173,99 @@ static const struct sih sih_modules[6] = {
                /* there are no SIH modules #6 or #7 ... */
 };
 
+static const struct sih sih_modules_twl5031[8] = {
+       [0] = {
+               .name           = "gpio",
+               .module         = TWL4030_MODULE_GPIO,
+               .control_offset = REG_GPIO_SIH_CTRL,
+               .set_cor        = true,
+               .bits           = TWL4030_GPIO_MAX,
+               .bytes_ixr      = 3,
+               /* Note: *all* of these IRQs default to no-trigger */
+               .edr_offset     = REG_GPIO_EDR1,
+               .bytes_edr      = 5,
+               .irq_lines      = 2,
+               .mask = { {
+                       .isr_offset     = REG_GPIO_ISR1A,
+                       .imr_offset     = REG_GPIO_IMR1A,
+               }, {
+                       .isr_offset     = REG_GPIO_ISR1B,
+                       .imr_offset     = REG_GPIO_IMR1B,
+               }, },
+       },
+       [1] = {
+               .name           = "keypad",
+               .set_cor        = true,
+               SIH_INITIALIZER(KEYPAD_KEYP, 4)
+       },
+       [2] = {
+               .name           = "bci",
+               .module         = TWL5031_MODULE_INTERRUPTS,
+               .control_offset = TWL5031_INTERRUPTS_BCISIHCTRL,
+               .bits           = 7,
+               .bytes_ixr      = 1,
+               .edr_offset     = TWL5031_INTERRUPTS_BCIEDR1,
+               /* Note: most of these IRQs default to no-trigger */
+               .bytes_edr      = 2,
+               .irq_lines      = 2,
+               .mask = { {
+                       .isr_offset     = TWL5031_INTERRUPTS_BCIISR1,
+                       .imr_offset     = TWL5031_INTERRUPTS_BCIIMR1,
+               }, {
+                       .isr_offset     = TWL5031_INTERRUPTS_BCIISR2,
+                       .imr_offset     = TWL5031_INTERRUPTS_BCIIMR2,
+               }, },
+       },
+       [3] = {
+               .name           = "madc",
+               SIH_INITIALIZER(MADC, 4)
+       },
+       [4] = {
+               /* USB doesn't use the same SIH organization */
+               .name           = "usb",
+       },
+       [5] = {
+               .name           = "power",
+               .set_cor        = true,
+               SIH_INITIALIZER(INT_PWR, 8)
+       },
+       [6] = {
+               /*
+                * ACI doesn't use the same SIH organization.
+                * For example, it supports only one interrupt line
+                */
+               .name           = "aci",
+               .module         = TWL5031_MODULE_ACCESSORY,
+               .bits           = 9,
+               .bytes_ixr      = 2,
+               .irq_lines      = 1,
+               .mask = { {
+                       .isr_offset     = TWL5031_ACIIDR_LSB,
+                       .imr_offset     = TWL5031_ACIIMR_LSB,
+               }, },
+
+       },
+       [7] = {
+               /* Accessory */
+               .name           = "acc",
+               .module         = TWL5031_MODULE_ACCESSORY,
+               .control_offset = TWL5031_ACCSIHCTRL,
+               .bits           = 2,
+               .bytes_ixr      = 1,
+               .edr_offset     = TWL5031_ACCEDR1,
+               /* Note: most of these IRQs default to no-trigger */
+               .bytes_edr      = 1,
+               .irq_lines      = 2,
+               .mask = { {
+                       .isr_offset     = TWL5031_ACCISR1,
+                       .imr_offset     = TWL5031_ACCIMR1,
+               }, {
+                       .isr_offset     = TWL5031_ACCISR2,
+                       .imr_offset     = TWL5031_ACCIMR2,
+               }, },
+       },
+};
+
 #undef TWL4030_MODULE_KEYPAD_KEYP
 #undef TWL4030_MODULE_INT_PWR
 #undef TWL4030_INT_PWR_EDR
@@ -194,7 +296,7 @@ static int twl4030_irq_thread(void *data)
                /* Wait for IRQ, then read PIH irq status (also blocking) */
                wait_for_completion_interruptible(&irq_event);
 
-               ret = twl4030_i2c_read_u8(TWL4030_MODULE_PIH, &pih_isr,
+               ret = twl_i2c_read_u8(TWL4030_MODULE_PIH, &pih_isr,
                                          REG_PIH_ISR_P1);
                if (ret) {
                        pr_warning("twl4030: I2C error %d reading PIH ISR\n",
@@ -284,13 +386,17 @@ static int twl4030_init_sih_modules(unsigned line)
        /* disable all interrupts on our line */
        memset(buf, 0xff, sizeof buf);
        sih = sih_modules;
-       for (i = 0; i < ARRAY_SIZE(sih_modules); i++, sih++) {
+       for (i = 0; i < nr_sih_modules; i++, sih++) {
 
                /* skip USB -- it's funky */
                if (!sih->bytes_ixr)
                        continue;
 
-               status = twl4030_i2c_write(sih->module, buf,
+               /* Not all the SIH modules support multiple interrupt lines */
+               if (sih->irq_lines <= line)
+                       continue;
+
+               status = twl_i2c_write(sih->module, buf,
                                sih->mask[line].imr_offset, sih->bytes_ixr);
                if (status < 0)
                        pr_err("twl4030: err %d initializing %s %s\n",
@@ -304,7 +410,7 @@ static int twl4030_init_sih_modules(unsigned line)
                 * And for PWR_INT it's not documented...
                 */
                if (sih->set_cor) {
-                       status = twl4030_i2c_write_u8(sih->module,
+                       status = twl_i2c_write_u8(sih->module,
                                        TWL4030_SIH_CTRL_COR_MASK,
                                        sih->control_offset);
                        if (status < 0)
@@ -314,7 +420,7 @@ static int twl4030_init_sih_modules(unsigned line)
        }
 
        sih = sih_modules;
-       for (i = 0; i < ARRAY_SIZE(sih_modules); i++, sih++) {
+       for (i = 0; i < nr_sih_modules; i++, sih++) {
                u8 rxbuf[4];
                int j;
 
@@ -322,20 +428,24 @@ static int twl4030_init_sih_modules(unsigned line)
                if (!sih->bytes_ixr)
                        continue;
 
+               /* Not all the SIH modules support multiple interrupt lines */
+               if (sih->irq_lines <= line)
+                       continue;
+
                /* Clear pending interrupt status.  Either the read was
                 * enough, or we need to write those bits.  Repeat, in
                 * case an IRQ is pending (PENDDIS=0) ... that's not
                 * uncommon with PWR_INT.PWRON.
                 */
                for (j = 0; j < 2; j++) {
-                       status = twl4030_i2c_read(sih->module, rxbuf,
+                       status = twl_i2c_read(sih->module, rxbuf,
                                sih->mask[line].isr_offset, sih->bytes_ixr);
                        if (status < 0)
                                pr_err("twl4030: err %d initializing %s %s\n",
                                        status, sih->name, "ISR");
 
                        if (!sih->set_cor)
-                               status = twl4030_i2c_write(sih->module, buf,
+                               status = twl_i2c_write(sih->module, buf,
                                        sih->mask[line].isr_offset,
                                        sih->bytes_ixr);
                        /* else COR=1 means read sufficed.
@@ -404,7 +514,7 @@ static void twl4030_sih_do_mask(struct work_struct *work)
                return;
 
        /* write the whole mask ... simpler than subsetting it */
-       status = twl4030_i2c_write(sih->module, imr.bytes,
+       status = twl_i2c_write(sih->module, imr.bytes,
                        sih->mask[irq_line].imr_offset, sih->bytes_ixr);
        if (status)
                pr_err("twl4030: %s, %s --> %d\n", __func__,
@@ -435,7 +545,7 @@ static void twl4030_sih_do_edge(struct work_struct *work)
         * any processor on the other IRQ line, EDR registers are
         * shared.
         */
-       status = twl4030_i2c_read(sih->module, bytes + 1,
+       status = twl_i2c_read(sih->module, bytes + 1,
                        sih->edr_offset, sih->bytes_edr);
        if (status) {
                pr_err("twl4030: %s, %s --> %d\n", __func__,
@@ -469,7 +579,7 @@ static void twl4030_sih_do_edge(struct work_struct *work)
        }
 
        /* Write */
-       status = twl4030_i2c_write(sih->module, bytes,
+       status = twl_i2c_write(sih->module, bytes,
                        sih->edr_offset, sih->bytes_edr);
        if (status)
                pr_err("twl4030: %s, %s --> %d\n", __func__,
@@ -554,7 +664,7 @@ static inline int sih_read_isr(const struct sih *sih)
        /* FIXME need retry-on-error ... */
 
        isr.word = 0;
-       status = twl4030_i2c_read(sih->module, isr.bytes,
+       status = twl_i2c_read(sih->module, isr.bytes,
                        sih->mask[irq_line].isr_offset, sih->bytes_ixr);
 
        return (status < 0) ? status : le32_to_cpu(isr.word);
@@ -611,7 +721,7 @@ int twl4030_sih_setup(int module)
 
        /* only support modules with standard clear-on-read for now */
        for (sih_mod = 0, sih = sih_modules;
-                       sih_mod < ARRAY_SIZE(sih_modules);
+                       sih_mod < nr_sih_modules;
                        sih_mod++, sih++) {
                if (sih->module == module && sih->set_cor) {
                        if (!WARN((irq_base + sih->bits) > NR_IRQS,
@@ -668,7 +778,7 @@ int twl4030_sih_setup(int module)
 /* FIXME pass in which interrupt line we'll use ... */
 #define twl_irq_line   0
 
-int twl_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
+int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
 {
        static struct irq_chip  twl4030_irq_chip;
 
@@ -728,7 +838,8 @@ int twl_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
                goto fail_rqirq;
        }
 
-       task = kthread_run(twl4030_irq_thread, (void *)irq_num, "twl4030-irq");
+       task = kthread_run(twl4030_irq_thread, (void *)(long)irq_num,
+                                                               "twl4030-irq");
        if (IS_ERR(task)) {
                pr_err("twl4030: could not create irq %d thread!\n", irq_num);
                status = PTR_ERR(task);
@@ -747,7 +858,7 @@ fail:
        return status;
 }
 
-int twl_exit_irq(void)
+int twl4030_exit_irq(void)
 {
        /* FIXME undo twl_init_irq() */
        if (twl4030_irq_base) {
@@ -756,3 +867,16 @@ int twl_exit_irq(void)
        }
        return 0;
 }
+
+int twl4030_init_chip_irq(const char *chip)
+{
+       if (!strcmp(chip, "twl5031")) {
+               sih_modules = sih_modules_twl5031;
+               nr_sih_modules = ARRAY_SIZE(sih_modules_twl5031);
+       } else {
+               sih_modules = sih_modules_twl4030;
+               nr_sih_modules = ARRAY_SIZE(sih_modules_twl4030);
+       }
+
+       return 0;
+}
index d423e0c4176b600db5a5dfe511a6d9f05da7e143..0815292fdafc6c98147b6f0328ed1f98f3861b2d 100644 (file)
@@ -26,7 +26,7 @@
 
 #include <linux/module.h>
 #include <linux/pm.h>
-#include <linux/i2c/twl4030.h>
+#include <linux/i2c/twl.h>
 #include <linux/platform_device.h>
 
 #include <asm/mach-types.h>
@@ -67,19 +67,35 @@ static u8 twl4030_start_script_address = 0x2b;
 #define R_KEY_1                        0xC0
 #define R_KEY_2                        0x0C
 
-/* resource configuration registers */
-
-#define DEVGROUP_OFFSET                0
+/* resource configuration registers
+   <RESOURCE>_DEV_GRP   at address 'n+0'
+   <RESOURCE>_TYPE      at address 'n+1'
+   <RESOURCE>_REMAP     at address 'n+2'
+   <RESOURCE>_DEDICATED at address 'n+3'
+*/
+#define DEV_GRP_OFFSET         0
 #define TYPE_OFFSET            1
+#define REMAP_OFFSET           2
+#define DEDICATED_OFFSET       3
+
+/* Bit positions in the registers */
+
+/* <RESOURCE>_DEV_GRP */
+#define DEV_GRP_SHIFT          5
+#define DEV_GRP_MASK           (7 << DEV_GRP_SHIFT)
 
-/* Bit positions */
-#define DEVGROUP_SHIFT         5
-#define DEVGROUP_MASK          (7 << DEVGROUP_SHIFT)
+/* <RESOURCE>_TYPE */
 #define TYPE_SHIFT             0
 #define TYPE_MASK              (7 << TYPE_SHIFT)
 #define TYPE2_SHIFT            3
 #define TYPE2_MASK             (3 << TYPE2_SHIFT)
 
+/* <RESOURCE>_REMAP */
+#define SLEEP_STATE_SHIFT      0
+#define SLEEP_STATE_MASK       (0xf << SLEEP_STATE_SHIFT)
+#define OFF_STATE_SHIFT                4
+#define OFF_STATE_MASK         (0xf << OFF_STATE_SHIFT)
+
 static u8 res_config_addrs[] = {
        [RES_VAUX1]     = 0x17,
        [RES_VAUX2]     = 0x1b,
@@ -115,11 +131,11 @@ static int __init twl4030_write_script_byte(u8 address, u8 byte)
 {
        int err;
 
-       err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
+       err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
                                R_MEMORY_ADDRESS);
        if (err)
                goto out;
-       err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, byte,
+       err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, byte,
                                R_MEMORY_DATA);
 out:
        return err;
@@ -176,18 +192,18 @@ static int __init twl4030_config_wakeup3_sequence(u8 address)
        u8 data;
 
        /* Set SLEEP to ACTIVE SEQ address for P3 */
-       err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
+       err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
                                R_SEQ_ADD_S2A3);
        if (err)
                goto out;
 
        /* P3 LVL_WAKEUP should be on LEVEL */
-       err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
+       err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
                                R_P3_SW_EVENTS);
        if (err)
                goto out;
        data |= LVL_WAKEUP;
-       err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data,
+       err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data,
                                R_P3_SW_EVENTS);
 out:
        if (err)
@@ -201,42 +217,42 @@ static int __init twl4030_config_wakeup12_sequence(u8 address)
        u8 data;
 
        /* Set SLEEP to ACTIVE SEQ address for P1 and P2 */
-       err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
+       err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
                                R_SEQ_ADD_S2A12);
        if (err)
                goto out;
 
        /* P1/P2 LVL_WAKEUP should be on LEVEL */
-       err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
+       err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
                                R_P1_SW_EVENTS);
        if (err)
                goto out;
 
        data |= LVL_WAKEUP;
-       err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data,
+       err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data,
                                R_P1_SW_EVENTS);
        if (err)
                goto out;
 
-       err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
+       err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
                                R_P2_SW_EVENTS);
        if (err)
                goto out;
 
        data |= LVL_WAKEUP;
-       err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data,
+       err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data,
                                R_P2_SW_EVENTS);
        if (err)
                goto out;
 
        if (machine_is_omap_3430sdp() || machine_is_omap_ldp()) {
                /* Disabling AC charger effect on sleep-active transitions */
-               err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
+               err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
                                        R_CFG_P1_TRANSITION);
                if (err)
                        goto out;
                data &= ~(1<<1);
-               err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data ,
+               err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data ,
                                        R_CFG_P1_TRANSITION);
                if (err)
                        goto out;
@@ -254,7 +270,7 @@ static int __init twl4030_config_sleep_sequence(u8 address)
        int err;
 
        /* Set ACTIVE to SLEEP SEQ address in T2 memory*/
-       err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
+       err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
                                R_SEQ_ADD_A2S);
 
        if (err)
@@ -269,41 +285,41 @@ static int __init twl4030_config_warmreset_sequence(u8 address)
        u8 rd_data;
 
        /* Set WARM RESET SEQ address for P1 */
-       err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
+       err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
                                R_SEQ_ADD_WARM);
        if (err)
                goto out;
 
        /* P1/P2/P3 enable WARMRESET */
-       err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
+       err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
                                R_P1_SW_EVENTS);
        if (err)
                goto out;
 
        rd_data |= ENABLE_WARMRESET;
-       err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
+       err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
                                R_P1_SW_EVENTS);
        if (err)
                goto out;
 
-       err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
+       err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
                                R_P2_SW_EVENTS);
        if (err)
                goto out;
 
        rd_data |= ENABLE_WARMRESET;
-       err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
+       err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
                                R_P2_SW_EVENTS);
        if (err)
                goto out;
 
-       err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
+       err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
                                R_P3_SW_EVENTS);
        if (err)
                goto out;
 
        rd_data |= ENABLE_WARMRESET;
-       err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
+       err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
                                R_P3_SW_EVENTS);
 out:
        if (err)
@@ -317,6 +333,7 @@ static int __init twl4030_configure_resource(struct twl4030_resconfig *rconfig)
        int err;
        u8 type;
        u8 grp;
+       u8 remap;
 
        if (rconfig->resource > TOTAL_RESOURCES) {
                pr_err("TWL4030 Resource %d does not exist\n",
@@ -327,19 +344,19 @@ static int __init twl4030_configure_resource(struct twl4030_resconfig *rconfig)
        rconfig_addr = res_config_addrs[rconfig->resource];
 
        /* Set resource group */
-       err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &grp,
-                               rconfig_addr + DEVGROUP_OFFSET);
+       err = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &grp,
+                             rconfig_addr + DEV_GRP_OFFSET);
        if (err) {
                pr_err("TWL4030 Resource %d group could not be read\n",
                        rconfig->resource);
                return err;
        }
 
-       if (rconfig->devgroup >= 0) {
-               grp &= ~DEVGROUP_MASK;
-               grp |= rconfig->devgroup << DEVGROUP_SHIFT;
-               err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
-                                       grp, rconfig_addr + DEVGROUP_OFFSET);
+       if (rconfig->devgroup != TWL4030_RESCONFIG_UNDEF) {
+               grp &= ~DEV_GRP_MASK;
+               grp |= rconfig->devgroup << DEV_GRP_SHIFT;
+               err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                                      grp, rconfig_addr + DEV_GRP_OFFSET);
                if (err < 0) {
                        pr_err("TWL4030 failed to program devgroup\n");
                        return err;
@@ -347,7 +364,7 @@ static int __init twl4030_configure_resource(struct twl4030_resconfig *rconfig)
        }
 
        /* Set resource types */
-       err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &type,
+       err = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &type,
                                rconfig_addr + TYPE_OFFSET);
        if (err < 0) {
                pr_err("TWL4030 Resource %d type could not be read\n",
@@ -355,23 +372,50 @@ static int __init twl4030_configure_resource(struct twl4030_resconfig *rconfig)
                return err;
        }
 
-       if (rconfig->type >= 0) {
+       if (rconfig->type != TWL4030_RESCONFIG_UNDEF) {
                type &= ~TYPE_MASK;
                type |= rconfig->type << TYPE_SHIFT;
        }
 
-       if (rconfig->type2 >= 0) {
+       if (rconfig->type2 != TWL4030_RESCONFIG_UNDEF) {
                type &= ~TYPE2_MASK;
                type |= rconfig->type2 << TYPE2_SHIFT;
        }
 
-       err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+       err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
                                type, rconfig_addr + TYPE_OFFSET);
        if (err < 0) {
                pr_err("TWL4030 failed to program resource type\n");
                return err;
        }
 
+       /* Set remap states */
+       err = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &remap,
+                             rconfig_addr + REMAP_OFFSET);
+       if (err < 0) {
+               pr_err("TWL4030 Resource %d remap could not be read\n",
+                       rconfig->resource);
+               return err;
+       }
+
+       if (rconfig->remap_off != TWL4030_RESCONFIG_UNDEF) {
+               remap &= ~OFF_STATE_MASK;
+               remap |= rconfig->remap_off << OFF_STATE_SHIFT;
+       }
+
+       if (rconfig->remap_sleep != TWL4030_RESCONFIG_UNDEF) {
+               remap &= ~SLEEP_STATE_MASK;
+               remap |= rconfig->remap_off << SLEEP_STATE_SHIFT;
+       }
+
+       err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                              remap,
+                              rconfig_addr + REMAP_OFFSET);
+       if (err < 0) {
+               pr_err("TWL4030 failed to program remap\n");
+               return err;
+       }
+
        return 0;
 }
 
@@ -424,12 +468,12 @@ void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
        struct twl4030_resconfig *resconfig;
        u8 address = twl4030_start_script_address;
 
-       err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_1,
+       err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_1,
                                R_PROTECT_KEY);
        if (err)
                goto unlock;
 
-       err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_2,
+       err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_2,
                                R_PROTECT_KEY);
        if (err)
                goto unlock;
@@ -452,7 +496,7 @@ void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
                }
        }
 
-       err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, R_PROTECT_KEY);
+       err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, R_PROTECT_KEY);
        if (err)
                pr_err("TWL4030 Unable to relock registers\n");
        return;
diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c
new file mode 100644 (file)
index 0000000..10bf228
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ * twl6030-irq.c - TWL6030 irq support
+ *
+ * Copyright (C) 2005-2009 Texas Instruments, Inc.
+ *
+ * Modifications to defer interrupt handling to a kernel thread:
+ * Copyright (C) 2006 MontaVista Software, Inc.
+ *
+ * Based on tlv320aic23.c:
+ * Copyright (c) by Kai Svahn <kai.svahn@nokia.com>
+ *
+ * Code cleanup and modifications to IRQ handler.
+ * by syed khasim <x0khasim@ti.com>
+ *
+ * TWL6030 specific code and IRQ handling changes by
+ * Jagadeesh Bhaskar Pakaravoor <j-pakaravoor@ti.com>
+ * Balaji T K <balajitk@ti.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/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kthread.h>
+#include <linux/i2c/twl.h>
+
+/*
+ * TWL6030 (unlike its predecessors, which had two level interrupt handling)
+ * three interrupt registers INT_STS_A, INT_STS_B and INT_STS_C.
+ * It exposes status bits saying who has raised an interrupt. There are
+ * three mask registers that corresponds to these status registers, that
+ * enables/disables these interrupts.
+ *
+ * We set up IRQs starting at a platform-specified base. An interrupt map table,
+ * specifies mapping between interrupt number and the associated module.
+ *
+ */
+
+static int twl6030_interrupt_mapping[24] = {
+       PWR_INTR_OFFSET,        /* Bit 0        PWRON                   */
+       PWR_INTR_OFFSET,        /* Bit 1        RPWRON                  */
+       PWR_INTR_OFFSET,        /* Bit 2        BAT_VLOW                */
+       RTC_INTR_OFFSET,        /* Bit 3        RTC_ALARM               */
+       RTC_INTR_OFFSET,        /* Bit 4        RTC_PERIOD              */
+       HOTDIE_INTR_OFFSET,     /* Bit 5        HOT_DIE                 */
+       SMPSLDO_INTR_OFFSET,    /* Bit 6        VXXX_SHORT              */
+       SMPSLDO_INTR_OFFSET,    /* Bit 7        VMMC_SHORT              */
+
+       SMPSLDO_INTR_OFFSET,    /* Bit 8        VUSIM_SHORT             */
+       BATDETECT_INTR_OFFSET,  /* Bit 9        BAT                     */
+       SIMDETECT_INTR_OFFSET,  /* Bit 10       SIM                     */
+       MMCDETECT_INTR_OFFSET,  /* Bit 11       MMC                     */
+       RSV_INTR_OFFSET,        /* Bit 12       Reserved                */
+       MADC_INTR_OFFSET,       /* Bit 13       GPADC_RT_EOC            */
+       MADC_INTR_OFFSET,       /* Bit 14       GPADC_SW_EOC            */
+       GASGAUGE_INTR_OFFSET,   /* Bit 15       CC_AUTOCAL              */
+
+       USBOTG_INTR_OFFSET,     /* Bit 16       ID_WKUP                 */
+       USBOTG_INTR_OFFSET,     /* Bit 17       VBUS_WKUP               */
+       USBOTG_INTR_OFFSET,     /* Bit 18       ID                      */
+       USBOTG_INTR_OFFSET,     /* Bit 19       VBUS                    */
+       CHARGER_INTR_OFFSET,    /* Bit 20       CHRG_CTRL               */
+       CHARGER_INTR_OFFSET,    /* Bit 21       EXT_CHRG                */
+       CHARGER_INTR_OFFSET,    /* Bit 22       INT_CHRG                */
+       RSV_INTR_OFFSET,        /* Bit 23       Reserved                */
+};
+/*----------------------------------------------------------------------*/
+
+static unsigned twl6030_irq_base;
+
+static struct completion irq_event;
+
+/*
+ * This thread processes interrupts reported by the Primary Interrupt Handler.
+ */
+static int twl6030_irq_thread(void *data)
+{
+       long irq = (long)data;
+       static unsigned i2c_errors;
+       static const unsigned max_i2c_errors = 100;
+       int ret;
+
+       current->flags |= PF_NOFREEZE;
+
+       while (!kthread_should_stop()) {
+               int i;
+               union {
+               u8 bytes[4];
+               u32 int_sts;
+               } sts;
+
+               /* Wait for IRQ, then read PIH irq status (also blocking) */
+               wait_for_completion_interruptible(&irq_event);
+
+               /* read INT_STS_A, B and C in one shot using a burst read */
+               ret = twl_i2c_read(TWL_MODULE_PIH, sts.bytes,
+                               REG_INT_STS_A, 3);
+               if (ret) {
+                       pr_warning("twl6030: I2C error %d reading PIH ISR\n",
+                                       ret);
+                       if (++i2c_errors >= max_i2c_errors) {
+                               printk(KERN_ERR "Maximum I2C error count"
+                                               " exceeded.  Terminating %s.\n",
+                                               __func__);
+                               break;
+                       }
+                       complete(&irq_event);
+                       continue;
+               }
+
+
+
+               sts.bytes[3] = 0; /* Only 24 bits are valid*/
+
+               for (i = 0; sts.int_sts; sts.int_sts >>= 1, i++) {
+                       local_irq_disable();
+                       if (sts.int_sts & 0x1) {
+                               int module_irq = twl6030_irq_base +
+                                       twl6030_interrupt_mapping[i];
+                               struct irq_desc *d = irq_to_desc(module_irq);
+
+                               if (!d) {
+                                       pr_err("twl6030: Invalid SIH IRQ: %d\n",
+                                              module_irq);
+                                       return -EINVAL;
+                               }
+
+                               /* These can't be masked ... always warn
+                                * if we get any surprises.
+                                */
+                               if (d->status & IRQ_DISABLED)
+                                       note_interrupt(module_irq, d,
+                                                       IRQ_NONE);
+                               else
+                                       d->handle_irq(module_irq, d);
+
+                       }
+               local_irq_enable();
+               }
+               ret = twl_i2c_write(TWL_MODULE_PIH, sts.bytes,
+                               REG_INT_STS_A, 3); /* clear INT_STS_A */
+               if (ret)
+                       pr_warning("twl6030: I2C error in clearing PIH ISR\n");
+
+               enable_irq(irq);
+       }
+
+       return 0;
+}
+
+/*
+ * handle_twl6030_int() is the desc->handle method for the twl6030 interrupt.
+ * This is a chained interrupt, so there is no desc->action method for it.
+ * Now we need to query the interrupt controller in the twl6030 to determine
+ * which module is generating the interrupt request.  However, we can't do i2c
+ * transactions in interrupt context, so we must defer that work to a kernel
+ * thread.  All we do here is acknowledge and mask the interrupt and wakeup
+ * the kernel thread.
+ */
+static irqreturn_t handle_twl6030_pih(int irq, void *devid)
+{
+       disable_irq_nosync(irq);
+       complete(devid);
+       return IRQ_HANDLED;
+}
+
+/*----------------------------------------------------------------------*/
+
+static inline void activate_irq(int irq)
+{
+#ifdef CONFIG_ARM
+       /* ARM requires an extra step to clear IRQ_NOREQUEST, which it
+        * sets on behalf of every irq_chip.  Also sets IRQ_NOPROBE.
+        */
+       set_irq_flags(irq, IRQF_VALID);
+#else
+       /* same effect on other architectures */
+       set_irq_noprobe(irq);
+#endif
+}
+
+/*----------------------------------------------------------------------*/
+
+static unsigned twl6030_irq_next;
+
+/*----------------------------------------------------------------------*/
+int twl6030_interrupt_unmask(u8 bit_mask, u8 offset)
+{
+       int ret;
+       u8 unmask_value;
+       ret = twl_i2c_read_u8(TWL_MODULE_PIH, &unmask_value,
+                       REG_INT_STS_A + offset);
+       unmask_value &= (~(bit_mask));
+       ret |= twl_i2c_write_u8(TWL_MODULE_PIH, unmask_value,
+                       REG_INT_STS_A + offset); /* unmask INT_MSK_A/B/C */
+       return ret;
+}
+EXPORT_SYMBOL(twl6030_interrupt_unmask);
+
+int twl6030_interrupt_mask(u8 bit_mask, u8 offset)
+{
+       int ret;
+       u8 mask_value;
+       ret = twl_i2c_read_u8(TWL_MODULE_PIH, &mask_value,
+                       REG_INT_STS_A + offset);
+       mask_value |= (bit_mask);
+       ret |= twl_i2c_write_u8(TWL_MODULE_PIH, mask_value,
+                       REG_INT_STS_A + offset); /* mask INT_MSK_A/B/C */
+       return ret;
+}
+EXPORT_SYMBOL(twl6030_interrupt_mask);
+
+int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
+{
+
+       int     status = 0;
+       int     i;
+       struct task_struct      *task;
+       int ret;
+       u8 mask[4];
+
+       static struct irq_chip  twl6030_irq_chip;
+       mask[1] = 0xFF;
+       mask[2] = 0xFF;
+       mask[3] = 0xFF;
+       ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0],
+                       REG_INT_MSK_LINE_A, 3); /* MASK ALL INT LINES */
+       ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0],
+                       REG_INT_MSK_STS_A, 3); /* MASK ALL INT STS */
+       ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0],
+                       REG_INT_STS_A, 3); /* clear INT_STS_A,B,C */
+
+       twl6030_irq_base = irq_base;
+
+       /* install an irq handler for each of the modules;
+        * clone dummy irq_chip since PIH can't *do* anything
+        */
+       twl6030_irq_chip = dummy_irq_chip;
+       twl6030_irq_chip.name = "twl6030";
+       twl6030_irq_chip.set_type = NULL;
+
+       for (i = irq_base; i < irq_end; i++) {
+               set_irq_chip_and_handler(i, &twl6030_irq_chip,
+                               handle_simple_irq);
+               activate_irq(i);
+       }
+
+       twl6030_irq_next = i;
+       pr_info("twl6030: %s (irq %d) chaining IRQs %d..%d\n", "PIH",
+                       irq_num, irq_base, twl6030_irq_next - 1);
+
+       /* install an irq handler to demultiplex the TWL6030 interrupt */
+       init_completion(&irq_event);
+       task = kthread_run(twl6030_irq_thread, (void *)irq_num, "twl6030-irq");
+       if (IS_ERR(task)) {
+               pr_err("twl6030: could not create irq %d thread!\n", irq_num);
+               status = PTR_ERR(task);
+               goto fail_kthread;
+       }
+
+       status = request_irq(irq_num, handle_twl6030_pih, IRQF_DISABLED,
+                               "TWL6030-PIH", &irq_event);
+       if (status < 0) {
+               pr_err("twl6030: could not claim irq%d: %d\n", irq_num, status);
+               goto fail_irq;
+       }
+       return status;
+fail_irq:
+       free_irq(irq_num, &irq_event);
+
+fail_kthread:
+       for (i = irq_base; i < irq_end; i++)
+               set_irq_chip_and_handler(i, NULL, NULL);
+       return status;
+}
+
+int twl6030_exit_irq(void)
+{
+
+       if (twl6030_irq_base) {
+               pr_err("twl6030: can't yet clean up IRQs?\n");
+               return -ENOSYS;
+       }
+       return 0;
+}
+
index 7f27576ca0464bede0c3bb6e1a1f86d04630f5eb..223a90c7492fbe71710dd4e1538608db90b75605 100644 (file)
@@ -90,9 +90,10 @@ int wm831x_isinkv_values[WM831X_ISINK_MAX_ISEL + 1] = {
 EXPORT_SYMBOL_GPL(wm831x_isinkv_values);
 
 enum wm831x_parent {
-       WM8310 = 0,
-       WM8311 = 1,
-       WM8312 = 2,
+       WM8310 = 0x8310,
+       WM8311 = 0x8311,
+       WM8312 = 0x8312,
+       WM8320 = 0x8320,
 };
 
 static int wm831x_reg_locked(struct wm831x *wm831x, unsigned short reg)
@@ -478,6 +479,20 @@ static struct resource wm831x_dcdc4_resources[] = {
        },
 };
 
+static struct resource wm8320_dcdc4_buck_resources[] = {
+       {
+               .start = WM831X_DC4_CONTROL,
+               .end   = WM832X_DC4_SLEEP_CONTROL,
+               .flags = IORESOURCE_IO,
+       },
+       {
+               .name  = "UV",
+               .start = WM831X_IRQ_UV_DC4,
+               .end   = WM831X_IRQ_UV_DC4,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
 static struct resource wm831x_gpio_resources[] = {
        {
                .start = WM831X_IRQ_GPIO_1,
@@ -1237,6 +1252,137 @@ static struct mfd_cell wm8312_devs[] = {
        },
 };
 
+static struct mfd_cell wm8320_devs[] = {
+       {
+               .name = "wm831x-backup",
+       },
+       {
+               .name = "wm831x-buckv",
+               .id = 1,
+               .num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
+               .resources = wm831x_dcdc1_resources,
+       },
+       {
+               .name = "wm831x-buckv",
+               .id = 2,
+               .num_resources = ARRAY_SIZE(wm831x_dcdc2_resources),
+               .resources = wm831x_dcdc2_resources,
+       },
+       {
+               .name = "wm831x-buckp",
+               .id = 3,
+               .num_resources = ARRAY_SIZE(wm831x_dcdc3_resources),
+               .resources = wm831x_dcdc3_resources,
+       },
+       {
+               .name = "wm831x-buckp",
+               .id = 4,
+               .num_resources = ARRAY_SIZE(wm8320_dcdc4_buck_resources),
+               .resources = wm8320_dcdc4_buck_resources,
+       },
+       {
+               .name = "wm831x-gpio",
+               .num_resources = ARRAY_SIZE(wm831x_gpio_resources),
+               .resources = wm831x_gpio_resources,
+       },
+       {
+               .name = "wm831x-hwmon",
+       },
+       {
+               .name = "wm831x-ldo",
+               .id = 1,
+               .num_resources = ARRAY_SIZE(wm831x_ldo1_resources),
+               .resources = wm831x_ldo1_resources,
+       },
+       {
+               .name = "wm831x-ldo",
+               .id = 2,
+               .num_resources = ARRAY_SIZE(wm831x_ldo2_resources),
+               .resources = wm831x_ldo2_resources,
+       },
+       {
+               .name = "wm831x-ldo",
+               .id = 3,
+               .num_resources = ARRAY_SIZE(wm831x_ldo3_resources),
+               .resources = wm831x_ldo3_resources,
+       },
+       {
+               .name = "wm831x-ldo",
+               .id = 4,
+               .num_resources = ARRAY_SIZE(wm831x_ldo4_resources),
+               .resources = wm831x_ldo4_resources,
+       },
+       {
+               .name = "wm831x-ldo",
+               .id = 5,
+               .num_resources = ARRAY_SIZE(wm831x_ldo5_resources),
+               .resources = wm831x_ldo5_resources,
+       },
+       {
+               .name = "wm831x-ldo",
+               .id = 6,
+               .num_resources = ARRAY_SIZE(wm831x_ldo6_resources),
+               .resources = wm831x_ldo6_resources,
+       },
+       {
+               .name = "wm831x-aldo",
+               .id = 7,
+               .num_resources = ARRAY_SIZE(wm831x_ldo7_resources),
+               .resources = wm831x_ldo7_resources,
+       },
+       {
+               .name = "wm831x-aldo",
+               .id = 8,
+               .num_resources = ARRAY_SIZE(wm831x_ldo8_resources),
+               .resources = wm831x_ldo8_resources,
+       },
+       {
+               .name = "wm831x-aldo",
+               .id = 9,
+               .num_resources = ARRAY_SIZE(wm831x_ldo9_resources),
+               .resources = wm831x_ldo9_resources,
+       },
+       {
+               .name = "wm831x-aldo",
+               .id = 10,
+               .num_resources = ARRAY_SIZE(wm831x_ldo10_resources),
+               .resources = wm831x_ldo10_resources,
+       },
+       {
+               .name = "wm831x-alive-ldo",
+               .id = 11,
+               .num_resources = ARRAY_SIZE(wm831x_ldo11_resources),
+               .resources = wm831x_ldo11_resources,
+       },
+       {
+               .name = "wm831x-on",
+               .num_resources = ARRAY_SIZE(wm831x_on_resources),
+               .resources = wm831x_on_resources,
+       },
+       {
+               .name = "wm831x-rtc",
+               .num_resources = ARRAY_SIZE(wm831x_rtc_resources),
+               .resources = wm831x_rtc_resources,
+       },
+       {
+               .name = "wm831x-status",
+               .id = 1,
+               .num_resources = ARRAY_SIZE(wm831x_status1_resources),
+               .resources = wm831x_status1_resources,
+       },
+       {
+               .name = "wm831x-status",
+               .id = 2,
+               .num_resources = ARRAY_SIZE(wm831x_status2_resources),
+               .resources = wm831x_status2_resources,
+       },
+       {
+               .name = "wm831x-watchdog",
+               .num_resources = ARRAY_SIZE(wm831x_wdt_resources),
+               .resources = wm831x_wdt_resources,
+       },
+};
+
 static struct mfd_cell backlight_devs[] = {
        {
                .name = "wm831x-backlight",
@@ -1282,50 +1428,37 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
                goto err;
        }
 
+       /* Some engineering samples do not have the ID set, rely on
+        * the device being registered correctly.
+        */
+       if (ret == 0) {
+               dev_info(wm831x->dev, "Device is an engineering sample\n");
+               ret = id;
+       }
+
        switch (ret) {
-       case 0x8310:
+       case WM8310:
                parent = WM8310;
-               switch (rev) {
-               case 0:
-                       dev_info(wm831x->dev, "WM8310 revision %c\n",
-                                'A' + rev);
-                       break;
-               }
+               wm831x->num_gpio = 16;
+               dev_info(wm831x->dev, "WM8310 revision %c\n", 'A' + rev);
                break;
 
-       case 0x8311:
+       case WM8311:
                parent = WM8311;
-               switch (rev) {
-               case 0:
-                       dev_info(wm831x->dev, "WM8311 revision %c\n",
-                                'A' + rev);
-                       break;
-               }
+               wm831x->num_gpio = 16;
+               dev_info(wm831x->dev, "WM8311 revision %c\n", 'A' + rev);
                break;
 
-       case 0x8312:
+       case WM8312:
                parent = WM8312;
-               switch (rev) {
-               case 0:
-                       dev_info(wm831x->dev, "WM8312 revision %c\n",
-                                'A' + rev);
-                       break;
-               }
+               wm831x->num_gpio = 16;
+               dev_info(wm831x->dev, "WM8312 revision %c\n", 'A' + rev);
                break;
 
-       case 0:
-               /* Some engineering samples do not have the ID set,
-                * rely on the device being registered correctly.
-                * This will need revisiting for future devices with
-                * multiple dies.
-                */
-               parent = id;
-               switch (rev) {
-               case 0:
-                       dev_info(wm831x->dev, "WM831%d ES revision %c\n",
-                                parent, 'A' + rev);
-                       break;
-               }
+       case WM8320:
+               parent = WM8320;
+               wm831x->num_gpio = 12;
+               dev_info(wm831x->dev, "WM8320 revision %c\n", 'A' + rev);
                break;
 
        default:
@@ -1338,7 +1471,7 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
         * current parts.
         */
        if (parent != id)
-               dev_warn(wm831x->dev, "Device was registered as a WM831%lu\n",
+               dev_warn(wm831x->dev, "Device was registered as a WM%lx\n",
                         id);
 
        /* Bootstrap the user key */
@@ -1371,18 +1504,24 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
        case WM8310:
                ret = mfd_add_devices(wm831x->dev, -1,
                                      wm8310_devs, ARRAY_SIZE(wm8310_devs),
-                                     NULL, 0);
+                                     NULL, wm831x->irq_base);
                break;
 
        case WM8311:
                ret = mfd_add_devices(wm831x->dev, -1,
                                      wm8311_devs, ARRAY_SIZE(wm8311_devs),
-                                     NULL, 0);
+                                     NULL, wm831x->irq_base);
                break;
 
        case WM8312:
                ret = mfd_add_devices(wm831x->dev, -1,
                                      wm8312_devs, ARRAY_SIZE(wm8312_devs),
+                                     NULL, wm831x->irq_base);
+               break;
+
+       case WM8320:
+               ret = mfd_add_devices(wm831x->dev, -1,
+                                     wm8320_devs, ARRAY_SIZE(wm8320_devs),
                                      NULL, 0);
                break;
 
@@ -1399,7 +1538,8 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
        if (pdata && pdata->backlight) {
                /* Treat errors as non-critical */
                ret = mfd_add_devices(wm831x->dev, -1, backlight_devs,
-                                     ARRAY_SIZE(backlight_devs), NULL, 0);
+                                     ARRAY_SIZE(backlight_devs), NULL,
+                                     wm831x->irq_base);
                if (ret < 0)
                        dev_err(wm831x->dev, "Failed to add backlight: %d\n",
                                ret);
@@ -1511,6 +1651,7 @@ static const struct i2c_device_id wm831x_i2c_id[] = {
        { "wm8310", WM8310 },
        { "wm8311", WM8311 },
        { "wm8312", WM8312 },
+       { "wm8320", WM8320 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id);
index ac056ea6b66ed6c432e47683e0a9fe78ac0e464e..301327697117da5c7ac1fcb8c759bbad7bdf2b37 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/i2c.h>
+#include <linux/irq.h>
 #include <linux/mfd/core.h>
 #include <linux/interrupt.h>
 
@@ -339,110 +340,71 @@ static inline int irq_data_to_mask_reg(struct wm831x_irq_data *irq_data)
        return WM831X_INTERRUPT_STATUS_1_MASK - 1 + irq_data->reg;
 }
 
-static void __wm831x_enable_irq(struct wm831x *wm831x, int irq)
+static inline struct wm831x_irq_data *irq_to_wm831x_irq(struct wm831x *wm831x,
+                                                       int irq)
 {
-       struct wm831x_irq_data *irq_data = &wm831x_irqs[irq];
-
-       wm831x->irq_masks[irq_data->reg - 1] &= ~irq_data->mask;
-       wm831x_reg_write(wm831x, irq_data_to_mask_reg(irq_data),
-                        wm831x->irq_masks[irq_data->reg - 1]);
+       return &wm831x_irqs[irq - wm831x->irq_base];
 }
 
-void wm831x_enable_irq(struct wm831x *wm831x, int irq)
+static void wm831x_irq_lock(unsigned int irq)
 {
-       mutex_lock(&wm831x->irq_lock);
-       __wm831x_enable_irq(wm831x, irq);
-       mutex_unlock(&wm831x->irq_lock);
-}
-EXPORT_SYMBOL_GPL(wm831x_enable_irq);
+       struct wm831x *wm831x = get_irq_chip_data(irq);
 
-static void __wm831x_disable_irq(struct wm831x *wm831x, int irq)
-{
-       struct wm831x_irq_data *irq_data = &wm831x_irqs[irq];
-
-       wm831x->irq_masks[irq_data->reg - 1] |= irq_data->mask;
-       wm831x_reg_write(wm831x, irq_data_to_mask_reg(irq_data),
-                        wm831x->irq_masks[irq_data->reg - 1]);
-}
-
-void wm831x_disable_irq(struct wm831x *wm831x, int irq)
-{
        mutex_lock(&wm831x->irq_lock);
-       __wm831x_disable_irq(wm831x, irq);
-       mutex_unlock(&wm831x->irq_lock);
 }
-EXPORT_SYMBOL_GPL(wm831x_disable_irq);
 
-int wm831x_request_irq(struct wm831x *wm831x,
-                      unsigned int irq, irq_handler_t handler,
-                      unsigned long flags, const char *name,
-                      void *dev)
+static void wm831x_irq_sync_unlock(unsigned int irq)
 {
-       int ret = 0;
-
-       if (irq < 0 || irq >= WM831X_NUM_IRQS)
-               return -EINVAL;
-
-       mutex_lock(&wm831x->irq_lock);
-
-       if (wm831x_irqs[irq].handler) {
-               dev_err(wm831x->dev, "Already have handler for IRQ %d\n", irq);
-               ret = -EINVAL;
-               goto out;
+       struct wm831x *wm831x = get_irq_chip_data(irq);
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(wm831x->irq_masks_cur); i++) {
+               /* If there's been a change in the mask write it back
+                * to the hardware. */
+               if (wm831x->irq_masks_cur[i] != wm831x->irq_masks_cache[i]) {
+                       wm831x->irq_masks_cache[i] = wm831x->irq_masks_cur[i];
+                       wm831x_reg_write(wm831x,
+                                        WM831X_INTERRUPT_STATUS_1_MASK + i,
+                                        wm831x->irq_masks_cur[i]);
+               }
        }
 
-       wm831x_irqs[irq].handler = handler;
-       wm831x_irqs[irq].handler_data = dev;
-
-       __wm831x_enable_irq(wm831x, irq);
-
-out:
        mutex_unlock(&wm831x->irq_lock);
-
-       return ret;
 }
-EXPORT_SYMBOL_GPL(wm831x_request_irq);
 
-void wm831x_free_irq(struct wm831x *wm831x, unsigned int irq, void *data)
+static void wm831x_irq_unmask(unsigned int irq)
 {
-       if (irq < 0 || irq >= WM831X_NUM_IRQS)
-               return;
-
-       mutex_lock(&wm831x->irq_lock);
+       struct wm831x *wm831x = get_irq_chip_data(irq);
+       struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, irq);
 
-       wm831x_irqs[irq].handler = NULL;
-       wm831x_irqs[irq].handler_data = NULL;
-
-       __wm831x_disable_irq(wm831x, irq);
-
-       mutex_unlock(&wm831x->irq_lock);
+       wm831x->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
 }
-EXPORT_SYMBOL_GPL(wm831x_free_irq);
 
-
-static void wm831x_handle_irq(struct wm831x *wm831x, int irq, int status)
+static void wm831x_irq_mask(unsigned int irq)
 {
-       struct wm831x_irq_data *irq_data = &wm831x_irqs[irq];
-
-       if (irq_data->handler) {
-               irq_data->handler(irq, irq_data->handler_data);
-               wm831x_reg_write(wm831x, irq_data_to_status_reg(irq_data),
-                                irq_data->mask);
-       } else {
-               dev_err(wm831x->dev, "Unhandled IRQ %d, masking\n", irq);
-               __wm831x_disable_irq(wm831x, irq);
-       }
+       struct wm831x *wm831x = get_irq_chip_data(irq);
+       struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, irq);
+
+       wm831x->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
 }
 
-/* Main interrupt handling occurs in a workqueue since we need
- * interrupts enabled to interact with the chip. */
-static void wm831x_irq_worker(struct work_struct *work)
+static struct irq_chip wm831x_irq_chip = {
+       .name = "wm831x",
+       .bus_lock = wm831x_irq_lock,
+       .bus_sync_unlock = wm831x_irq_sync_unlock,
+       .mask = wm831x_irq_mask,
+       .unmask = wm831x_irq_unmask,
+};
+
+/* The processing of the primary interrupt occurs in a thread so that
+ * we can interact with the device over I2C or SPI. */
+static irqreturn_t wm831x_irq_thread(int irq, void *data)
 {
-       struct wm831x *wm831x = container_of(work, struct wm831x, irq_work);
+       struct wm831x *wm831x = data;
        unsigned int i;
        int primary;
-       int status_regs[5];
-       int read[5] = { 0 };
+       int status_regs[WM831X_NUM_IRQ_REGS] = { 0 };
+       int read[WM831X_NUM_IRQ_REGS] = { 0 };
        int *status;
 
        primary = wm831x_reg_read(wm831x, WM831X_SYSTEM_INTERRUPTS);
@@ -452,8 +414,6 @@ static void wm831x_irq_worker(struct work_struct *work)
                goto out;
        }
 
-       mutex_lock(&wm831x->irq_lock);
-
        for (i = 0; i < ARRAY_SIZE(wm831x_irqs); i++) {
                int offset = wm831x_irqs[i].reg - 1;
 
@@ -471,41 +431,34 @@ static void wm831x_irq_worker(struct work_struct *work)
                                dev_err(wm831x->dev,
                                        "Failed to read IRQ status: %d\n",
                                        *status);
-                               goto out_lock;
+                               goto out;
                        }
 
-                       /* Mask out the disabled IRQs */
-                       *status &= ~wm831x->irq_masks[offset];
                        read[offset] = 1;
                }
 
-               if (*status & wm831x_irqs[i].mask)
-                       wm831x_handle_irq(wm831x, i, *status);
+               /* Report it if it isn't masked, or forget the status. */
+               if ((*status & ~wm831x->irq_masks_cur[offset])
+                   & wm831x_irqs[i].mask)
+                       handle_nested_irq(wm831x->irq_base + i);
+               else
+                       *status &= ~wm831x_irqs[i].mask;
        }
 
-out_lock:
-       mutex_unlock(&wm831x->irq_lock);
 out:
-       enable_irq(wm831x->irq);
-}
-
-
-static irqreturn_t wm831x_cpu_irq(int irq, void *data)
-{
-       struct wm831x *wm831x = data;
-
-       /* Shut the interrupt to the CPU up and schedule the actual
-        * handler; we can't check that the IRQ is asserted. */
-       disable_irq_nosync(irq);
-
-       queue_work(wm831x->irq_wq, &wm831x->irq_work);
+       for (i = 0; i < ARRAY_SIZE(status_regs); i++) {
+               if (status_regs[i])
+                       wm831x_reg_write(wm831x, WM831X_INTERRUPT_STATUS_1 + i,
+                                        status_regs[i]);
+       }
 
        return IRQ_HANDLED;
 }
 
 int wm831x_irq_init(struct wm831x *wm831x, int irq)
 {
-       int i, ret;
+       struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+       int i, cur_irq, ret;
 
        mutex_init(&wm831x->irq_lock);
 
@@ -515,41 +468,53 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq)
                return 0;
        }
 
-
-       wm831x->irq_wq = create_singlethread_workqueue("wm831x-irq");
-       if (!wm831x->irq_wq) {
-               dev_err(wm831x->dev, "Failed to allocate IRQ worker\n");
-               return -ESRCH;
+       if (!pdata || !pdata->irq_base) {
+               dev_err(wm831x->dev,
+                       "No interrupt base specified, no interrupts\n");
+               return 0;
        }
 
        wm831x->irq = irq;
-       INIT_WORK(&wm831x->irq_work, wm831x_irq_worker);
+       wm831x->irq_base = pdata->irq_base;
 
        /* Mask the individual interrupt sources */
-       for (i = 0; i < ARRAY_SIZE(wm831x->irq_masks); i++) {
-               wm831x->irq_masks[i] = 0xffff;
+       for (i = 0; i < ARRAY_SIZE(wm831x->irq_masks_cur); i++) {
+               wm831x->irq_masks_cur[i] = 0xffff;
+               wm831x->irq_masks_cache[i] = 0xffff;
                wm831x_reg_write(wm831x, WM831X_INTERRUPT_STATUS_1_MASK + i,
                                 0xffff);
        }
 
-       /* Enable top level interrupts, we mask at secondary level */
-       wm831x_reg_write(wm831x, WM831X_SYSTEM_INTERRUPTS_MASK, 0);
+       /* Register them with genirq */
+       for (cur_irq = wm831x->irq_base;
+            cur_irq < ARRAY_SIZE(wm831x_irqs) + wm831x->irq_base;
+            cur_irq++) {
+               set_irq_chip_data(cur_irq, wm831x);
+               set_irq_chip_and_handler(cur_irq, &wm831x_irq_chip,
+                                        handle_edge_irq);
+               set_irq_nested_thread(cur_irq, 1);
+
+               /* ARM needs us to explicitly flag the IRQ as valid
+                * and will set them noprobe when we do so. */
+#ifdef CONFIG_ARM
+               set_irq_flags(cur_irq, IRQF_VALID);
+#else
+               set_irq_noprobe(cur_irq);
+#endif
+       }
 
-       /* We're good to go.  We set IRQF_SHARED since there's a
-        * chance the driver will interoperate with another driver but
-        * the need to disable the IRQ while handing via I2C/SPI means
-        * that this may break and performance will be impacted.  If
-        * this does happen it's a hardware design issue and the only
-        * other alternative would be polling.
-        */
-       ret = request_irq(irq, wm831x_cpu_irq, IRQF_TRIGGER_LOW | IRQF_SHARED,
-                         "wm831x", wm831x);
+       ret = request_threaded_irq(irq, NULL, wm831x_irq_thread,
+                                  IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+                                  "wm831x", wm831x);
        if (ret != 0) {
                dev_err(wm831x->dev, "Failed to request IRQ %d: %d\n",
                        irq, ret);
                return ret;
        }
 
+       /* Enable top level interrupts, we mask at secondary level */
+       wm831x_reg_write(wm831x, WM831X_SYSTEM_INTERRUPTS_MASK, 0);
+
        return 0;
 }
 
index ba27c9dc1ad39284a04ebcb8e11c8b7fd3d8c67e..8485a70180605d0eea68cb1b1d98872541846c5c 100644 (file)
@@ -337,733 +337,6 @@ int wm8350_reg_unlock(struct wm8350 *wm8350)
 }
 EXPORT_SYMBOL_GPL(wm8350_reg_unlock);
 
-static void wm8350_irq_call_handler(struct wm8350 *wm8350, int irq)
-{
-       mutex_lock(&wm8350->irq_mutex);
-
-       if (wm8350->irq[irq].handler)
-               wm8350->irq[irq].handler(wm8350, irq, wm8350->irq[irq].data);
-       else {
-               dev_err(wm8350->dev, "irq %d nobody cared. now masked.\n",
-                       irq);
-               wm8350_mask_irq(wm8350, irq);
-       }
-
-       mutex_unlock(&wm8350->irq_mutex);
-}
-
-/*
- * This is a threaded IRQ handler so can access I2C/SPI.  Since all
- * interrupts are clear on read the IRQ line will be reasserted and
- * the physical IRQ will be handled again if another interrupt is
- * asserted while we run - in the normal course of events this is a
- * rare occurrence so we save I2C/SPI reads.
- */
-static irqreturn_t wm8350_irq(int irq, void *data)
-{
-       struct wm8350 *wm8350 = data;
-       u16 level_one, status1, status2, comp;
-
-       /* TODO: Use block reads to improve performance? */
-       level_one = wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS)
-               & ~wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK);
-       status1 = wm8350_reg_read(wm8350, WM8350_INT_STATUS_1)
-               & ~wm8350_reg_read(wm8350, WM8350_INT_STATUS_1_MASK);
-       status2 = wm8350_reg_read(wm8350, WM8350_INT_STATUS_2)
-               & ~wm8350_reg_read(wm8350, WM8350_INT_STATUS_2_MASK);
-       comp = wm8350_reg_read(wm8350, WM8350_COMPARATOR_INT_STATUS)
-               & ~wm8350_reg_read(wm8350, WM8350_COMPARATOR_INT_STATUS_MASK);
-
-       /* over current */
-       if (level_one & WM8350_OC_INT) {
-               u16 oc;
-
-               oc = wm8350_reg_read(wm8350, WM8350_OVER_CURRENT_INT_STATUS);
-               oc &= ~wm8350_reg_read(wm8350,
-                                      WM8350_OVER_CURRENT_INT_STATUS_MASK);
-
-               if (oc & WM8350_OC_LS_EINT)     /* limit switch */
-                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_OC_LS);
-       }
-
-       /* under voltage */
-       if (level_one & WM8350_UV_INT) {
-               u16 uv;
-
-               uv = wm8350_reg_read(wm8350, WM8350_UNDER_VOLTAGE_INT_STATUS);
-               uv &= ~wm8350_reg_read(wm8350,
-                                      WM8350_UNDER_VOLTAGE_INT_STATUS_MASK);
-
-               if (uv & WM8350_UV_DC1_EINT)
-                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC1);
-               if (uv & WM8350_UV_DC2_EINT)
-                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC2);
-               if (uv & WM8350_UV_DC3_EINT)
-                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC3);
-               if (uv & WM8350_UV_DC4_EINT)
-                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC4);
-               if (uv & WM8350_UV_DC5_EINT)
-                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC5);
-               if (uv & WM8350_UV_DC6_EINT)
-                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC6);
-               if (uv & WM8350_UV_LDO1_EINT)
-                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO1);
-               if (uv & WM8350_UV_LDO2_EINT)
-                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO2);
-               if (uv & WM8350_UV_LDO3_EINT)
-                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO3);
-               if (uv & WM8350_UV_LDO4_EINT)
-                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO4);
-       }
-
-       /* charger, RTC */
-       if (status1) {
-               if (status1 & WM8350_CHG_BAT_HOT_EINT)
-                       wm8350_irq_call_handler(wm8350,
-                                               WM8350_IRQ_CHG_BAT_HOT);
-               if (status1 & WM8350_CHG_BAT_COLD_EINT)
-                       wm8350_irq_call_handler(wm8350,
-                                               WM8350_IRQ_CHG_BAT_COLD);
-               if (status1 & WM8350_CHG_BAT_FAIL_EINT)
-                       wm8350_irq_call_handler(wm8350,
-                                               WM8350_IRQ_CHG_BAT_FAIL);
-               if (status1 & WM8350_CHG_TO_EINT)
-                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_TO);
-               if (status1 & WM8350_CHG_END_EINT)
-                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_END);
-               if (status1 & WM8350_CHG_START_EINT)
-                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_START);
-               if (status1 & WM8350_CHG_FAST_RDY_EINT)
-                       wm8350_irq_call_handler(wm8350,
-                                               WM8350_IRQ_CHG_FAST_RDY);
-               if (status1 & WM8350_CHG_VBATT_LT_3P9_EINT)
-                       wm8350_irq_call_handler(wm8350,
-                                               WM8350_IRQ_CHG_VBATT_LT_3P9);
-               if (status1 & WM8350_CHG_VBATT_LT_3P1_EINT)
-                       wm8350_irq_call_handler(wm8350,
-                                               WM8350_IRQ_CHG_VBATT_LT_3P1);
-               if (status1 & WM8350_CHG_VBATT_LT_2P85_EINT)
-                       wm8350_irq_call_handler(wm8350,
-                                               WM8350_IRQ_CHG_VBATT_LT_2P85);
-               if (status1 & WM8350_RTC_ALM_EINT)
-                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_ALM);
-               if (status1 & WM8350_RTC_SEC_EINT)
-                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_SEC);
-               if (status1 & WM8350_RTC_PER_EINT)
-                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_PER);
-       }
-
-       /* current sink, system, aux adc */
-       if (status2) {
-               if (status2 & WM8350_CS1_EINT)
-                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_CS1);
-               if (status2 & WM8350_CS2_EINT)
-                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_CS2);
-
-               if (status2 & WM8350_SYS_HYST_COMP_FAIL_EINT)
-                       wm8350_irq_call_handler(wm8350,
-                                               WM8350_IRQ_SYS_HYST_COMP_FAIL);
-               if (status2 & WM8350_SYS_CHIP_GT115_EINT)
-                       wm8350_irq_call_handler(wm8350,
-                                               WM8350_IRQ_SYS_CHIP_GT115);
-               if (status2 & WM8350_SYS_CHIP_GT140_EINT)
-                       wm8350_irq_call_handler(wm8350,
-                                               WM8350_IRQ_SYS_CHIP_GT140);
-               if (status2 & WM8350_SYS_WDOG_TO_EINT)
-                       wm8350_irq_call_handler(wm8350,
-                                               WM8350_IRQ_SYS_WDOG_TO);
-
-               if (status2 & WM8350_AUXADC_DATARDY_EINT)
-                       wm8350_irq_call_handler(wm8350,
-                                               WM8350_IRQ_AUXADC_DATARDY);
-               if (status2 & WM8350_AUXADC_DCOMP4_EINT)
-                       wm8350_irq_call_handler(wm8350,
-                                               WM8350_IRQ_AUXADC_DCOMP4);
-               if (status2 & WM8350_AUXADC_DCOMP3_EINT)
-                       wm8350_irq_call_handler(wm8350,
-                                               WM8350_IRQ_AUXADC_DCOMP3);
-               if (status2 & WM8350_AUXADC_DCOMP2_EINT)
-                       wm8350_irq_call_handler(wm8350,
-                                               WM8350_IRQ_AUXADC_DCOMP2);
-               if (status2 & WM8350_AUXADC_DCOMP1_EINT)
-                       wm8350_irq_call_handler(wm8350,
-                                               WM8350_IRQ_AUXADC_DCOMP1);
-
-               if (status2 & WM8350_USB_LIMIT_EINT)
-                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_USB_LIMIT);
-       }
-
-       /* wake, codec, ext */
-       if (comp) {
-               if (comp & WM8350_WKUP_OFF_STATE_EINT)
-                       wm8350_irq_call_handler(wm8350,
-                                               WM8350_IRQ_WKUP_OFF_STATE);
-               if (comp & WM8350_WKUP_HIB_STATE_EINT)
-                       wm8350_irq_call_handler(wm8350,
-                                               WM8350_IRQ_WKUP_HIB_STATE);
-               if (comp & WM8350_WKUP_CONV_FAULT_EINT)
-                       wm8350_irq_call_handler(wm8350,
-                                               WM8350_IRQ_WKUP_CONV_FAULT);
-               if (comp & WM8350_WKUP_WDOG_RST_EINT)
-                       wm8350_irq_call_handler(wm8350,
-                                               WM8350_IRQ_WKUP_WDOG_RST);
-               if (comp & WM8350_WKUP_GP_PWR_ON_EINT)
-                       wm8350_irq_call_handler(wm8350,
-                                               WM8350_IRQ_WKUP_GP_PWR_ON);
-               if (comp & WM8350_WKUP_ONKEY_EINT)
-                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_WKUP_ONKEY);
-               if (comp & WM8350_WKUP_GP_WAKEUP_EINT)
-                       wm8350_irq_call_handler(wm8350,
-                                               WM8350_IRQ_WKUP_GP_WAKEUP);
-
-               if (comp & WM8350_CODEC_JCK_DET_L_EINT)
-                       wm8350_irq_call_handler(wm8350,
-                                               WM8350_IRQ_CODEC_JCK_DET_L);
-               if (comp & WM8350_CODEC_JCK_DET_R_EINT)
-                       wm8350_irq_call_handler(wm8350,
-                                               WM8350_IRQ_CODEC_JCK_DET_R);
-               if (comp & WM8350_CODEC_MICSCD_EINT)
-                       wm8350_irq_call_handler(wm8350,
-                                               WM8350_IRQ_CODEC_MICSCD);
-               if (comp & WM8350_CODEC_MICD_EINT)
-                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_CODEC_MICD);
-
-               if (comp & WM8350_EXT_USB_FB_EINT)
-                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_EXT_USB_FB);
-               if (comp & WM8350_EXT_WALL_FB_EINT)
-                       wm8350_irq_call_handler(wm8350,
-                                               WM8350_IRQ_EXT_WALL_FB);
-               if (comp & WM8350_EXT_BAT_FB_EINT)
-                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_EXT_BAT_FB);
-       }
-
-       if (level_one & WM8350_GP_INT) {
-               int i;
-               u16 gpio;
-
-               gpio = wm8350_reg_read(wm8350, WM8350_GPIO_INT_STATUS);
-               gpio &= ~wm8350_reg_read(wm8350,
-                                        WM8350_GPIO_INT_STATUS_MASK);
-
-               for (i = 0; i < 12; i++) {
-                       if (gpio & (1 << i))
-                               wm8350_irq_call_handler(wm8350,
-                                                       WM8350_IRQ_GPIO(i));
-               }
-       }
-
-       return IRQ_HANDLED;
-}
-
-int wm8350_register_irq(struct wm8350 *wm8350, int irq,
-                       void (*handler) (struct wm8350 *, int, void *),
-                       void *data)
-{
-       if (irq < 0 || irq > WM8350_NUM_IRQ || !handler)
-               return -EINVAL;
-
-       if (wm8350->irq[irq].handler)
-               return -EBUSY;
-
-       mutex_lock(&wm8350->irq_mutex);
-       wm8350->irq[irq].handler = handler;
-       wm8350->irq[irq].data = data;
-       mutex_unlock(&wm8350->irq_mutex);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(wm8350_register_irq);
-
-int wm8350_free_irq(struct wm8350 *wm8350, int irq)
-{
-       if (irq < 0 || irq > WM8350_NUM_IRQ)
-               return -EINVAL;
-
-       mutex_lock(&wm8350->irq_mutex);
-       wm8350->irq[irq].handler = NULL;
-       mutex_unlock(&wm8350->irq_mutex);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(wm8350_free_irq);
-
-int wm8350_mask_irq(struct wm8350 *wm8350, int irq)
-{
-       switch (irq) {
-       case WM8350_IRQ_CHG_BAT_HOT:
-               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
-                                      WM8350_IM_CHG_BAT_HOT_EINT);
-       case WM8350_IRQ_CHG_BAT_COLD:
-               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
-                                      WM8350_IM_CHG_BAT_COLD_EINT);
-       case WM8350_IRQ_CHG_BAT_FAIL:
-               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
-                                      WM8350_IM_CHG_BAT_FAIL_EINT);
-       case WM8350_IRQ_CHG_TO:
-               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
-                                      WM8350_IM_CHG_TO_EINT);
-       case WM8350_IRQ_CHG_END:
-               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
-                                      WM8350_IM_CHG_END_EINT);
-       case WM8350_IRQ_CHG_START:
-               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
-                                      WM8350_IM_CHG_START_EINT);
-       case WM8350_IRQ_CHG_FAST_RDY:
-               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
-                                      WM8350_IM_CHG_FAST_RDY_EINT);
-       case WM8350_IRQ_RTC_PER:
-               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
-                                      WM8350_IM_RTC_PER_EINT);
-       case WM8350_IRQ_RTC_SEC:
-               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
-                                      WM8350_IM_RTC_SEC_EINT);
-       case WM8350_IRQ_RTC_ALM:
-               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
-                                      WM8350_IM_RTC_ALM_EINT);
-       case WM8350_IRQ_CHG_VBATT_LT_3P9:
-               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
-                                      WM8350_IM_CHG_VBATT_LT_3P9_EINT);
-       case WM8350_IRQ_CHG_VBATT_LT_3P1:
-               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
-                                      WM8350_IM_CHG_VBATT_LT_3P1_EINT);
-       case WM8350_IRQ_CHG_VBATT_LT_2P85:
-               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
-                                      WM8350_IM_CHG_VBATT_LT_2P85_EINT);
-       case WM8350_IRQ_CS1:
-               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
-                                      WM8350_IM_CS1_EINT);
-       case WM8350_IRQ_CS2:
-               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
-                                      WM8350_IM_CS2_EINT);
-       case WM8350_IRQ_USB_LIMIT:
-               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
-                                      WM8350_IM_USB_LIMIT_EINT);
-       case WM8350_IRQ_AUXADC_DATARDY:
-               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
-                                      WM8350_IM_AUXADC_DATARDY_EINT);
-       case WM8350_IRQ_AUXADC_DCOMP4:
-               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
-                                      WM8350_IM_AUXADC_DCOMP4_EINT);
-       case WM8350_IRQ_AUXADC_DCOMP3:
-               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
-                                      WM8350_IM_AUXADC_DCOMP3_EINT);
-       case WM8350_IRQ_AUXADC_DCOMP2:
-               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
-                                      WM8350_IM_AUXADC_DCOMP2_EINT);
-       case WM8350_IRQ_AUXADC_DCOMP1:
-               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
-                                      WM8350_IM_AUXADC_DCOMP1_EINT);
-       case WM8350_IRQ_SYS_HYST_COMP_FAIL:
-               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
-                                      WM8350_IM_SYS_HYST_COMP_FAIL_EINT);
-       case WM8350_IRQ_SYS_CHIP_GT115:
-               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
-                                      WM8350_IM_SYS_CHIP_GT115_EINT);
-       case WM8350_IRQ_SYS_CHIP_GT140:
-               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
-                                      WM8350_IM_SYS_CHIP_GT140_EINT);
-       case WM8350_IRQ_SYS_WDOG_TO:
-               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
-                                      WM8350_IM_SYS_WDOG_TO_EINT);
-       case WM8350_IRQ_UV_LDO4:
-               return wm8350_set_bits(wm8350,
-                                      WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
-                                      WM8350_IM_UV_LDO4_EINT);
-       case WM8350_IRQ_UV_LDO3:
-               return wm8350_set_bits(wm8350,
-                                      WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
-                                      WM8350_IM_UV_LDO3_EINT);
-       case WM8350_IRQ_UV_LDO2:
-               return wm8350_set_bits(wm8350,
-                                      WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
-                                      WM8350_IM_UV_LDO2_EINT);
-       case WM8350_IRQ_UV_LDO1:
-               return wm8350_set_bits(wm8350,
-                                      WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
-                                      WM8350_IM_UV_LDO1_EINT);
-       case WM8350_IRQ_UV_DC6:
-               return wm8350_set_bits(wm8350,
-                                      WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
-                                      WM8350_IM_UV_DC6_EINT);
-       case WM8350_IRQ_UV_DC5:
-               return wm8350_set_bits(wm8350,
-                                      WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
-                                      WM8350_IM_UV_DC5_EINT);
-       case WM8350_IRQ_UV_DC4:
-               return wm8350_set_bits(wm8350,
-                                      WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
-                                      WM8350_IM_UV_DC4_EINT);
-       case WM8350_IRQ_UV_DC3:
-               return wm8350_set_bits(wm8350,
-                                      WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
-                                      WM8350_IM_UV_DC3_EINT);
-       case WM8350_IRQ_UV_DC2:
-               return wm8350_set_bits(wm8350,
-                                      WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
-                                      WM8350_IM_UV_DC2_EINT);
-       case WM8350_IRQ_UV_DC1:
-               return wm8350_set_bits(wm8350,
-                                      WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
-                                      WM8350_IM_UV_DC1_EINT);
-       case WM8350_IRQ_OC_LS:
-               return wm8350_set_bits(wm8350,
-                                      WM8350_OVER_CURRENT_INT_STATUS_MASK,
-                                      WM8350_IM_OC_LS_EINT);
-       case WM8350_IRQ_EXT_USB_FB:
-               return wm8350_set_bits(wm8350,
-                                      WM8350_COMPARATOR_INT_STATUS_MASK,
-                                      WM8350_IM_EXT_USB_FB_EINT);
-       case WM8350_IRQ_EXT_WALL_FB:
-               return wm8350_set_bits(wm8350,
-                                      WM8350_COMPARATOR_INT_STATUS_MASK,
-                                      WM8350_IM_EXT_WALL_FB_EINT);
-       case WM8350_IRQ_EXT_BAT_FB:
-               return wm8350_set_bits(wm8350,
-                                      WM8350_COMPARATOR_INT_STATUS_MASK,
-                                      WM8350_IM_EXT_BAT_FB_EINT);
-       case WM8350_IRQ_CODEC_JCK_DET_L:
-               return wm8350_set_bits(wm8350,
-                                      WM8350_COMPARATOR_INT_STATUS_MASK,
-                                      WM8350_IM_CODEC_JCK_DET_L_EINT);
-       case WM8350_IRQ_CODEC_JCK_DET_R:
-               return wm8350_set_bits(wm8350,
-                                      WM8350_COMPARATOR_INT_STATUS_MASK,
-                                      WM8350_IM_CODEC_JCK_DET_R_EINT);
-       case WM8350_IRQ_CODEC_MICSCD:
-               return wm8350_set_bits(wm8350,
-                                      WM8350_COMPARATOR_INT_STATUS_MASK,
-                                      WM8350_IM_CODEC_MICSCD_EINT);
-       case WM8350_IRQ_CODEC_MICD:
-               return wm8350_set_bits(wm8350,
-                                      WM8350_COMPARATOR_INT_STATUS_MASK,
-                                      WM8350_IM_CODEC_MICD_EINT);
-       case WM8350_IRQ_WKUP_OFF_STATE:
-               return wm8350_set_bits(wm8350,
-                                      WM8350_COMPARATOR_INT_STATUS_MASK,
-                                      WM8350_IM_WKUP_OFF_STATE_EINT);
-       case WM8350_IRQ_WKUP_HIB_STATE:
-               return wm8350_set_bits(wm8350,
-                                      WM8350_COMPARATOR_INT_STATUS_MASK,
-                                      WM8350_IM_WKUP_HIB_STATE_EINT);
-       case WM8350_IRQ_WKUP_CONV_FAULT:
-               return wm8350_set_bits(wm8350,
-                                      WM8350_COMPARATOR_INT_STATUS_MASK,
-                                      WM8350_IM_WKUP_CONV_FAULT_EINT);
-       case WM8350_IRQ_WKUP_WDOG_RST:
-               return wm8350_set_bits(wm8350,
-                                      WM8350_COMPARATOR_INT_STATUS_MASK,
-                                      WM8350_IM_WKUP_OFF_STATE_EINT);
-       case WM8350_IRQ_WKUP_GP_PWR_ON:
-               return wm8350_set_bits(wm8350,
-                                      WM8350_COMPARATOR_INT_STATUS_MASK,
-                                      WM8350_IM_WKUP_GP_PWR_ON_EINT);
-       case WM8350_IRQ_WKUP_ONKEY:
-               return wm8350_set_bits(wm8350,
-                                      WM8350_COMPARATOR_INT_STATUS_MASK,
-                                      WM8350_IM_WKUP_ONKEY_EINT);
-       case WM8350_IRQ_WKUP_GP_WAKEUP:
-               return wm8350_set_bits(wm8350,
-                                      WM8350_COMPARATOR_INT_STATUS_MASK,
-                                      WM8350_IM_WKUP_GP_WAKEUP_EINT);
-       case WM8350_IRQ_GPIO(0):
-               return wm8350_set_bits(wm8350,
-                                      WM8350_GPIO_INT_STATUS_MASK,
-                                      WM8350_IM_GP0_EINT);
-       case WM8350_IRQ_GPIO(1):
-               return wm8350_set_bits(wm8350,
-                                      WM8350_GPIO_INT_STATUS_MASK,
-                                      WM8350_IM_GP1_EINT);
-       case WM8350_IRQ_GPIO(2):
-               return wm8350_set_bits(wm8350,
-                                      WM8350_GPIO_INT_STATUS_MASK,
-                                      WM8350_IM_GP2_EINT);
-       case WM8350_IRQ_GPIO(3):
-               return wm8350_set_bits(wm8350,
-                                      WM8350_GPIO_INT_STATUS_MASK,
-                                      WM8350_IM_GP3_EINT);
-       case WM8350_IRQ_GPIO(4):
-               return wm8350_set_bits(wm8350,
-                                      WM8350_GPIO_INT_STATUS_MASK,
-                                      WM8350_IM_GP4_EINT);
-       case WM8350_IRQ_GPIO(5):
-               return wm8350_set_bits(wm8350,
-                                      WM8350_GPIO_INT_STATUS_MASK,
-                                      WM8350_IM_GP5_EINT);
-       case WM8350_IRQ_GPIO(6):
-               return wm8350_set_bits(wm8350,
-                                      WM8350_GPIO_INT_STATUS_MASK,
-                                      WM8350_IM_GP6_EINT);
-       case WM8350_IRQ_GPIO(7):
-               return wm8350_set_bits(wm8350,
-                                      WM8350_GPIO_INT_STATUS_MASK,
-                                      WM8350_IM_GP7_EINT);
-       case WM8350_IRQ_GPIO(8):
-               return wm8350_set_bits(wm8350,
-                                      WM8350_GPIO_INT_STATUS_MASK,
-                                      WM8350_IM_GP8_EINT);
-       case WM8350_IRQ_GPIO(9):
-               return wm8350_set_bits(wm8350,
-                                      WM8350_GPIO_INT_STATUS_MASK,
-                                      WM8350_IM_GP9_EINT);
-       case WM8350_IRQ_GPIO(10):
-               return wm8350_set_bits(wm8350,
-                                      WM8350_GPIO_INT_STATUS_MASK,
-                                      WM8350_IM_GP10_EINT);
-       case WM8350_IRQ_GPIO(11):
-               return wm8350_set_bits(wm8350,
-                                      WM8350_GPIO_INT_STATUS_MASK,
-                                      WM8350_IM_GP11_EINT);
-       case WM8350_IRQ_GPIO(12):
-               return wm8350_set_bits(wm8350,
-                                      WM8350_GPIO_INT_STATUS_MASK,
-                                      WM8350_IM_GP12_EINT);
-       default:
-               dev_warn(wm8350->dev, "Attempting to mask unknown IRQ %d\n",
-                        irq);
-               return -EINVAL;
-       }
-       return 0;
-}
-EXPORT_SYMBOL_GPL(wm8350_mask_irq);
-
-int wm8350_unmask_irq(struct wm8350 *wm8350, int irq)
-{
-       switch (irq) {
-       case WM8350_IRQ_CHG_BAT_HOT:
-               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
-                                        WM8350_IM_CHG_BAT_HOT_EINT);
-       case WM8350_IRQ_CHG_BAT_COLD:
-               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
-                                        WM8350_IM_CHG_BAT_COLD_EINT);
-       case WM8350_IRQ_CHG_BAT_FAIL:
-               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
-                                        WM8350_IM_CHG_BAT_FAIL_EINT);
-       case WM8350_IRQ_CHG_TO:
-               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
-                                        WM8350_IM_CHG_TO_EINT);
-       case WM8350_IRQ_CHG_END:
-               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
-                                        WM8350_IM_CHG_END_EINT);
-       case WM8350_IRQ_CHG_START:
-               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
-                                        WM8350_IM_CHG_START_EINT);
-       case WM8350_IRQ_CHG_FAST_RDY:
-               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
-                                        WM8350_IM_CHG_FAST_RDY_EINT);
-       case WM8350_IRQ_RTC_PER:
-               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
-                                        WM8350_IM_RTC_PER_EINT);
-       case WM8350_IRQ_RTC_SEC:
-               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
-                                        WM8350_IM_RTC_SEC_EINT);
-       case WM8350_IRQ_RTC_ALM:
-               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
-                                        WM8350_IM_RTC_ALM_EINT);
-       case WM8350_IRQ_CHG_VBATT_LT_3P9:
-               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
-                                        WM8350_IM_CHG_VBATT_LT_3P9_EINT);
-       case WM8350_IRQ_CHG_VBATT_LT_3P1:
-               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
-                                        WM8350_IM_CHG_VBATT_LT_3P1_EINT);
-       case WM8350_IRQ_CHG_VBATT_LT_2P85:
-               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
-                                        WM8350_IM_CHG_VBATT_LT_2P85_EINT);
-       case WM8350_IRQ_CS1:
-               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
-                                        WM8350_IM_CS1_EINT);
-       case WM8350_IRQ_CS2:
-               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
-                                        WM8350_IM_CS2_EINT);
-       case WM8350_IRQ_USB_LIMIT:
-               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
-                                        WM8350_IM_USB_LIMIT_EINT);
-       case WM8350_IRQ_AUXADC_DATARDY:
-               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
-                                        WM8350_IM_AUXADC_DATARDY_EINT);
-       case WM8350_IRQ_AUXADC_DCOMP4:
-               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
-                                        WM8350_IM_AUXADC_DCOMP4_EINT);
-       case WM8350_IRQ_AUXADC_DCOMP3:
-               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
-                                        WM8350_IM_AUXADC_DCOMP3_EINT);
-       case WM8350_IRQ_AUXADC_DCOMP2:
-               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
-                                        WM8350_IM_AUXADC_DCOMP2_EINT);
-       case WM8350_IRQ_AUXADC_DCOMP1:
-               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
-                                        WM8350_IM_AUXADC_DCOMP1_EINT);
-       case WM8350_IRQ_SYS_HYST_COMP_FAIL:
-               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
-                                        WM8350_IM_SYS_HYST_COMP_FAIL_EINT);
-       case WM8350_IRQ_SYS_CHIP_GT115:
-               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
-                                        WM8350_IM_SYS_CHIP_GT115_EINT);
-       case WM8350_IRQ_SYS_CHIP_GT140:
-               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
-                                        WM8350_IM_SYS_CHIP_GT140_EINT);
-       case WM8350_IRQ_SYS_WDOG_TO:
-               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
-                                        WM8350_IM_SYS_WDOG_TO_EINT);
-       case WM8350_IRQ_UV_LDO4:
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
-                                        WM8350_IM_UV_LDO4_EINT);
-       case WM8350_IRQ_UV_LDO3:
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
-                                        WM8350_IM_UV_LDO3_EINT);
-       case WM8350_IRQ_UV_LDO2:
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
-                                        WM8350_IM_UV_LDO2_EINT);
-       case WM8350_IRQ_UV_LDO1:
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
-                                        WM8350_IM_UV_LDO1_EINT);
-       case WM8350_IRQ_UV_DC6:
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
-                                        WM8350_IM_UV_DC6_EINT);
-       case WM8350_IRQ_UV_DC5:
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
-                                        WM8350_IM_UV_DC5_EINT);
-       case WM8350_IRQ_UV_DC4:
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
-                                        WM8350_IM_UV_DC4_EINT);
-       case WM8350_IRQ_UV_DC3:
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
-                                        WM8350_IM_UV_DC3_EINT);
-       case WM8350_IRQ_UV_DC2:
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
-                                        WM8350_IM_UV_DC2_EINT);
-       case WM8350_IRQ_UV_DC1:
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
-                                        WM8350_IM_UV_DC1_EINT);
-       case WM8350_IRQ_OC_LS:
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_OVER_CURRENT_INT_STATUS_MASK,
-                                        WM8350_IM_OC_LS_EINT);
-       case WM8350_IRQ_EXT_USB_FB:
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_COMPARATOR_INT_STATUS_MASK,
-                                        WM8350_IM_EXT_USB_FB_EINT);
-       case WM8350_IRQ_EXT_WALL_FB:
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_COMPARATOR_INT_STATUS_MASK,
-                                        WM8350_IM_EXT_WALL_FB_EINT);
-       case WM8350_IRQ_EXT_BAT_FB:
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_COMPARATOR_INT_STATUS_MASK,
-                                        WM8350_IM_EXT_BAT_FB_EINT);
-       case WM8350_IRQ_CODEC_JCK_DET_L:
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_COMPARATOR_INT_STATUS_MASK,
-                                        WM8350_IM_CODEC_JCK_DET_L_EINT);
-       case WM8350_IRQ_CODEC_JCK_DET_R:
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_COMPARATOR_INT_STATUS_MASK,
-                                        WM8350_IM_CODEC_JCK_DET_R_EINT);
-       case WM8350_IRQ_CODEC_MICSCD:
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_COMPARATOR_INT_STATUS_MASK,
-                                        WM8350_IM_CODEC_MICSCD_EINT);
-       case WM8350_IRQ_CODEC_MICD:
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_COMPARATOR_INT_STATUS_MASK,
-                                        WM8350_IM_CODEC_MICD_EINT);
-       case WM8350_IRQ_WKUP_OFF_STATE:
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_COMPARATOR_INT_STATUS_MASK,
-                                        WM8350_IM_WKUP_OFF_STATE_EINT);
-       case WM8350_IRQ_WKUP_HIB_STATE:
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_COMPARATOR_INT_STATUS_MASK,
-                                        WM8350_IM_WKUP_HIB_STATE_EINT);
-       case WM8350_IRQ_WKUP_CONV_FAULT:
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_COMPARATOR_INT_STATUS_MASK,
-                                        WM8350_IM_WKUP_CONV_FAULT_EINT);
-       case WM8350_IRQ_WKUP_WDOG_RST:
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_COMPARATOR_INT_STATUS_MASK,
-                                        WM8350_IM_WKUP_OFF_STATE_EINT);
-       case WM8350_IRQ_WKUP_GP_PWR_ON:
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_COMPARATOR_INT_STATUS_MASK,
-                                        WM8350_IM_WKUP_GP_PWR_ON_EINT);
-       case WM8350_IRQ_WKUP_ONKEY:
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_COMPARATOR_INT_STATUS_MASK,
-                                        WM8350_IM_WKUP_ONKEY_EINT);
-       case WM8350_IRQ_WKUP_GP_WAKEUP:
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_COMPARATOR_INT_STATUS_MASK,
-                                        WM8350_IM_WKUP_GP_WAKEUP_EINT);
-       case WM8350_IRQ_GPIO(0):
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_GPIO_INT_STATUS_MASK,
-                                        WM8350_IM_GP0_EINT);
-       case WM8350_IRQ_GPIO(1):
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_GPIO_INT_STATUS_MASK,
-                                        WM8350_IM_GP1_EINT);
-       case WM8350_IRQ_GPIO(2):
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_GPIO_INT_STATUS_MASK,
-                                        WM8350_IM_GP2_EINT);
-       case WM8350_IRQ_GPIO(3):
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_GPIO_INT_STATUS_MASK,
-                                        WM8350_IM_GP3_EINT);
-       case WM8350_IRQ_GPIO(4):
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_GPIO_INT_STATUS_MASK,
-                                        WM8350_IM_GP4_EINT);
-       case WM8350_IRQ_GPIO(5):
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_GPIO_INT_STATUS_MASK,
-                                        WM8350_IM_GP5_EINT);
-       case WM8350_IRQ_GPIO(6):
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_GPIO_INT_STATUS_MASK,
-                                        WM8350_IM_GP6_EINT);
-       case WM8350_IRQ_GPIO(7):
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_GPIO_INT_STATUS_MASK,
-                                        WM8350_IM_GP7_EINT);
-       case WM8350_IRQ_GPIO(8):
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_GPIO_INT_STATUS_MASK,
-                                        WM8350_IM_GP8_EINT);
-       case WM8350_IRQ_GPIO(9):
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_GPIO_INT_STATUS_MASK,
-                                        WM8350_IM_GP9_EINT);
-       case WM8350_IRQ_GPIO(10):
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_GPIO_INT_STATUS_MASK,
-                                        WM8350_IM_GP10_EINT);
-       case WM8350_IRQ_GPIO(11):
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_GPIO_INT_STATUS_MASK,
-                                        WM8350_IM_GP11_EINT);
-       case WM8350_IRQ_GPIO(12):
-               return wm8350_clear_bits(wm8350,
-                                        WM8350_GPIO_INT_STATUS_MASK,
-                                        WM8350_IM_GP12_EINT);
-       default:
-               dev_warn(wm8350->dev, "Attempting to unmask unknown IRQ %d\n",
-                        irq);
-               return -EINVAL;
-       }
-       return 0;
-}
-EXPORT_SYMBOL_GPL(wm8350_unmask_irq);
-
 int wm8350_read_auxadc(struct wm8350 *wm8350, int channel, int scale, int vref)
 {
        u16 reg, result = 0;
@@ -1264,7 +537,7 @@ static void wm8350_client_dev_register(struct wm8350 *wm8350,
        int ret;
 
        *pdev = platform_device_alloc(name, -1);
-       if (pdev == NULL) {
+       if (*pdev == NULL) {
                dev_err(wm8350->dev, "Failed to allocate %s\n", name);
                return;
        }
@@ -1409,49 +682,18 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq,
                return ret;
        }
 
-       wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0xFFFF);
-       wm8350_reg_write(wm8350, WM8350_INT_STATUS_1_MASK, 0xFFFF);
-       wm8350_reg_write(wm8350, WM8350_INT_STATUS_2_MASK, 0xFFFF);
-       wm8350_reg_write(wm8350, WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 0xFFFF);
-       wm8350_reg_write(wm8350, WM8350_GPIO_INT_STATUS_MASK, 0xFFFF);
-       wm8350_reg_write(wm8350, WM8350_COMPARATOR_INT_STATUS_MASK, 0xFFFF);
-
        mutex_init(&wm8350->auxadc_mutex);
-       mutex_init(&wm8350->irq_mutex);
-       if (irq) {
-               int flags = IRQF_ONESHOT;
-
-               if (pdata && pdata->irq_high) {
-                       flags |= IRQF_TRIGGER_HIGH;
-
-                       wm8350_set_bits(wm8350, WM8350_SYSTEM_CONTROL_1,
-                                       WM8350_IRQ_POL);
-               } else {
-                       flags |= IRQF_TRIGGER_LOW;
-
-                       wm8350_clear_bits(wm8350, WM8350_SYSTEM_CONTROL_1,
-                                         WM8350_IRQ_POL);
-               }
 
-               ret = request_threaded_irq(irq, NULL, wm8350_irq, flags,
-                                          "wm8350", wm8350);
-               if (ret != 0) {
-                       dev_err(wm8350->dev, "Failed to request IRQ: %d\n",
-                               ret);
-                       goto err;
-               }
-       } else {
-               dev_err(wm8350->dev, "No IRQ configured\n");
+       ret = wm8350_irq_init(wm8350, irq, pdata);
+       if (ret < 0)
                goto err;
-       }
-       wm8350->chip_irq = irq;
 
        if (pdata && pdata->init) {
                ret = pdata->init(wm8350);
                if (ret != 0) {
                        dev_err(wm8350->dev, "Platform init() failed: %d\n",
                                ret);
-                       goto err;
+                       goto err_irq;
                }
        }
 
@@ -1470,6 +712,8 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq,
 
        return 0;
 
+err_irq:
+       wm8350_irq_exit(wm8350);
 err:
        kfree(wm8350->reg_cache);
        return ret;
@@ -1493,7 +737,8 @@ void wm8350_device_exit(struct wm8350 *wm8350)
        platform_device_unregister(wm8350->gpio.pdev);
        platform_device_unregister(wm8350->codec.pdev);
 
-       free_irq(wm8350->chip_irq, wm8350);
+       wm8350_irq_exit(wm8350);
+
        kfree(wm8350->reg_cache);
 }
 EXPORT_SYMBOL_GPL(wm8350_device_exit);
diff --git a/drivers/mfd/wm8350-irq.c b/drivers/mfd/wm8350-irq.c
new file mode 100644 (file)
index 0000000..c8df547
--- /dev/null
@@ -0,0 +1,529 @@
+/*
+ * wm8350-irq.c  --  IRQ support for Wolfson WM8350
+ *
+ * Copyright 2007, 2008, 2009 Wolfson Microelectronics PLC.
+ *
+ * Author: Liam Girdwood, Mark Brown
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/bug.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+
+#include <linux/mfd/wm8350/core.h>
+#include <linux/mfd/wm8350/audio.h>
+#include <linux/mfd/wm8350/comparator.h>
+#include <linux/mfd/wm8350/gpio.h>
+#include <linux/mfd/wm8350/pmic.h>
+#include <linux/mfd/wm8350/rtc.h>
+#include <linux/mfd/wm8350/supply.h>
+#include <linux/mfd/wm8350/wdt.h>
+
+#define WM8350_NUM_IRQ_REGS 7
+
+#define WM8350_INT_OFFSET_1                     0
+#define WM8350_INT_OFFSET_2                     1
+#define WM8350_POWER_UP_INT_OFFSET              2
+#define WM8350_UNDER_VOLTAGE_INT_OFFSET         3
+#define WM8350_OVER_CURRENT_INT_OFFSET          4
+#define WM8350_GPIO_INT_OFFSET                  5
+#define WM8350_COMPARATOR_INT_OFFSET            6
+
+struct wm8350_irq_data {
+       int primary;
+       int reg;
+       int mask;
+       int primary_only;
+};
+
+static struct wm8350_irq_data wm8350_irqs[] = {
+       [WM8350_IRQ_OC_LS] = {
+               .primary = WM8350_OC_INT,
+               .reg = WM8350_OVER_CURRENT_INT_OFFSET,
+               .mask = WM8350_OC_LS_EINT,
+               .primary_only = 1,
+       },
+       [WM8350_IRQ_UV_DC1] = {
+               .primary = WM8350_UV_INT,
+               .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
+               .mask = WM8350_UV_DC1_EINT,
+       },
+       [WM8350_IRQ_UV_DC2] = {
+               .primary = WM8350_UV_INT,
+               .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
+               .mask = WM8350_UV_DC2_EINT,
+       },
+       [WM8350_IRQ_UV_DC3] = {
+               .primary = WM8350_UV_INT,
+               .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
+               .mask = WM8350_UV_DC3_EINT,
+       },
+       [WM8350_IRQ_UV_DC4] = {
+               .primary = WM8350_UV_INT,
+               .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
+               .mask = WM8350_UV_DC4_EINT,
+       },
+       [WM8350_IRQ_UV_DC5] = {
+               .primary = WM8350_UV_INT,
+               .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
+               .mask = WM8350_UV_DC5_EINT,
+       },
+       [WM8350_IRQ_UV_DC6] = {
+               .primary = WM8350_UV_INT,
+               .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
+               .mask = WM8350_UV_DC6_EINT,
+       },
+       [WM8350_IRQ_UV_LDO1] = {
+               .primary = WM8350_UV_INT,
+               .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
+               .mask = WM8350_UV_LDO1_EINT,
+       },
+       [WM8350_IRQ_UV_LDO2] = {
+               .primary = WM8350_UV_INT,
+               .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
+               .mask = WM8350_UV_LDO2_EINT,
+       },
+       [WM8350_IRQ_UV_LDO3] = {
+               .primary = WM8350_UV_INT,
+               .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
+               .mask = WM8350_UV_LDO3_EINT,
+       },
+       [WM8350_IRQ_UV_LDO4] = {
+               .primary = WM8350_UV_INT,
+               .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
+               .mask = WM8350_UV_LDO4_EINT,
+       },
+       [WM8350_IRQ_CHG_BAT_HOT] = {
+               .primary = WM8350_CHG_INT,
+               .reg = WM8350_INT_OFFSET_1,
+               .mask = WM8350_CHG_BAT_HOT_EINT,
+       },
+       [WM8350_IRQ_CHG_BAT_COLD] = {
+               .primary = WM8350_CHG_INT,
+               .reg = WM8350_INT_OFFSET_1,
+               .mask = WM8350_CHG_BAT_COLD_EINT,
+       },
+       [WM8350_IRQ_CHG_BAT_FAIL] = {
+               .primary = WM8350_CHG_INT,
+               .reg = WM8350_INT_OFFSET_1,
+               .mask = WM8350_CHG_BAT_FAIL_EINT,
+       },
+       [WM8350_IRQ_CHG_TO] = {
+               .primary = WM8350_CHG_INT,
+               .reg = WM8350_INT_OFFSET_1,
+               .mask = WM8350_CHG_TO_EINT,
+       },
+       [WM8350_IRQ_CHG_END] = {
+               .primary = WM8350_CHG_INT,
+               .reg = WM8350_INT_OFFSET_1,
+               .mask = WM8350_CHG_END_EINT,
+       },
+       [WM8350_IRQ_CHG_START] = {
+               .primary = WM8350_CHG_INT,
+               .reg = WM8350_INT_OFFSET_1,
+               .mask = WM8350_CHG_START_EINT,
+       },
+       [WM8350_IRQ_CHG_FAST_RDY] = {
+               .primary = WM8350_CHG_INT,
+               .reg = WM8350_INT_OFFSET_1,
+               .mask = WM8350_CHG_FAST_RDY_EINT,
+       },
+       [WM8350_IRQ_CHG_VBATT_LT_3P9] = {
+               .primary = WM8350_CHG_INT,
+               .reg = WM8350_INT_OFFSET_1,
+               .mask = WM8350_CHG_VBATT_LT_3P9_EINT,
+       },
+       [WM8350_IRQ_CHG_VBATT_LT_3P1] = {
+               .primary = WM8350_CHG_INT,
+               .reg = WM8350_INT_OFFSET_1,
+               .mask = WM8350_CHG_VBATT_LT_3P1_EINT,
+       },
+       [WM8350_IRQ_CHG_VBATT_LT_2P85] = {
+               .primary = WM8350_CHG_INT,
+               .reg = WM8350_INT_OFFSET_1,
+               .mask = WM8350_CHG_VBATT_LT_2P85_EINT,
+       },
+       [WM8350_IRQ_RTC_ALM] = {
+               .primary = WM8350_RTC_INT,
+               .reg = WM8350_INT_OFFSET_1,
+               .mask = WM8350_RTC_ALM_EINT,
+       },
+       [WM8350_IRQ_RTC_SEC] = {
+               .primary = WM8350_RTC_INT,
+               .reg = WM8350_INT_OFFSET_1,
+               .mask = WM8350_RTC_SEC_EINT,
+       },
+       [WM8350_IRQ_RTC_PER] = {
+               .primary = WM8350_RTC_INT,
+               .reg = WM8350_INT_OFFSET_1,
+               .mask = WM8350_RTC_PER_EINT,
+       },
+       [WM8350_IRQ_CS1] = {
+               .primary = WM8350_CS_INT,
+               .reg = WM8350_INT_OFFSET_2,
+               .mask = WM8350_CS1_EINT,
+       },
+       [WM8350_IRQ_CS2] = {
+               .primary = WM8350_CS_INT,
+               .reg = WM8350_INT_OFFSET_2,
+               .mask = WM8350_CS2_EINT,
+       },
+       [WM8350_IRQ_SYS_HYST_COMP_FAIL] = {
+               .primary = WM8350_SYS_INT,
+               .reg = WM8350_INT_OFFSET_2,
+               .mask = WM8350_SYS_HYST_COMP_FAIL_EINT,
+       },
+       [WM8350_IRQ_SYS_CHIP_GT115] = {
+               .primary = WM8350_SYS_INT,
+               .reg = WM8350_INT_OFFSET_2,
+               .mask = WM8350_SYS_CHIP_GT115_EINT,
+       },
+       [WM8350_IRQ_SYS_CHIP_GT140] = {
+               .primary = WM8350_SYS_INT,
+               .reg = WM8350_INT_OFFSET_2,
+               .mask = WM8350_SYS_CHIP_GT140_EINT,
+       },
+       [WM8350_IRQ_SYS_WDOG_TO] = {
+               .primary = WM8350_SYS_INT,
+               .reg = WM8350_INT_OFFSET_2,
+               .mask = WM8350_SYS_WDOG_TO_EINT,
+       },
+       [WM8350_IRQ_AUXADC_DATARDY] = {
+               .primary = WM8350_AUXADC_INT,
+               .reg = WM8350_INT_OFFSET_2,
+               .mask = WM8350_AUXADC_DATARDY_EINT,
+       },
+       [WM8350_IRQ_AUXADC_DCOMP4] = {
+               .primary = WM8350_AUXADC_INT,
+               .reg = WM8350_INT_OFFSET_2,
+               .mask = WM8350_AUXADC_DCOMP4_EINT,
+       },
+       [WM8350_IRQ_AUXADC_DCOMP3] = {
+               .primary = WM8350_AUXADC_INT,
+               .reg = WM8350_INT_OFFSET_2,
+               .mask = WM8350_AUXADC_DCOMP3_EINT,
+       },
+       [WM8350_IRQ_AUXADC_DCOMP2] = {
+               .primary = WM8350_AUXADC_INT,
+               .reg = WM8350_INT_OFFSET_2,
+               .mask = WM8350_AUXADC_DCOMP2_EINT,
+       },
+       [WM8350_IRQ_AUXADC_DCOMP1] = {
+               .primary = WM8350_AUXADC_INT,
+               .reg = WM8350_INT_OFFSET_2,
+               .mask = WM8350_AUXADC_DCOMP1_EINT,
+       },
+       [WM8350_IRQ_USB_LIMIT] = {
+               .primary = WM8350_USB_INT,
+               .reg = WM8350_INT_OFFSET_2,
+               .mask = WM8350_USB_LIMIT_EINT,
+               .primary_only = 1,
+       },
+       [WM8350_IRQ_WKUP_OFF_STATE] = {
+               .primary = WM8350_WKUP_INT,
+               .reg = WM8350_COMPARATOR_INT_OFFSET,
+               .mask = WM8350_WKUP_OFF_STATE_EINT,
+       },
+       [WM8350_IRQ_WKUP_HIB_STATE] = {
+               .primary = WM8350_WKUP_INT,
+               .reg = WM8350_COMPARATOR_INT_OFFSET,
+               .mask = WM8350_WKUP_HIB_STATE_EINT,
+       },
+       [WM8350_IRQ_WKUP_CONV_FAULT] = {
+               .primary = WM8350_WKUP_INT,
+               .reg = WM8350_COMPARATOR_INT_OFFSET,
+               .mask = WM8350_WKUP_CONV_FAULT_EINT,
+       },
+       [WM8350_IRQ_WKUP_WDOG_RST] = {
+               .primary = WM8350_WKUP_INT,
+               .reg = WM8350_COMPARATOR_INT_OFFSET,
+               .mask = WM8350_WKUP_WDOG_RST_EINT,
+       },
+       [WM8350_IRQ_WKUP_GP_PWR_ON] = {
+               .primary = WM8350_WKUP_INT,
+               .reg = WM8350_COMPARATOR_INT_OFFSET,
+               .mask = WM8350_WKUP_GP_PWR_ON_EINT,
+       },
+       [WM8350_IRQ_WKUP_ONKEY] = {
+               .primary = WM8350_WKUP_INT,
+               .reg = WM8350_COMPARATOR_INT_OFFSET,
+               .mask = WM8350_WKUP_ONKEY_EINT,
+       },
+       [WM8350_IRQ_WKUP_GP_WAKEUP] = {
+               .primary = WM8350_WKUP_INT,
+               .reg = WM8350_COMPARATOR_INT_OFFSET,
+               .mask = WM8350_WKUP_GP_WAKEUP_EINT,
+       },
+       [WM8350_IRQ_CODEC_JCK_DET_L] = {
+               .primary = WM8350_CODEC_INT,
+               .reg = WM8350_COMPARATOR_INT_OFFSET,
+               .mask = WM8350_CODEC_JCK_DET_L_EINT,
+       },
+       [WM8350_IRQ_CODEC_JCK_DET_R] = {
+               .primary = WM8350_CODEC_INT,
+               .reg = WM8350_COMPARATOR_INT_OFFSET,
+               .mask = WM8350_CODEC_JCK_DET_R_EINT,
+       },
+       [WM8350_IRQ_CODEC_MICSCD] = {
+               .primary = WM8350_CODEC_INT,
+               .reg = WM8350_COMPARATOR_INT_OFFSET,
+               .mask = WM8350_CODEC_MICSCD_EINT,
+       },
+       [WM8350_IRQ_CODEC_MICD] = {
+               .primary = WM8350_CODEC_INT,
+               .reg = WM8350_COMPARATOR_INT_OFFSET,
+               .mask = WM8350_CODEC_MICD_EINT,
+       },
+       [WM8350_IRQ_EXT_USB_FB] = {
+               .primary = WM8350_EXT_INT,
+               .reg = WM8350_COMPARATOR_INT_OFFSET,
+               .mask = WM8350_EXT_USB_FB_EINT,
+       },
+       [WM8350_IRQ_EXT_WALL_FB] = {
+               .primary = WM8350_EXT_INT,
+               .reg = WM8350_COMPARATOR_INT_OFFSET,
+               .mask = WM8350_EXT_WALL_FB_EINT,
+       },
+       [WM8350_IRQ_EXT_BAT_FB] = {
+               .primary = WM8350_EXT_INT,
+               .reg = WM8350_COMPARATOR_INT_OFFSET,
+               .mask = WM8350_EXT_BAT_FB_EINT,
+       },
+       [WM8350_IRQ_GPIO(0)] = {
+               .primary = WM8350_GP_INT,
+               .reg = WM8350_GPIO_INT_OFFSET,
+               .mask = WM8350_GP0_EINT,
+       },
+       [WM8350_IRQ_GPIO(1)] = {
+               .primary = WM8350_GP_INT,
+               .reg = WM8350_GPIO_INT_OFFSET,
+               .mask = WM8350_GP1_EINT,
+       },
+       [WM8350_IRQ_GPIO(2)] = {
+               .primary = WM8350_GP_INT,
+               .reg = WM8350_GPIO_INT_OFFSET,
+               .mask = WM8350_GP2_EINT,
+       },
+       [WM8350_IRQ_GPIO(3)] = {
+               .primary = WM8350_GP_INT,
+               .reg = WM8350_GPIO_INT_OFFSET,
+               .mask = WM8350_GP3_EINT,
+       },
+       [WM8350_IRQ_GPIO(4)] = {
+               .primary = WM8350_GP_INT,
+               .reg = WM8350_GPIO_INT_OFFSET,
+               .mask = WM8350_GP4_EINT,
+       },
+       [WM8350_IRQ_GPIO(5)] = {
+               .primary = WM8350_GP_INT,
+               .reg = WM8350_GPIO_INT_OFFSET,
+               .mask = WM8350_GP5_EINT,
+       },
+       [WM8350_IRQ_GPIO(6)] = {
+               .primary = WM8350_GP_INT,
+               .reg = WM8350_GPIO_INT_OFFSET,
+               .mask = WM8350_GP6_EINT,
+       },
+       [WM8350_IRQ_GPIO(7)] = {
+               .primary = WM8350_GP_INT,
+               .reg = WM8350_GPIO_INT_OFFSET,
+               .mask = WM8350_GP7_EINT,
+       },
+       [WM8350_IRQ_GPIO(8)] = {
+               .primary = WM8350_GP_INT,
+               .reg = WM8350_GPIO_INT_OFFSET,
+               .mask = WM8350_GP8_EINT,
+       },
+       [WM8350_IRQ_GPIO(9)] = {
+               .primary = WM8350_GP_INT,
+               .reg = WM8350_GPIO_INT_OFFSET,
+               .mask = WM8350_GP9_EINT,
+       },
+       [WM8350_IRQ_GPIO(10)] = {
+               .primary = WM8350_GP_INT,
+               .reg = WM8350_GPIO_INT_OFFSET,
+               .mask = WM8350_GP10_EINT,
+       },
+       [WM8350_IRQ_GPIO(11)] = {
+               .primary = WM8350_GP_INT,
+               .reg = WM8350_GPIO_INT_OFFSET,
+               .mask = WM8350_GP11_EINT,
+       },
+       [WM8350_IRQ_GPIO(12)] = {
+               .primary = WM8350_GP_INT,
+               .reg = WM8350_GPIO_INT_OFFSET,
+               .mask = WM8350_GP12_EINT,
+       },
+};
+
+static void wm8350_irq_call_handler(struct wm8350 *wm8350, int irq)
+{
+       mutex_lock(&wm8350->irq_mutex);
+
+       if (wm8350->irq[irq].handler)
+               wm8350->irq[irq].handler(irq, wm8350->irq[irq].data);
+       else {
+               dev_err(wm8350->dev, "irq %d nobody cared. now masked.\n",
+                       irq);
+               wm8350_mask_irq(wm8350, irq);
+       }
+
+       mutex_unlock(&wm8350->irq_mutex);
+}
+
+/*
+ * This is a threaded IRQ handler so can access I2C/SPI.  Since all
+ * interrupts are clear on read the IRQ line will be reasserted and
+ * the physical IRQ will be handled again if another interrupt is
+ * asserted while we run - in the normal course of events this is a
+ * rare occurrence so we save I2C/SPI reads.
+ */
+static irqreturn_t wm8350_irq(int irq, void *irq_data)
+{
+       struct wm8350 *wm8350 = irq_data;
+       u16 level_one;
+       u16 sub_reg[WM8350_NUM_IRQ_REGS];
+       int read_done[WM8350_NUM_IRQ_REGS];
+       struct wm8350_irq_data *data;
+       int i;
+
+       /* TODO: Use block reads to improve performance? */
+       level_one = wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS)
+               & ~wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK);
+
+       if (!level_one)
+               return IRQ_NONE;
+
+       memset(&read_done, 0, sizeof(read_done));
+
+       for (i = 0; i < ARRAY_SIZE(wm8350_irqs); i++) {
+               data = &wm8350_irqs[i];
+
+               if (!(level_one & data->primary))
+                       continue;
+
+               if (!read_done[data->reg]) {
+                       sub_reg[data->reg] =
+                               wm8350_reg_read(wm8350, WM8350_INT_STATUS_1 +
+                                               data->reg);
+                       sub_reg[data->reg] &=
+                               ~wm8350_reg_read(wm8350,
+                                                WM8350_INT_STATUS_1_MASK +
+                                                data->reg);
+                       read_done[data->reg] = 1;
+               }
+
+               if (sub_reg[data->reg] & data->mask)
+                       wm8350_irq_call_handler(wm8350, i);
+       }
+
+       return IRQ_HANDLED;
+}
+
+int wm8350_register_irq(struct wm8350 *wm8350, int irq,
+                       irq_handler_t handler, unsigned long flags,
+                       const char *name, void *data)
+{
+       if (irq < 0 || irq > WM8350_NUM_IRQ || !handler)
+               return -EINVAL;
+
+       if (wm8350->irq[irq].handler)
+               return -EBUSY;
+
+       mutex_lock(&wm8350->irq_mutex);
+       wm8350->irq[irq].handler = handler;
+       wm8350->irq[irq].data = data;
+       mutex_unlock(&wm8350->irq_mutex);
+
+       wm8350_unmask_irq(wm8350, irq);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_register_irq);
+
+int wm8350_free_irq(struct wm8350 *wm8350, int irq)
+{
+       if (irq < 0 || irq > WM8350_NUM_IRQ)
+               return -EINVAL;
+
+       wm8350_mask_irq(wm8350, irq);
+
+       mutex_lock(&wm8350->irq_mutex);
+       wm8350->irq[irq].handler = NULL;
+       mutex_unlock(&wm8350->irq_mutex);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_free_irq);
+
+int wm8350_mask_irq(struct wm8350 *wm8350, int irq)
+{
+       return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK +
+                              wm8350_irqs[irq].reg,
+                              wm8350_irqs[irq].mask);
+}
+EXPORT_SYMBOL_GPL(wm8350_mask_irq);
+
+int wm8350_unmask_irq(struct wm8350 *wm8350, int irq)
+{
+       return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK +
+                                wm8350_irqs[irq].reg,
+                                wm8350_irqs[irq].mask);
+}
+EXPORT_SYMBOL_GPL(wm8350_unmask_irq);
+
+int wm8350_irq_init(struct wm8350 *wm8350, int irq,
+                   struct wm8350_platform_data *pdata)
+{
+       int ret;
+       int flags = IRQF_ONESHOT;
+
+       if (!irq) {
+               dev_err(wm8350->dev, "No IRQ configured\n");
+               return -EINVAL;
+       }
+
+       wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0xFFFF);
+       wm8350_reg_write(wm8350, WM8350_INT_STATUS_1_MASK, 0xFFFF);
+       wm8350_reg_write(wm8350, WM8350_INT_STATUS_2_MASK, 0xFFFF);
+       wm8350_reg_write(wm8350, WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 0xFFFF);
+       wm8350_reg_write(wm8350, WM8350_GPIO_INT_STATUS_MASK, 0xFFFF);
+       wm8350_reg_write(wm8350, WM8350_COMPARATOR_INT_STATUS_MASK, 0xFFFF);
+
+       mutex_init(&wm8350->irq_mutex);
+       wm8350->chip_irq = irq;
+
+       if (pdata && pdata->irq_high) {
+               flags |= IRQF_TRIGGER_HIGH;
+
+               wm8350_set_bits(wm8350, WM8350_SYSTEM_CONTROL_1,
+                               WM8350_IRQ_POL);
+       } else {
+               flags |= IRQF_TRIGGER_LOW;
+
+               wm8350_clear_bits(wm8350, WM8350_SYSTEM_CONTROL_1,
+                                 WM8350_IRQ_POL);
+       }
+
+       ret = request_threaded_irq(irq, NULL, wm8350_irq, flags,
+                                  "wm8350", wm8350);
+       if (ret != 0)
+               dev_err(wm8350->dev, "Failed to request IRQ: %d\n", ret);
+
+       return ret;
+}
+
+int wm8350_irq_exit(struct wm8350 *wm8350)
+{
+       free_irq(wm8350->chip_irq, wm8350);
+       return 0;
+}
index 7ccc1eab98ab51f01c750d8493fb01859836c17b..e965139e5cd5ba116369eedd05b72435621b6796 100644 (file)
@@ -3170,14 +3170,6 @@ const u16 wm8352_mode3_defaults[] = {
 };
 #endif
 
-/* The register defaults for the config mode used must be compiled in but
- * due to the impact on kernel size it is possible to disable
- */
-#ifndef WM8350_HAVE_CONFIG_MODE
-#warning No WM8350 config modes supported - select at least one of the
-#warning MFD_WM8350_CONFIG_MODE_n options from the board driver.
-#endif
-
 /*
  * Access masks.
  */
index 8c658cf6f62f3066d84c3b7e45ce79d6d0979dd4..109d2783e4d88fc6823b57d36dd8138a30e5d68b 100644 (file)
@@ -1378,7 +1378,7 @@ static void sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len)
        }
        __skb_pull(skb, sizeof(*p));
 
-       st = per_cpu_ptr(sge->port_stats[p->iff], smp_processor_id());
+       st = this_cpu_ptr(sge->port_stats[p->iff]);
 
        skb->protocol = eth_type_trans(skb, adapter->port[p->iff].dev);
        if ((adapter->flags & RX_CSUM_ENABLED) && p->csum == 0xffff &&
@@ -1780,8 +1780,7 @@ netdev_tx_t t1_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct adapter *adapter = dev->ml_priv;
        struct sge *sge = adapter->sge;
-       struct sge_port_stats *st = per_cpu_ptr(sge->port_stats[dev->if_port],
-                                               smp_processor_id());
+       struct sge_port_stats *st = this_cpu_ptr(sge->port_stats[dev->if_port]);
        struct cpl_tx_pkt *cpl;
        struct sk_buff *orig_skb = skb;
        int ret;
index eae4ad749e9d87956facbfadd53036d5d882ce03..b9fcc9819837e7f79530ad11782272ea0f81a344 100644 (file)
@@ -81,7 +81,7 @@ static netdev_tx_t loopback_xmit(struct sk_buff *skb,
 
        /* it's OK to use per_cpu_ptr() because BHs are off */
        pcpu_lstats = dev->ml_priv;
-       lb_stats = per_cpu_ptr(pcpu_lstats, smp_processor_id());
+       lb_stats = this_cpu_ptr(pcpu_lstats);
 
        len = skb->len;
        if (likely(netif_rx(skb) == NET_RX_SUCCESS)) {
index 81bafd57847814ef6875ff1447c092a5e24e1a03..d431b59e7d11bda7b203a96cec3217570344eade 100644 (file)
@@ -270,7 +270,7 @@ static int try_io_port(struct pcmcia_device *link)
            /* for master/slave multifunction cards */
            link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
            link->irq.Attributes =
-               IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
+               IRQ_TYPE_DYNAMIC_SHARING;
        }
     } else {
        /* This should be two 16-port windows */
index 8ad8384fc1c04ebde288ca9e8846d6b0ddb12eb7..813aca3fc433eed9d3411091e182e9f95c2602ca 100644 (file)
@@ -426,7 +426,7 @@ static int fmvj18x_config(struct pcmcia_device *link)
 
     if (link->io.NumPorts2 != 0) {
        link->irq.Attributes =
-               IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
+               IRQ_TYPE_DYNAMIC_SHARING;
        ret = mfc_try_io_port(link);
        if (ret != 0) goto failed;
     } else if (cardtype == UNGERMANN) {
index 2d26b6ca28b92949fd543b484d916a187c6bcaed..92ed3fbf89a570c8c063521d3613828976e71461 100644 (file)
@@ -490,7 +490,7 @@ static int try_io_port(struct pcmcia_device *link)
            /* for master/slave multifunction cards */
            link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
            link->irq.Attributes =
-               IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
+               IRQ_TYPE_DYNAMIC_SHARING;
        }
     } else {
        /* This should be two 16-port windows */
index cc4853bc025354ff62066ea9919598da1463b82d..6dd486d2977ba47c5ea72d98c2ea2d3378ebd435 100644 (file)
@@ -454,7 +454,7 @@ static int mhz_mfc_config(struct pcmcia_device *link)
     link->conf.Attributes |= CONF_ENABLE_SPKR;
     link->conf.Status = CCSR_AUDIO_ENA;
     link->irq.Attributes =
-       IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
+       IRQ_TYPE_DYNAMIC_SHARING;
     link->io.IOAddrLines = 16;
     link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
     link->io.NumPorts2 = 8;
index a2eda28f903ea6e6ccd2b4104280e28d3314c07d..466fc72698c03c4599e78f961e257c2d1013cf92 100644 (file)
@@ -841,7 +841,7 @@ xirc2ps_config(struct pcmcia_device * link)
            link->conf.Attributes |= CONF_ENABLE_SPKR;
            link->conf.Status |= CCSR_AUDIO_ENA;
        }
-       link->irq.Attributes |= IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED ;
+       link->irq.Attributes |= IRQ_TYPE_DYNAMIC_SHARING;
        link->io.NumPorts2 = 8;
        link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
        if (local->dingo) {
index 63099c58a6ddd7a92f616ca196141becbd7ad463..3a15de56df9caa31b818139dbcd75e2dc99e5cc8 100644 (file)
@@ -153,15 +153,14 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev)
        struct net_device *rcv = NULL;
        struct veth_priv *priv, *rcv_priv;
        struct veth_net_stats *stats, *rcv_stats;
-       int length, cpu;
+       int length;
 
        priv = netdev_priv(dev);
        rcv = priv->peer;
        rcv_priv = netdev_priv(rcv);
 
-       cpu = smp_processor_id();
-       stats = per_cpu_ptr(priv->stats, cpu);
-       rcv_stats = per_cpu_ptr(rcv_priv->stats, cpu);
+       stats = this_cpu_ptr(priv->stats);
+       rcv_stats = this_cpu_ptr(rcv_priv->stats);
 
        if (!(rcv->flags & IFF_UP))
                goto tx_drop;
index a7aae24f2889a4578ebd90dad52ae72aab916116..166b67ea622f11563a33c539b78c5dafc7c2503f 100644 (file)
@@ -47,7 +47,7 @@
  */
 static struct ring_buffer *op_ring_buffer_read;
 static struct ring_buffer *op_ring_buffer_write;
-DEFINE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer);
+DEFINE_PER_CPU(struct oprofile_cpu_buffer, op_cpu_buffer);
 
 static void wq_sync_buffer(struct work_struct *work);
 
@@ -61,8 +61,7 @@ unsigned long oprofile_get_cpu_buffer_size(void)
 
 void oprofile_cpu_buffer_inc_smpl_lost(void)
 {
-       struct oprofile_cpu_buffer *cpu_buf
-               = &__get_cpu_var(cpu_buffer);
+       struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(op_cpu_buffer);
 
        cpu_buf->sample_lost_overflow++;
 }
@@ -95,7 +94,7 @@ int alloc_cpu_buffers(void)
                goto fail;
 
        for_each_possible_cpu(i) {
-               struct oprofile_cpu_buffer *b = &per_cpu(cpu_buffer, i);
+               struct oprofile_cpu_buffer *b = &per_cpu(op_cpu_buffer, i);
 
                b->last_task = NULL;
                b->last_is_kernel = -1;
@@ -122,7 +121,7 @@ void start_cpu_work(void)
        work_enabled = 1;
 
        for_each_online_cpu(i) {
-               struct oprofile_cpu_buffer *b = &per_cpu(cpu_buffer, i);
+               struct oprofile_cpu_buffer *b = &per_cpu(op_cpu_buffer, i);
 
                /*
                 * Spread the work by 1 jiffy per cpu so they dont all
@@ -139,7 +138,7 @@ void end_cpu_work(void)
        work_enabled = 0;
 
        for_each_online_cpu(i) {
-               struct oprofile_cpu_buffer *b = &per_cpu(cpu_buffer, i);
+               struct oprofile_cpu_buffer *b = &per_cpu(op_cpu_buffer, i);
 
                cancel_delayed_work(&b->work);
        }
@@ -330,7 +329,7 @@ static inline void
 __oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs,
                          unsigned long event, int is_kernel)
 {
-       struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer);
+       struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(op_cpu_buffer);
        unsigned long backtrace = oprofile_backtrace_depth;
 
        /*
@@ -375,7 +374,7 @@ oprofile_write_reserve(struct op_entry *entry, struct pt_regs * const regs,
 {
        struct op_sample *sample;
        int is_kernel = !user_mode(regs);
-       struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer);
+       struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(op_cpu_buffer);
 
        cpu_buf->sample_received++;
 
@@ -430,13 +429,13 @@ int oprofile_write_commit(struct op_entry *entry)
 
 void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event)
 {
-       struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer);
+       struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(op_cpu_buffer);
        log_sample(cpu_buf, pc, 0, is_kernel, event);
 }
 
 void oprofile_add_trace(unsigned long pc)
 {
-       struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer);
+       struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(op_cpu_buffer);
 
        if (!cpu_buf->tracing)
                return;
index 272995d20293ab10aa4d77fb44d7f4bd79d76afb..68ea16ab645f3e3e134b56db9269df2044234b92 100644 (file)
@@ -50,7 +50,7 @@ struct oprofile_cpu_buffer {
        struct delayed_work work;
 };
 
-DECLARE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer);
+DECLARE_PER_CPU(struct oprofile_cpu_buffer, op_cpu_buffer);
 
 /*
  * Resets the cpu buffer to a sane state.
@@ -60,7 +60,7 @@ DECLARE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer);
  */
 static inline void op_cpu_buffer_reset(int cpu)
 {
-       struct oprofile_cpu_buffer *cpu_buf = &per_cpu(cpu_buffer, cpu);
+       struct oprofile_cpu_buffer *cpu_buf = &per_cpu(op_cpu_buffer, cpu);
 
        cpu_buf->last_is_kernel = -1;
        cpu_buf->last_task = NULL;
index 61689e814d465fc90bb0652d0c5cec9380e185f5..917d28ebeacd24ab2a6f0f3772be1846b4011bb5 100644 (file)
@@ -23,7 +23,7 @@ void oprofile_reset_stats(void)
        int i;
 
        for_each_possible_cpu(i) {
-               cpu_buf = &per_cpu(cpu_buffer, i);
+               cpu_buf = &per_cpu(op_cpu_buffer, i);
                cpu_buf->sample_received = 0;
                cpu_buf->sample_lost_overflow = 0;
                cpu_buf->backtrace_aborted = 0;
@@ -51,7 +51,7 @@ void oprofile_create_stats_files(struct super_block *sb, struct dentry *root)
                return;
 
        for_each_possible_cpu(i) {
-               cpu_buf = &per_cpu(cpu_buffer, i);
+               cpu_buf = &per_cpu(op_cpu_buffer, i);
                snprintf(buf, 10, "cpu%d", i);
                cpudir = oprofilefs_mkdir(sb, dir, buf);
 
index cd5082d3ca19272294410fa8b45f82b9aa6b9494..9f3adbd9f7005e02b6886f5915f42faaee89994f 100644 (file)
@@ -64,7 +64,7 @@ config PCMCIA_IOCTL
          If unsure, say Y.
 
 config CARDBUS
-       bool "32-bit CardBus support"   
+       bool "32-bit CardBus support"
        depends on PCI
        default y
        ---help---
@@ -87,8 +87,8 @@ config YENTA
        select PCCARD_NONSTATIC
        ---help---
          This option enables support for CardBus host bridges.  Virtually
-         all modern PCMCIA bridges are CardBus compatible.  A "bridge" is 
-         the hardware inside your computer that PCMCIA cards are plugged 
+         all modern PCMCIA bridges are CardBus compatible.  A "bridge" is
+         the hardware inside your computer that PCMCIA cards are plugged
          into.
 
          To compile this driver as modules, choose M here: the
@@ -208,7 +208,7 @@ config PCMCIA_PXA2XX
        depends on ARM && ARCH_PXA && PCMCIA
        depends on (ARCH_LUBBOCK || MACH_MAINSTONE || PXA_SHARPSL \
                    || MACH_ARMCORE || ARCH_PXA_PALM || TRIZEPS_PCMCIA \
-                   || ARCH_VIPER || ARCH_PXA_ESERIES || MACH_STARGATE2)
+                   || ARCOM_PCMCIA || ARCH_PXA_ESERIES || MACH_STARGATE2)
        select PCMCIA_SOC_COMMON
        help
          Say Y here to include support for the PXA2xx PCMCIA controller
index 382938313991a263d77a43c5a03d28516f9939cb..83ff802de5446944d895f9c796d0544275c97533 100644 (file)
@@ -67,7 +67,7 @@ pxa2xx-obj-$(CONFIG_ARCH_LUBBOCK)             += pxa2xx_lubbock_cs.o
 pxa2xx-obj-$(CONFIG_MACH_MAINSTONE)            += pxa2xx_mainstone.o
 pxa2xx-obj-$(CONFIG_PXA_SHARPSL)               += pxa2xx_sharpsl.o
 pxa2xx-obj-$(CONFIG_MACH_ARMCORE)              += pxa2xx_cm_x2xx_cs.o
-pxa2xx-obj-$(CONFIG_ARCH_VIPER)                        += pxa2xx_viper.o
+pxa2xx-obj-$(CONFIG_ARCOM_PCMCIA)              += pxa2xx_viper.o
 pxa2xx-obj-$(CONFIG_TRIZEPS_PCMCIA)            += pxa2xx_trizeps4.o
 pxa2xx-obj-$(CONFIG_MACH_PALMTX)               += pxa2xx_palmtx.o
 pxa2xx-obj-$(CONFIG_MACH_PALMTC)               += pxa2xx_palmtc.o
index a73b040ddbfb81102fffe2a6da4768155f7689e3..cdf50f3bc2df389af234ed8976017ba5c717e218 100644 (file)
@@ -27,8 +27,8 @@
 #include <linux/mm.h>
 #include <linux/pci.h>
 #include <linux/ioport.h>
+#include <linux/io.h>
 #include <asm/irq.h>
-#include <asm/io.h>
 
 #include <pcmcia/cs_types.h>
 #include <pcmcia/ss.h>
@@ -58,7 +58,7 @@
     image number and an offset within that image.  xlate_rom_addr()
     converts an image/offset address to an absolute offset from the
     ROM's base address.
-    
+
 =====================================================================*/
 
 static u_int xlate_rom_addr(void __iomem *b, u_int addr)
@@ -85,10 +85,10 @@ static u_int xlate_rom_addr(void __iomem *b, u_int addr)
     These are similar to setup_cis_mem and release_cis_mem for 16-bit
     cards.  The "result" that is used externally is the cb_cis_virt
     pointer in the struct pcmcia_socket structure.
-    
+
 =====================================================================*/
 
-static void cb_release_cis_mem(struct pcmcia_socket * s)
+static void cb_release_cis_mem(struct pcmcia_socket *s)
 {
        if (s->cb_cis_virt) {
                dev_dbg(&s->dev, "cb_release_cis_mem()\n");
@@ -98,7 +98,7 @@ static void cb_release_cis_mem(struct pcmcia_socket * s)
        }
 }
 
-static int cb_setup_cis_mem(struct pcmcia_socket * s, struct resource *res)
+static int cb_setup_cis_mem(struct pcmcia_socket *s, struct resource *res)
 {
        unsigned int start, size;
 
@@ -124,10 +124,11 @@ static int cb_setup_cis_mem(struct pcmcia_socket * s, struct resource *res)
 
     This is used by the CIS processing code to read CIS information
     from a CardBus device.
-    
+
 =====================================================================*/
 
-int read_cb_mem(struct pcmcia_socket * s, int space, u_int addr, u_int len, void *ptr)
+int read_cb_mem(struct pcmcia_socket *s, int space, u_int addr, u_int len,
+               void *ptr)
 {
        struct pci_dev *dev;
        struct resource *res;
@@ -181,7 +182,7 @@ fail:
     cb_alloc() and cb_free() allocate and free the kernel data
     structures for a Cardbus device, and handle the lowest level PCI
     device setup issues.
-    
+
 =====================================================================*/
 
 static void cardbus_config_irq_and_cls(struct pci_bus *bus, int irq)
@@ -214,14 +215,14 @@ static void cardbus_config_irq_and_cls(struct pci_bus *bus, int irq)
        }
 }
 
-int __ref cb_alloc(struct pcmcia_socket * s)
+int __ref cb_alloc(struct pcmcia_socket *s)
 {
        struct pci_bus *bus = s->cb_dev->subordinate;
        struct pci_dev *dev;
        unsigned int max, pass;
 
        s->functions = pci_scan_slot(bus, PCI_DEVFN(0, 0));
-//     pcibios_fixup_bus(bus);
+/*     pcibios_fixup_bus(bus); */
 
        max = bus->secondary;
        for (pass = 0; pass < 2; pass++)
@@ -248,7 +249,7 @@ int __ref cb_alloc(struct pcmcia_socket * s)
        return 0;
 }
 
-void cb_free(struct pcmcia_socket * s)
+void cb_free(struct pcmcia_socket *s)
 {
        struct pci_dev *bridge = s->cb_dev;
 
index 8c1b73cf021b2fee37c17f792748f27b0ec5f794..25b1cd219e374202b6d4f8f3fd84e849204daaa3 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/mm.h>
 #include <linux/pci.h>
 #include <linux/ioport.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <asm/byteorder.h>
 #include <asm/unaligned.h>
 
@@ -125,7 +125,7 @@ set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flag
 
     Low-level functions to read and write CIS memory.  I think the
     write routine is only useful for writing one-byte registers.
-    
+
 ======================================================================*/
 
 /* Bits in attr field */
@@ -137,7 +137,7 @@ int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
 {
     void __iomem *sys, *end;
     unsigned char *buf = ptr;
-    
+
     dev_dbg(&s->dev, "pcmcia_read_cis_mem(%d, %#x, %u)\n", attr, addr, len);
 
     if (attr & IS_INDIRECT) {
@@ -203,7 +203,7 @@ void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
 {
     void __iomem *sys, *end;
     unsigned char *buf = ptr;
-    
+
     dev_dbg(&s->dev, "pcmcia_write_cis_mem(%d, %#x, %u)\n", attr, addr, len);
 
     if (attr & IS_INDIRECT) {
@@ -262,7 +262,7 @@ EXPORT_SYMBOL(pcmcia_write_cis_mem);
     This is a wrapper around read_cis_mem, with the same interface,
     but which caches information, for cards whose CIS may not be
     readable all the time.
-    
+
 ======================================================================*/
 
 static void read_cis_cache(struct pcmcia_socket *s, int attr, u_int addr,
@@ -342,7 +342,7 @@ EXPORT_SYMBOL(destroy_cis_cache);
 
     This verifies if the CIS of a card matches what is in the CIS
     cache.
-    
+
 ======================================================================*/
 
 int verify_cis_cache(struct pcmcia_socket *s)
@@ -381,7 +381,7 @@ int verify_cis_cache(struct pcmcia_socket *s)
 
     For really bad cards, we provide a facility for uploading a
     replacement CIS.
-    
+
 ======================================================================*/
 
 int pcmcia_replace_cis(struct pcmcia_socket *s,
@@ -406,7 +406,7 @@ EXPORT_SYMBOL(pcmcia_replace_cis);
 /*======================================================================
 
     The high-level CIS tuple services
-    
+
 ======================================================================*/
 
 typedef struct tuple_flags {
@@ -421,8 +421,6 @@ typedef struct tuple_flags {
 #define MFC_FN(f)      (((tuple_flags *)(&(f)))->mfc_fn)
 #define SPACE(f)       (((tuple_flags *)(&(f)))->space)
 
-int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int func, tuple_t *tuple);
-
 int pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function, tuple_t *tuple)
 {
     if (!s)
@@ -523,10 +521,11 @@ int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function, tuple_
                ofs++; continue;
            }
        }
-       
+
        /* End of chain?  Follow long link if possible */
        if (link[0] == CISTPL_END) {
-           if ((ofs = follow_link(s, tuple)) < 0)
+           ofs = follow_link(s, tuple);
+           if (ofs < 0)
                return -ENOSPC;
            attr = SPACE(tuple->Flags);
            read_cis_cache(s, attr, ofs, 2, link);
@@ -578,7 +577,7 @@ int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function, tuple_
        } else
            if (tuple->DesiredTuple == RETURN_FIRST_TUPLE)
                break;
-       
+
        if (link[0] == tuple->DesiredTuple)
            break;
        ofs += link[1] + 2;
@@ -587,7 +586,7 @@ int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function, tuple_
        dev_dbg(&s->dev, "cs: overrun in pcmcia_get_next_tuple\n");
        return -ENOSPC;
     }
-    
+
     tuple->TupleCode = link[0];
     tuple->TupleLink = link[1];
     tuple->CISOffset = ofs + 2;
@@ -623,7 +622,7 @@ EXPORT_SYMBOL(pccard_get_tuple_data);
 /*======================================================================
 
     Parsing routines for individual tuples
-    
+
 ======================================================================*/
 
 static int parse_device(tuple_t *tuple, cistpl_device_t *device)
@@ -637,26 +636,37 @@ static int parse_device(tuple_t *tuple, cistpl_device_t *device)
 
     device->ndev = 0;
     for (i = 0; i < CISTPL_MAX_DEVICES; i++) {
-       
-       if (*p == 0xff) break;
+
+       if (*p == 0xff)
+               break;
        device->dev[i].type = (*p >> 4);
        device->dev[i].wp = (*p & 0x08) ? 1 : 0;
        switch (*p & 0x07) {
-       case 0: device->dev[i].speed = 0;   break;
-       case 1: device->dev[i].speed = 250; break;
-       case 2: device->dev[i].speed = 200; break;
-       case 3: device->dev[i].speed = 150; break;
-       case 4: device->dev[i].speed = 100; break;
+       case 0:
+               device->dev[i].speed = 0;
+               break;
+       case 1:
+               device->dev[i].speed = 250;
+               break;
+       case 2:
+               device->dev[i].speed = 200;
+               break;
+       case 3:
+               device->dev[i].speed = 150;
+               break;
+       case 4:
+               device->dev[i].speed = 100;
+               break;
        case 7:
-           if (++p == q)
-                   return -EINVAL;
-           device->dev[i].speed = SPEED_CVT(*p);
-           while (*p & 0x80)
                if (++p == q)
                        return -EINVAL;
-           break;
+               device->dev[i].speed = SPEED_CVT(*p);
+               while (*p & 0x80)
+                       if (++p == q)
+                               return -EINVAL;
+               break;
        default:
-           return -EINVAL;
+               return -EINVAL;
        }
 
        if (++p == q)
@@ -671,7 +681,7 @@ static int parse_device(tuple_t *tuple, cistpl_device_t *device)
        if (++p == q)
                break;
     }
-    
+
     return 0;
 }
 
@@ -706,9 +716,9 @@ static int parse_longlink_mfc(tuple_t *tuple,
 {
     u_char *p;
     int i;
-    
+
     p = (u_char *)tuple->TupleData;
-    
+
     link->nfn = *p; p++;
     if (tuple->TupleDataLen <= link->nfn*5)
        return -EINVAL;
@@ -737,11 +747,13 @@ static int parse_strings(u_char *p, u_char *q, int max,
        ns++;
        for (;;) {
            s[j++] = (*p == 0xff) ? '\0' : *p;
-           if ((*p == '\0') || (*p == 0xff)) break;
+           if ((*p == '\0') || (*p == 0xff))
+                   break;
            if (++p == q)
                    return -EINVAL;
        }
-       if ((*p == 0xff) || (++p == q)) break;
+       if ((*p == 0xff) || (++p == q))
+               break;
     }
     if (found) {
        *found = ns;
@@ -756,10 +768,10 @@ static int parse_strings(u_char *p, u_char *q, int max,
 static int parse_vers_1(tuple_t *tuple, cistpl_vers_1_t *vers_1)
 {
     u_char *p, *q;
-    
+
     p = (u_char *)tuple->TupleData;
     q = p + tuple->TupleDataLen;
-    
+
     vers_1->major = *p; p++;
     vers_1->minor = *p; p++;
     if (p >= q)
@@ -774,10 +786,10 @@ static int parse_vers_1(tuple_t *tuple, cistpl_vers_1_t *vers_1)
 static int parse_altstr(tuple_t *tuple, cistpl_altstr_t *altstr)
 {
     u_char *p, *q;
-    
+
     p = (u_char *)tuple->TupleData;
     q = p + tuple->TupleDataLen;
-    
+
     return parse_strings(p, q, CISTPL_MAX_ALTSTR_STRINGS,
                         altstr->str, altstr->ofs, &altstr->ns);
 }
@@ -793,7 +805,8 @@ static int parse_jedec(tuple_t *tuple, cistpl_jedec_t *jedec)
     q = p + tuple->TupleDataLen;
 
     for (nid = 0; nid < CISTPL_MAX_DEVICES; nid++) {
-       if (p > q-2) break;
+       if (p > q-2)
+               break;
        jedec->id[nid].mfr = p[0];
        jedec->id[nid].info = p[1];
        p += 2;
@@ -871,7 +884,7 @@ static int parse_config(tuple_t *tuple, cistpl_config_t *config)
 
     The following routines are all used to parse the nightmarish
     config table entries.
-    
+
 ======================================================================*/
 
 static u_char *parse_power(u_char *p, u_char *q,
@@ -880,17 +893,20 @@ static u_char *parse_power(u_char *p, u_char *q,
     int i;
     u_int scale;
 
-    if (p == q) return NULL;
+    if (p == q)
+           return NULL;
     pwr->present = *p;
     pwr->flags = 0;
     p++;
     for (i = 0; i < 7; i++)
        if (pwr->present & (1<<i)) {
-           if (p == q) return NULL;
+           if (p == q)
+                   return NULL;
            pwr->param[i] = POWER_CVT(*p);
            scale = POWER_SCALE(*p);
            while (*p & 0x80) {
-               if (++p == q) return NULL;
+               if (++p == q)
+                       return NULL;
                if ((*p & 0x7f) < 100)
                    pwr->param[i] += (*p & 0x7f) * scale / 100;
                else if (*p == 0x7d)
@@ -914,24 +930,28 @@ static u_char *parse_timing(u_char *p, u_char *q,
 {
     u_char scale;
 
-    if (p == q) return NULL;
+    if (p == q)
+           return NULL;
     scale = *p;
     if ((scale & 3) != 3) {
-       if (++p == q) return NULL;
+       if (++p == q)
+               return NULL;
        timing->wait = SPEED_CVT(*p);
        timing->waitscale = exponent[scale & 3];
     } else
        timing->wait = 0;
     scale >>= 2;
     if ((scale & 7) != 7) {
-       if (++p == q) return NULL;
+       if (++p == q)
+               return NULL;
        timing->ready = SPEED_CVT(*p);
        timing->rdyscale = exponent[scale & 7];
     } else
        timing->ready = 0;
     scale >>= 3;
     if (scale != 7) {
-       if (++p == q) return NULL;
+       if (++p == q)
+               return NULL;
        timing->reserved = SPEED_CVT(*p);
        timing->rsvscale = exponent[scale];
     } else
@@ -946,7 +966,8 @@ static u_char *parse_io(u_char *p, u_char *q, cistpl_io_t *io)
 {
     int i, j, bsz, lsz;
 
-    if (p == q) return NULL;
+    if (p == q)
+           return NULL;
     io->flags = *p;
 
     if (!(*p & 0x80)) {
@@ -955,24 +976,29 @@ static u_char *parse_io(u_char *p, u_char *q, cistpl_io_t *io)
        io->win[0].len = (1 << (io->flags & CISTPL_IO_LINES_MASK));
        return p+1;
     }
-    
-    if (++p == q) return NULL;
+
+    if (++p == q)
+           return NULL;
     io->nwin = (*p & 0x0f) + 1;
     bsz = (*p & 0x30) >> 4;
-    if (bsz == 3) bsz++;
+    if (bsz == 3)
+           bsz++;
     lsz = (*p & 0xc0) >> 6;
-    if (lsz == 3) lsz++;
+    if (lsz == 3)
+           lsz++;
     p++;
-    
+
     for (i = 0; i < io->nwin; i++) {
        io->win[i].base = 0;
        io->win[i].len = 1;
        for (j = 0; j < bsz; j++, p++) {
-           if (p == q) return NULL;
+           if (p == q)
+                   return NULL;
            io->win[i].base += *p << (j*8);
        }
        for (j = 0; j < lsz; j++, p++) {
-           if (p == q) return NULL;
+           if (p == q)
+                   return NULL;
            io->win[i].len += *p << (j*8);
        }
     }
@@ -986,27 +1012,32 @@ static u_char *parse_mem(u_char *p, u_char *q, cistpl_mem_t *mem)
     int i, j, asz, lsz, has_ha;
     u_int len, ca, ha;
 
-    if (p == q) return NULL;
+    if (p == q)
+           return NULL;
 
     mem->nwin = (*p & 0x07) + 1;
     lsz = (*p & 0x18) >> 3;
     asz = (*p & 0x60) >> 5;
     has_ha = (*p & 0x80);
-    if (++p == q) return NULL;
-    
+    if (++p == q)
+           return NULL;
+
     for (i = 0; i < mem->nwin; i++) {
        len = ca = ha = 0;
        for (j = 0; j < lsz; j++, p++) {
-           if (p == q) return NULL;
+           if (p == q)
+                   return NULL;
            len += *p << (j*8);
        }
        for (j = 0; j < asz; j++, p++) {
-           if (p == q) return NULL;
+           if (p == q)
+                   return NULL;
            ca += *p << (j*8);
        }
        if (has_ha)
            for (j = 0; j < asz; j++, p++) {
-               if (p == q) return NULL;
+               if (p == q)
+                       return NULL;
                ha += *p << (j*8);
            }
        mem->win[i].len = len << 8;
@@ -1095,7 +1126,7 @@ static int parse_cftable_entry(tuple_t *tuple,
        entry->timing.ready = 0;
        entry->timing.reserved = 0;
     }
-    
+
     /* I/O window options */
     if (features & 0x08) {
        p = parse_io(p, q, &entry->io);
@@ -1103,7 +1134,7 @@ static int parse_cftable_entry(tuple_t *tuple,
                return -EINVAL;
     } else
        entry->io.nwin = 0;
-    
+
     /* Interrupt options */
     if (features & 0x10) {
        p = parse_irq(p, q, &entry->irq);
@@ -1153,7 +1184,7 @@ static int parse_cftable_entry(tuple_t *tuple,
     }
 
     entry->subtuples = q-p;
-    
+
     return 0;
 }
 
@@ -1176,7 +1207,7 @@ static int parse_bar(tuple_t *tuple, cistpl_bar_t *bar)
 static int parse_config_cb(tuple_t *tuple, cistpl_config_t *config)
 {
     u_char *p;
-    
+
     p = (u_char *)tuple->TupleData;
     if ((*p != 3) || (tuple->TupleDataLen < 6))
        return -EINVAL;
@@ -1231,7 +1262,7 @@ static int parse_cftable_entry_cb(tuple_t *tuple,
        entry->io = *p; p++;
     } else
        entry->io = 0;
-    
+
     /* Interrupt options */
     if (features & 0x10) {
        p = parse_irq(p, q, &entry->irq);
@@ -1264,7 +1295,7 @@ static int parse_cftable_entry_cb(tuple_t *tuple,
     }
 
     entry->subtuples = q-p;
-    
+
     return 0;
 }
 
@@ -1281,7 +1312,8 @@ static int parse_device_geo(tuple_t *tuple, cistpl_device_geo_t *geo)
     q = p + tuple->TupleDataLen;
 
     for (n = 0; n < CISTPL_MAX_DEVICES; n++) {
-       if (p > q-6) break;
+       if (p > q-6)
+               break;
        geo->geo[n].buswidth = p[0];
        geo->geo[n].erase_block = 1 << (p[1]-1);
        geo->geo[n].read_block  = 1 << (p[2]-1);
@@ -1302,13 +1334,13 @@ static int parse_vers_2(tuple_t *tuple, cistpl_vers_2_t *v2)
 
     if (tuple->TupleDataLen < 10)
        return -EINVAL;
-    
+
     p = tuple->TupleData;
     q = p + tuple->TupleDataLen;
 
     v2->vers = p[0];
     v2->comply = p[1];
-    v2->dindex = get_unaligned_le16(p +);
+    v2->dindex = get_unaligned_le16(p + 2);
     v2->vspec8 = p[6];
     v2->vspec9 = p[7];
     v2->nhdr = p[8];
@@ -1322,7 +1354,7 @@ static int parse_org(tuple_t *tuple, cistpl_org_t *org)
 {
     u_char *p, *q;
     int i;
-    
+
     p = tuple->TupleData;
     q = p + tuple->TupleDataLen;
     if (p == q)
@@ -1332,7 +1364,8 @@ static int parse_org(tuple_t *tuple, cistpl_org_t *org)
            return -EINVAL;
     for (i = 0; i < 30; i++) {
        org->desc[i] = *p;
-       if (*p == '\0') break;
+       if (*p == '\0')
+               break;
        if (++p == q)
                return -EINVAL;
     }
@@ -1363,7 +1396,7 @@ static int parse_format(tuple_t *tuple, cistpl_format_t *fmt)
 int pcmcia_parse_tuple(tuple_t *tuple, cisparse_t *parse)
 {
     int ret = 0;
-    
+
     if (tuple->TupleDataLen > tuple->TupleDataMax)
        return -EINVAL;
     switch (tuple->TupleCode) {
@@ -1448,7 +1481,7 @@ EXPORT_SYMBOL(pcmcia_parse_tuple);
 /*======================================================================
 
     This is used internally by Card Services to look up CIS stuff.
-    
+
 ======================================================================*/
 
 int pccard_read_tuple(struct pcmcia_socket *s, unsigned int function, cisdata_t code, void *parse)
@@ -1550,7 +1583,7 @@ EXPORT_SYMBOL(pccard_loop_tuple);
     checks include making sure several critical tuples are present and
     valid; seeing if the total number of tuples is reasonable; and
     looking for tuples that use reserved codes.
-    
+
 ======================================================================*/
 
 int pccard_validate_cis(struct pcmcia_socket *s, unsigned int *info)
index 790af87a922fc6e541f5ab2bb02d2b2f315388d9..6d6f82b38a68c9ffaf341504a3dbdbac882a5496 100644 (file)
@@ -135,7 +135,7 @@ int pcmcia_socket_dev_resume(struct device *dev)
 EXPORT_SYMBOL(pcmcia_socket_dev_resume);
 
 
-struct pcmcia_socket * pcmcia_get_socket(struct pcmcia_socket *skt)
+struct pcmcia_socket *pcmcia_get_socket(struct pcmcia_socket *skt)
 {
        struct device *dev = get_device(&skt->dev);
        if (!dev)
@@ -145,7 +145,7 @@ struct pcmcia_socket * pcmcia_get_socket(struct pcmcia_socket *skt)
                put_device(&skt->dev);
                return NULL;
        }
-       return (skt);
+       return skt;
 }
 EXPORT_SYMBOL(pcmcia_get_socket);
 
@@ -297,7 +297,7 @@ void pcmcia_unregister_socket(struct pcmcia_socket *socket)
 EXPORT_SYMBOL(pcmcia_unregister_socket);
 
 
-struct pcmcia_socket * pcmcia_get_socket_by_nr(unsigned int nr)
+struct pcmcia_socket *pcmcia_get_socket_by_nr(unsigned int nr)
 {
        struct pcmcia_socket *s;
 
@@ -736,7 +736,7 @@ EXPORT_SYMBOL(pcmcia_parse_events);
 /* register pcmcia_callback */
 int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c)
 {
-        int ret = 0;
+       int ret = 0;
 
        /* s->skt_mutex also protects s->callback */
        mutex_lock(&s->skt_mutex);
@@ -848,7 +848,7 @@ EXPORT_SYMBOL(pcmcia_suspend_card);
 int pcmcia_resume_card(struct pcmcia_socket *skt)
 {
        int ret;
-    
+
        dev_dbg(&skt->dev, "waking up socket\n");
 
        mutex_lock(&skt->skt_mutex);
@@ -876,7 +876,7 @@ EXPORT_SYMBOL(pcmcia_resume_card);
 int pcmcia_eject_card(struct pcmcia_socket *skt)
 {
        int ret;
-    
+
        dev_dbg(&skt->dev, "user eject request\n");
 
        mutex_lock(&skt->skt_mutex);
index 05893d41dd418d19dde7847da6f33c7926b2b966..1a4a3c49cc15c71fe9db9ab07f61fd4cdff194ad 100644 (file)
@@ -57,7 +57,7 @@ static void pcmcia_check_driver(struct pcmcia_driver *p_drv)
                       "function\n", p_drv->drv.name);
 
        while (did && did->match_flags) {
-               for (i=0; i<4; i++) {
+               for (i = 0; i < 4; i++) {
                        if (!did->prod_id[i])
                                continue;
 
@@ -105,7 +105,7 @@ pcmcia_store_new_id(struct device_driver *driver, const char *buf, size_t count)
        __u16 match_flags, manf_id, card_id;
        __u8 func_id, function, device_no;
        __u32 prod_id_hash[4] = {0, 0, 0, 0};
-       int fields=0;
+       int fields = 0;
        int retval = 0;
 
        fields = sscanf(buf, "%hx %hx %hx %hhx %hhx %hhx %x %x %x %x",
@@ -214,7 +214,7 @@ EXPORT_SYMBOL(pcmcia_unregister_driver);
 
 /* pcmcia_device handling */
 
-struct pcmcia_device * pcmcia_get_dev(struct pcmcia_device *p_dev)
+struct pcmcia_device *pcmcia_get_dev(struct pcmcia_device *p_dev)
 {
        struct device *tmp_dev;
        tmp_dev = get_device(&p_dev->dev);
@@ -258,7 +258,7 @@ static void pcmcia_add_device_later(struct pcmcia_socket *s, int mfc)
        return;
 }
 
-static int pcmcia_device_probe(struct device * dev)
+static int pcmcia_device_probe(struct device *dev)
 {
        struct pcmcia_device *p_dev;
        struct pcmcia_driver *p_drv;
@@ -325,7 +325,7 @@ put_module:
 put_dev:
        if (ret)
                put_device(dev);
-       return (ret);
+       return ret;
 }
 
 
@@ -354,7 +354,7 @@ static void pcmcia_card_remove(struct pcmcia_socket *s, struct pcmcia_device *le
 
                spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
                list_del(&p_dev->socket_device_list);
-               p_dev->_removed=1;
+               p_dev->_removed = 1;
                spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
 
                dev_dbg(&p_dev->dev, "unregistering device\n");
@@ -364,7 +364,7 @@ static void pcmcia_card_remove(struct pcmcia_socket *s, struct pcmcia_device *le
        return;
 }
 
-static int pcmcia_device_remove(struct device * dev)
+static int pcmcia_device_remove(struct device *dev)
 {
        struct pcmcia_device *p_dev;
        struct pcmcia_driver *p_drv;
@@ -391,7 +391,7 @@ static int pcmcia_device_remove(struct device * dev)
                return 0;
 
        if (p_drv->remove)
-               p_drv->remove(p_dev);
+               p_drv->remove(p_dev);
 
        p_dev->dev_node = NULL;
 
@@ -499,7 +499,7 @@ static int pcmcia_device_query(struct pcmcia_device *p_dev)
  */
 static DEFINE_MUTEX(device_add_lock);
 
-struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int function)
+struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, unsigned int function)
 {
        struct pcmcia_device *p_dev, *tmp_dev;
        unsigned long flags;
@@ -545,8 +545,8 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f
         * Note that this is serialized by the device_add_lock, so that
         * only one such struct will be created.
         */
-        list_for_each_entry(tmp_dev, &s->devices_list, socket_device_list)
-                if (p_dev->func == tmp_dev->func) {
+       list_for_each_entry(tmp_dev, &s->devices_list, socket_device_list)
+               if (p_dev->func == tmp_dev->func) {
                        p_dev->function_config = tmp_dev->function_config;
                        p_dev->io = tmp_dev->io;
                        p_dev->irq = tmp_dev->irq;
@@ -627,10 +627,10 @@ static int pcmcia_card_add(struct pcmcia_socket *s)
                no_funcs = 1;
        s->functions = no_funcs;
 
-       for (i=0; i < no_funcs; i++)
+       for (i = 0; i < no_funcs; i++)
                pcmcia_device_add(s, i);
 
-       return (ret);
+       return ret;
 }
 
 
@@ -756,7 +756,7 @@ static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
  release:
        release_firmware(fw);
 
-       return (ret);
+       return ret;
 }
 
 #else /* !CONFIG_PCMCIA_LOAD_CIS */
@@ -852,7 +852,7 @@ static inline int pcmcia_devmatch(struct pcmcia_device *dev,
 
        if (did->match_flags & PCMCIA_DEV_ID_MATCH_ANONYMOUS) {
                int i;
-               for (i=0; i<4; i++)
+               for (i = 0; i < 4; i++)
                        if (dev->prod_id[i])
                                return 0;
                if (dev->has_manf_id || dev->has_card_id || dev->has_func_id)
@@ -865,9 +865,10 @@ static inline int pcmcia_devmatch(struct pcmcia_device *dev,
 }
 
 
-static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) {
-       struct pcmcia_device * p_dev = to_pcmcia_dev(dev);
-       struct pcmcia_driver * p_drv = to_pcmcia_drv(drv);
+static int pcmcia_bus_match(struct device *dev, struct device_driver *drv)
+{
+       struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+       struct pcmcia_driver *p_drv = to_pcmcia_drv(drv);
        struct pcmcia_device_id *did = p_drv->id_table;
        struct pcmcia_dynid *dynid;
 
@@ -917,7 +918,7 @@ static int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
        p_dev = to_pcmcia_dev(dev);
 
        /* calculate hashes */
-       for (i=0; i<4; i++) {
+       for (i = 0; i < 4; i++) {
                if (!p_dev->prod_id[i])
                        continue;
                hash[i] = crc32(0, p_dev->prod_id[i], strlen(p_dev->prod_id[i]));
@@ -984,14 +985,14 @@ static void runtime_resume(struct device *dev)
 static ssize_t field##_show (struct device *dev, struct device_attribute *attr, char *buf)             \
 {                                                                      \
        struct pcmcia_device *p_dev = to_pcmcia_dev(dev);               \
-       return p_dev->test ? sprintf (buf, format, p_dev->field) : -ENODEV; \
+       return p_dev->test ? sprintf(buf, format, p_dev->field) : -ENODEV; \
 }
 
 #define pcmcia_device_stringattr(name, field)                                  \
 static ssize_t name##_show (struct device *dev, struct device_attribute *attr, char *buf)              \
 {                                                                      \
        struct pcmcia_device *p_dev = to_pcmcia_dev(dev);               \
-       return p_dev->field ? sprintf (buf, "%s\n", p_dev->field) : -ENODEV; \
+       return p_dev->field ? sprintf(buf, "%s\n", p_dev->field) : -ENODEV; \
 }
 
 pcmcia_device_attr(func, socket, "0x%02x\n");
@@ -1020,8 +1021,8 @@ static ssize_t pcmcia_store_pm_state(struct device *dev, struct device_attribute
        struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
        int ret = 0;
 
-        if (!count)
-                return -EINVAL;
+       if (!count)
+               return -EINVAL;
 
        if ((!p_dev->suspended) && !strncmp(buf, "off", 3))
                ret = runtime_suspend(dev);
@@ -1039,10 +1040,11 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
        u32 hash[4] = { 0, 0, 0, 0};
 
        /* calculate hashes */
-       for (i=0; i<4; i++) {
+       for (i = 0; i < 4; i++) {
                if (!p_dev->prod_id[i])
                        continue;
-               hash[i] = crc32(0,p_dev->prod_id[i],strlen(p_dev->prod_id[i]));
+               hash[i] = crc32(0, p_dev->prod_id[i],
+                               strlen(p_dev->prod_id[i]));
        }
        return sprintf(buf, "pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X"
                                "pa%08Xpb%08Xpc%08Xpd%08X\n",
@@ -1091,7 +1093,7 @@ static struct device_attribute pcmcia_dev_attrs[] = {
 
 /* PM support, also needed for reset */
 
-static int pcmcia_dev_suspend(struct device * dev, pm_message_t state)
+static int pcmcia_dev_suspend(struct device *dev, pm_message_t state)
 {
        struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
        struct pcmcia_driver *p_drv = NULL;
@@ -1131,10 +1133,10 @@ static int pcmcia_dev_suspend(struct device * dev, pm_message_t state)
 }
 
 
-static int pcmcia_dev_resume(struct device * dev)
+static int pcmcia_dev_resume(struct device *dev)
 {
        struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
-        struct pcmcia_driver *p_drv = NULL;
+       struct pcmcia_driver *p_drv = NULL;
        int ret = 0;
 
        if (!p_dev->suspended)
@@ -1211,7 +1213,7 @@ static int pcmcia_bus_suspend(struct pcmcia_socket *skt)
 /*======================================================================
 
     The card status event handler.
-    
+
 ======================================================================*/
 
 /* Normally, the event is passed to individual drivers after
@@ -1264,7 +1266,7 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
 } /* ds_event */
 
 
-struct pcmcia_device * pcmcia_dev_present(struct pcmcia_device *_p_dev)
+struct pcmcia_device *pcmcia_dev_present(struct pcmcia_device *_p_dev)
 {
        struct pcmcia_device *p_dev;
        struct pcmcia_device *ret = NULL;
@@ -1329,7 +1331,7 @@ static int __devinit pcmcia_bus_add_socket(struct device *dev,
        if (ret) {
                dev_printk(KERN_ERR, dev, "PCMCIA registration failed\n");
                pcmcia_put_socket(socket);
-               return (ret);
+               return ret;
        }
 
        return 0;
@@ -1400,7 +1402,7 @@ static int __init init_pcmcia_bus(void)
 
        return 0;
 }
-fs_initcall(init_pcmcia_bus); /* one level after subsys_initcall so that 
+fs_initcall(init_pcmcia_bus); /* one level after subsys_initcall so that
                               * pcmcia_socket_class is already registered */
 
 
index c4d7908fa37f1974f413627cd3b274512ec872ae..f73fd5beaa372f05ddd64a8621b6c1786e64c366 100644 (file)
@@ -88,12 +88,12 @@ static struct pcmcia_driver *get_pcmcia_driver(dev_info_t *dev_info)
 
        p_drv = container_of(drv, struct pcmcia_driver, drv);
 
-       return (p_drv);
+       return p_drv;
 }
 
 
 #ifdef CONFIG_PROC_FS
-static struct proc_dir_entry *proc_pccard = NULL;
+static struct proc_dir_entry *proc_pccard;
 
 static int proc_read_drivers_callback(struct device_driver *driver, void *_m)
 {
@@ -158,7 +158,8 @@ static int adjust_irq(struct pcmcia_socket *s, adjust_t *adj)
 
 #else
 
-static inline int adjust_irq(struct pcmcia_socket *s, adjust_t *adj) {
+static inline int adjust_irq(struct pcmcia_socket *s, adjust_t *adj)
+{
        return 0;
 }
 
@@ -195,7 +196,7 @@ static int pcmcia_adjust_resource_info(adjust_t *adj)
                                begin = adj->resource.memory.Base;
                                end = adj->resource.memory.Base + adj->resource.memory.Size - 1;
                                if (s->resource_ops->add_mem)
-                                       ret =s->resource_ops->add_mem(s, adj->Action, begin, end);
+                                       ret = s->resource_ops->add_mem(s, adj->Action, begin, end);
                        case RES_IO_RANGE:
                                begin = adj->resource.io.BasePort;
                                end = adj->resource.io.BasePort + adj->resource.io.NumPorts - 1;
@@ -215,7 +216,7 @@ static int pcmcia_adjust_resource_info(adjust_t *adj)
        }
        up_read(&pcmcia_socket_list_rwsem);
 
-       return (ret);
+       return ret;
 }
 
 
@@ -490,7 +491,7 @@ static int bind_request(struct pcmcia_socket *s, bind_info_t *bind_info)
        }
 
        spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
-        list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
+       list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
                if (p_dev->func == bind_info->function) {
                        if ((p_dev->dev.driver == &p_drv->drv)) {
                                if (p_dev->cardmgr) {
@@ -558,7 +559,7 @@ rescan:
  err_put:
        pcmcia_put_socket(s);
 
-       return (ret);
+       return ret;
 } /* bind_request */
 
 #ifdef CONFIG_CARDBUS
@@ -655,7 +656,7 @@ static int get_device_info(struct pcmcia_socket *s, bind_info_t *bind_info, int
 
  err_put:
        pcmcia_put_dev(p_dev);
-       return (ret);
+       return ret;
 } /* get_device_info */
 
 
@@ -664,7 +665,7 @@ static int ds_open(struct inode *inode, struct file *file)
     socket_t i = iminor(inode);
     struct pcmcia_socket *s;
     user_info_t *user;
-    static int warning_printed = 0;
+    static int warning_printed;
     int ret = 0;
 
     pr_debug("ds_open(socket %d)\n", i);
@@ -738,12 +739,13 @@ static int ds_release(struct inode *inode, struct file *file)
     s = user->socket;
 
     /* Unlink user data structure */
-    if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+    if ((file->f_flags & O_ACCMODE) != O_RDONLY)
        s->pcmcia_state.busy = 0;
-    }
+
     file->private_data = NULL;
     for (link = &s->user; *link; link = &(*link)->next)
-       if (*link == user) break;
+       if (*link == user)
+               break;
     if (link == NULL)
        goto out;
     *link = user->next;
@@ -774,7 +776,7 @@ static ssize_t ds_read(struct file *file, char __user *buf,
 
     s = user->socket;
     if (s->pcmcia_state.dead)
-        return -EIO;
+       return -EIO;
 
     ret = wait_event_interruptible(s->queue, !queue_empty(user));
     if (ret == 0)
@@ -824,7 +826,7 @@ static u_int ds_poll(struct file *file, poll_table *wait)
 
 /*====================================================================*/
 
-static int ds_ioctl(struct inode * inode, struct file * file,
+static int ds_ioctl(struct inode *inode, struct file *file,
                    u_int cmd, u_long arg)
 {
     struct pcmcia_socket *s;
@@ -842,10 +844,11 @@ static int ds_ioctl(struct inode * inode, struct file * file,
 
     s = user->socket;
     if (s->pcmcia_state.dead)
-        return -EIO;
+       return -EIO;
 
     size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
-    if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL;
+    if (size > sizeof(ds_ioctl_arg_t))
+       return -EINVAL;
 
     /* Permission check */
     if (!(cmd & IOC_OUT) && !capable(CAP_SYS_ADMIN))
@@ -1024,8 +1027,8 @@ static int ds_ioctl(struct inode * inode, struct file * file,
     }
 
     if (cmd & IOC_OUT) {
-        if (__copy_to_user(uarg, (char *)buf, size))
-            err = -EFAULT;
+       if (__copy_to_user(uarg, (char *)buf, size))
+               err = -EFAULT;
     }
 
 free_out:
@@ -1045,7 +1048,8 @@ static const struct file_operations ds_fops = {
        .poll           = ds_poll,
 };
 
-void __init pcmcia_setup_ioctl(void) {
+void __init pcmcia_setup_ioctl(void)
+{
        int i;
 
        /* Set up character device for user mode clients */
@@ -1064,7 +1068,8 @@ void __init pcmcia_setup_ioctl(void) {
 }
 
 
-void __exit pcmcia_cleanup_ioctl(void) {
+void __exit pcmcia_cleanup_ioctl(void)
+{
 #ifdef CONFIG_PROC_FS
        if (proc_pccard) {
                remove_proc_entry("drivers", proc_pccard);
index a8bf8c1b45ede688ab3613eeaf570356d0baa795..d5db95644b64f69cc5dc61fc47f11a7abc21bc71 100644 (file)
@@ -33,7 +33,7 @@
 
 
 /* Access speed for IO windows */
-static int io_speed = 0;
+static int io_speed;
 module_param(io_speed, int, 0444);
 
 
@@ -62,7 +62,8 @@ static int alloc_io_space(struct pcmcia_socket *s, u_int attr,
                               num, align);
                        align = 0;
                } else
-                       while (align && (align < num)) align <<= 1;
+                       while (align && (align < num))
+                               align <<= 1;
        }
        if (*base & ~(align-1)) {
                dev_dbg(&s->dev, "odd IO request: base %#x align %#x\n",
@@ -338,7 +339,7 @@ static int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req)
        struct pcmcia_socket *s = p_dev->socket;
        config_t *c = p_dev->function_config;
 
-       if (!p_dev->_io )
+       if (!p_dev->_io)
                return -EINVAL;
 
        p_dev->_io = 0;
@@ -362,7 +363,7 @@ static int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req)
 static int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req)
 {
        struct pcmcia_socket *s = p_dev->socket;
-       config_t *c= p_dev->function_config;
+       config_t *c = p_dev->function_config;
 
        if (!p_dev->_irq)
                return -EINVAL;
@@ -383,9 +384,8 @@ static int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req)
                s->irq.AssignedIRQ = 0;
        }
 
-       if (req->Handler) {
+       if (req->Handler)
                free_irq(req->AssignedIRQ, p_dev->priv);
-       }
 
 #ifdef CONFIG_PCMCIA_PROBE
        pcmcia_used_irq[req->AssignedIRQ]--;
@@ -656,7 +656,8 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req)
                type = IRQF_SHARED;
        else if (req->Attributes & IRQ_TYPE_DYNAMIC_SHARING)
                type = IRQF_SHARED;
-       else printk(KERN_WARNING "pcmcia: Driver needs updating to support IRQ sharing.\n");
+       else
+               printk(KERN_WARNING "pcmcia: Driver needs updating to support IRQ sharing.\n");
 
 #ifdef CONFIG_PCMCIA_PROBE
 
@@ -788,7 +789,8 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha
 
        /* Allocate system memory window */
        for (w = 0; w < MAX_WIN; w++)
-               if (!(s->state & SOCKET_WIN_REQ(w))) break;
+               if (!(s->state & SOCKET_WIN_REQ(w)))
+                       break;
        if (w == MAX_WIN) {
                dev_dbg(&s->dev, "all windows are used already\n");
                return -EINVAL;
@@ -826,18 +828,19 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha
        s->state |= SOCKET_WIN_REQ(w);
 
        /* Return window handle */
-       if (s->features & SS_CAP_STATIC_MAP) {
+       if (s->features & SS_CAP_STATIC_MAP)
                req->Base = win->static_start;
-       } else {
+       else
                req->Base = win->res->start;
-       }
+
        *wh = w + 1;
 
        return 0;
 } /* pcmcia_request_window */
 EXPORT_SYMBOL(pcmcia_request_window);
 
-void pcmcia_disable_device(struct pcmcia_device *p_dev) {
+void pcmcia_disable_device(struct pcmcia_device *p_dev)
+{
        pcmcia_release_configuration(p_dev);
        pcmcia_release_io(p_dev, &p_dev->io);
        pcmcia_release_irq(p_dev, &p_dev->irq);
@@ -970,7 +973,7 @@ int pcmcia_loop_tuple(struct pcmcia_device *p_dev, cisdata_t code,
 
        return pccard_loop_tuple(p_dev->socket, p_dev->func, code, NULL,
                                 &loop, pcmcia_do_loop_tuple);
-};
+}
 EXPORT_SYMBOL(pcmcia_loop_tuple);
 
 
@@ -1000,7 +1003,7 @@ static int pcmcia_do_get_tuple(struct pcmcia_device *p_dev, tuple_t *tuple,
        } else
                dev_dbg(&p_dev->dev, "do_get_tuple: out of memory\n");
        return 0;
-};
+}
 
 /**
  * pcmcia_get_tuple() - get first tuple from CIS
@@ -1024,7 +1027,7 @@ size_t pcmcia_get_tuple(struct pcmcia_device *p_dev, cisdata_t code,
        pcmcia_loop_tuple(p_dev, code, pcmcia_do_get_tuple, &get);
 
        return get.len;
-};
+}
 EXPORT_SYMBOL(pcmcia_get_tuple);
 
 
@@ -1057,7 +1060,7 @@ static int pcmcia_do_get_mac(struct pcmcia_device *p_dev, tuple_t *tuple,
        for (i = 0; i < 6; i++)
                dev->dev_addr[i] = tuple->TupleData[i+2];
        return 0;
-};
+}
 
 /**
  * pcmcia_get_mac_from_cis() - read out MAC address from CISTPL_FUNCE
@@ -1071,6 +1074,6 @@ static int pcmcia_do_get_mac(struct pcmcia_device *p_dev, tuple_t *tuple,
 int pcmcia_get_mac_from_cis(struct pcmcia_device *p_dev, struct net_device *dev)
 {
        return pcmcia_loop_tuple(p_dev, CISTPL_FUNCE, pcmcia_do_get_mac, dev);
-};
+}
 EXPORT_SYMBOL(pcmcia_get_mac_from_cis);
 
index 84dde7768ad54cd6c8d1fbd0899afd2c38700a95..da346eb7e77eba91474027329794c94ceb8cd2b7 100644 (file)
@@ -214,7 +214,8 @@ static void pxa2xx_configure_sockets(struct device *dev)
        MECR |= MECR_CIT;
 
        /* Set MECR:NOS (Number Of Sockets) */
-       if ((ops->first + ops->nr) > 1 || machine_is_viper())
+       if ((ops->first + ops->nr) > 1 ||
+           machine_is_viper() || machine_is_arcom_zeus())
                MECR |= MECR_NOS;
        else
                MECR &= ~MECR_NOS;
@@ -252,6 +253,7 @@ int pxa2xx_drv_pcmcia_add_one(struct soc_pcmcia_socket *skt)
 
        return soc_pcmcia_add_one(skt);
 }
+EXPORT_SYMBOL(pxa2xx_drv_pcmcia_add_one);
 
 void pxa2xx_drv_pcmcia_ops(struct pcmcia_low_level *ops)
 {
@@ -261,19 +263,19 @@ void pxa2xx_drv_pcmcia_ops(struct pcmcia_low_level *ops)
        ops->frequency_change = pxa2xx_pcmcia_frequency_change;
 #endif
 }
+EXPORT_SYMBOL(pxa2xx_drv_pcmcia_ops);
 
-int __pxa2xx_drv_pcmcia_probe(struct device *dev)
+static int pxa2xx_drv_pcmcia_probe(struct platform_device *dev)
 {
        int i, ret = 0;
        struct pcmcia_low_level *ops;
        struct skt_dev_info *sinfo;
        struct soc_pcmcia_socket *skt;
 
-       if (!dev || !dev->platform_data)
+       ops = (struct pcmcia_low_level *)dev->dev.platform_data;
+       if (!ops)
                return -ENODEV;
 
-       ops = (struct pcmcia_low_level *)dev->platform_data;
-
        pxa2xx_drv_pcmcia_ops(ops);
 
        sinfo = kzalloc(SKT_DEV_INFO_SIZE(ops->nr), GFP_KERNEL);
@@ -308,13 +310,6 @@ int __pxa2xx_drv_pcmcia_probe(struct device *dev)
 
        return ret;
 }
-EXPORT_SYMBOL(__pxa2xx_drv_pcmcia_probe);
-
-
-static int pxa2xx_drv_pcmcia_probe(struct platform_device *dev)
-{
-       return __pxa2xx_drv_pcmcia_probe(&dev->dev);
-}
 
 static int pxa2xx_drv_pcmcia_remove(struct platform_device *dev)
 {
index cb5efaec886f2c807849d2dc467aa71b631c6b1a..bb62ea87b8f9c55158027c1716442d5593ab0772 100644 (file)
@@ -1,6 +1,3 @@
-/* temporary measure */
-extern int __pxa2xx_drv_pcmcia_probe(struct device *);
-
 int pxa2xx_drv_pcmcia_add_one(struct soc_pcmcia_socket *skt);
 void pxa2xx_drv_pcmcia_ops(struct pcmcia_low_level *ops);
 
index 3a8993ed562120f7da811620c770d98f23430831..459a232d66be2caad82155d712cb97c62a7b01a6 100644 (file)
@@ -67,7 +67,7 @@ static int palmtc_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
        if (ret)
                goto err7;
 
-       skt->irq = IRQ_GPIO(GPIO_NR_PALMTC_PCMCIA_READY);
+       skt->socket.pci_irq = IRQ_GPIO(GPIO_NR_PALMTC_PCMCIA_READY);
        return 0;
 
 err7:
index 490749ea677faed056b3db7e8fc2115c8967bba4..d08802fe35f9a993cdd50cec2410543d83aa29ad 100644 (file)
@@ -40,7 +40,7 @@ static struct pcmcia_irqs irqs[] = {
 
 static int sg2_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
-       skt->irq = IRQ_GPIO(SG2_S0_GPIO_READY);
+       skt->socket.pci_irq = IRQ_GPIO(SG2_S0_GPIO_READY);
        return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
index 27be2e154df2a92782dbfafa48598c00dc3cd72f..a51f2077644a5f80cdb4e9688947e046ce42a0e7 100644 (file)
@@ -1,9 +1,8 @@
 /*
- * VIPER PCMCIA support
+ * Viper/Zeus PCMCIA support
  *   Copyright 2004 Arcom Control Systems
  *
  * Maintained by Marc Zyngier <maz@misterjones.org>
- *                           <marc.zyngier@altran.com>
  *
  * Based on:
  *   iPAQ h2200 PCMCIA support
 
 #include <asm/irq.h>
 
-#include <mach/viper.h>
-#include <asm/mach-types.h>
+#include <mach/arcom-pcmcia.h>
 
 #include "soc_common.h"
 #include "pxa2xx_base.h"
 
+static struct platform_device *arcom_pcmcia_dev;
+
 static struct pcmcia_irqs irqs[] = {
-       { 0, gpio_to_irq(VIPER_CF_CD_GPIO),  "PCMCIA_CD" }
+       {
+               .sock   = 0,
+               .str    = "PCMCIA_CD",
+       },
 };
 
+static inline struct arcom_pcmcia_pdata *viper_get_pdata(void)
+{
+       return arcom_pcmcia_dev->dev.platform_data;
+}
+
 static int viper_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
+       struct arcom_pcmcia_pdata *pdata = viper_get_pdata();
        unsigned long flags;
 
-       skt->socket.pci_irq = gpio_to_irq(VIPER_CF_RDY_GPIO);
+       skt->socket.pci_irq = gpio_to_irq(pdata->rdy_gpio);
+       irqs[0].irq = gpio_to_irq(pdata->cd_gpio);
 
-       if (gpio_request(VIPER_CF_CD_GPIO, "CF detect"))
+       if (gpio_request(pdata->cd_gpio, "CF detect"))
                goto err_request_cd;
 
-       if (gpio_request(VIPER_CF_RDY_GPIO, "CF ready"))
+       if (gpio_request(pdata->rdy_gpio, "CF ready"))
                goto err_request_rdy;
 
-       if (gpio_request(VIPER_CF_POWER_GPIO, "CF power"))
+       if (gpio_request(pdata->pwr_gpio, "CF power"))
                goto err_request_pwr;
 
        local_irq_save(flags);
 
-       /* GPIO 82 is the CF power enable line. initially off */
-       if (gpio_direction_output(VIPER_CF_POWER_GPIO, 0) ||
-           gpio_direction_input(VIPER_CF_CD_GPIO) ||
-           gpio_direction_input(VIPER_CF_RDY_GPIO)) {
+       if (gpio_direction_output(pdata->pwr_gpio, 0) ||
+           gpio_direction_input(pdata->cd_gpio) ||
+           gpio_direction_input(pdata->rdy_gpio)) {
                local_irq_restore(flags);
                goto err_dir;
        }
@@ -66,13 +75,13 @@ static int viper_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
        return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
 
 err_dir:
-       gpio_free(VIPER_CF_POWER_GPIO);
+       gpio_free(pdata->pwr_gpio);
 err_request_pwr:
-       gpio_free(VIPER_CF_RDY_GPIO);
+       gpio_free(pdata->rdy_gpio);
 err_request_rdy:
-       gpio_free(VIPER_CF_CD_GPIO);
+       gpio_free(pdata->cd_gpio);
 err_request_cd:
-       printk(KERN_ERR "viper: Failed to setup PCMCIA GPIOs\n");
+       dev_err(&arcom_pcmcia_dev->dev, "Failed to setup PCMCIA GPIOs\n");
        return -1;
 }
 
@@ -81,17 +90,21 @@ err_request_cd:
  */
 static void viper_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
 {
+       struct arcom_pcmcia_pdata *pdata = viper_get_pdata();
+
        soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
-       gpio_free(VIPER_CF_POWER_GPIO);
-       gpio_free(VIPER_CF_RDY_GPIO);
-       gpio_free(VIPER_CF_CD_GPIO);
+       gpio_free(pdata->pwr_gpio);
+       gpio_free(pdata->rdy_gpio);
+       gpio_free(pdata->cd_gpio);
 }
 
 static void viper_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
                                      struct pcmcia_state *state)
 {
-       state->detect = gpio_get_value(VIPER_CF_CD_GPIO) ? 0 : 1;
-       state->ready  = gpio_get_value(VIPER_CF_RDY_GPIO) ? 1 : 0;
+       struct arcom_pcmcia_pdata *pdata = viper_get_pdata();
+
+       state->detect = !gpio_get_value(pdata->cd_gpio);
+       state->ready  = !!gpio_get_value(pdata->rdy_gpio);
        state->bvd1   = 1;
        state->bvd2   = 1;
        state->wrprot = 0;
@@ -102,20 +115,21 @@ static void viper_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
 static int viper_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
                                         const socket_state_t *state)
 {
+       struct arcom_pcmcia_pdata *pdata = viper_get_pdata();
+
        /* Silently ignore Vpp, output enable, speaker enable. */
-       viper_cf_rst(state->flags & SS_RESET);
+       pdata->reset(state->flags & SS_RESET);
 
        /* Apply socket voltage */
        switch (state->Vcc) {
        case 0:
-               gpio_set_value(VIPER_CF_POWER_GPIO, 0);
+               gpio_set_value(pdata->pwr_gpio, 0);
                break;
        case 33:
-               gpio_set_value(VIPER_CF_POWER_GPIO, 1);
+               gpio_set_value(pdata->pwr_gpio, 1);
                break;
        default:
-               printk(KERN_ERR "%s: Unsupported Vcc:%d\n",
-                      __func__, state->Vcc);
+               dev_err(&arcom_pcmcia_dev->dev, "Unsupported Vcc:%d\n", state->Vcc);
                return -1;
        }
 
@@ -130,7 +144,7 @@ static void viper_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
 {
 }
 
-static struct pcmcia_low_level viper_pcmcia_ops __initdata = {
+static struct pcmcia_low_level viper_pcmcia_ops = {
        .owner                  = THIS_MODULE,
        .hw_init                = viper_pcmcia_hw_init,
        .hw_shutdown            = viper_pcmcia_hw_shutdown,
@@ -143,17 +157,25 @@ static struct pcmcia_low_level viper_pcmcia_ops __initdata = {
 
 static struct platform_device *viper_pcmcia_device;
 
-static int __init viper_pcmcia_init(void)
+static int viper_pcmcia_probe(struct platform_device *pdev)
 {
        int ret;
 
-       if (!machine_is_viper())
-               return -ENODEV;
+       /* I can't imagine more than one device, but you never know... */
+       if (arcom_pcmcia_dev)
+               return -EEXIST;
+
+       if (!pdev->dev.platform_data)
+               return -EINVAL;
 
        viper_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
        if (!viper_pcmcia_device)
                return -ENOMEM;
 
+       arcom_pcmcia_dev = pdev;
+
+       viper_pcmcia_device->dev.parent = &pdev->dev;
+
        ret = platform_device_add_data(viper_pcmcia_device,
                                       &viper_pcmcia_ops,
                                       sizeof(viper_pcmcia_ops));
@@ -161,18 +183,49 @@ static int __init viper_pcmcia_init(void)
        if (!ret)
                ret = platform_device_add(viper_pcmcia_device);
 
-       if (ret)
+       if (ret) {
                platform_device_put(viper_pcmcia_device);
+               arcom_pcmcia_dev = NULL;
+       }
 
        return ret;
 }
 
-static void __exit viper_pcmcia_exit(void)
+static int viper_pcmcia_remove(struct platform_device *pdev)
 {
        platform_device_unregister(viper_pcmcia_device);
+       arcom_pcmcia_dev = NULL;
+       return 0;
+}
+
+static struct platform_device_id viper_pcmcia_id_table[] = {
+       { .name = "viper-pcmcia", },
+       { .name = "zeus-pcmcia",  },
+       { },
+};
+
+static struct platform_driver viper_pcmcia_driver = {
+       .probe          = viper_pcmcia_probe,
+       .remove         = viper_pcmcia_remove,
+       .driver         = {
+               .name   = "arcom-pcmcia",
+               .owner  = THIS_MODULE,
+       },
+       .id_table       = viper_pcmcia_id_table,
+};
+
+static int __init viper_pcmcia_init(void)
+{
+       return platform_driver_register(&viper_pcmcia_driver);
+}
+
+static void __exit viper_pcmcia_exit(void)
+{
+       return platform_driver_unregister(&viper_pcmcia_driver);
 }
 
 module_init(viper_pcmcia_init);
 module_exit(viper_pcmcia_exit);
 
+MODULE_DEVICE_TABLE(platform, viper_pcmcia_id_table);
 MODULE_LICENSE("GPL");
index de0e770ce6a30ec404fb9fb1833ce793ab5d55b5..52db17263d8bd9b0b7265040c0a3747ccc7be601 100644 (file)
@@ -126,16 +126,16 @@ static void pcmcia_align(void *align_data, struct resource *res,
        res->start = start;
 
 #ifdef CONFIG_X86
-        if (res->flags & IORESOURCE_IO) {
-                if (start & 0x300) {
-                        start = (start + 0x3ff) & ~0x3ff;
-                        res->start = start;
-                }
-        }
+       if (res->flags & IORESOURCE_IO) {
+               if (start & 0x300) {
+                       start = (start + 0x3ff) & ~0x3ff;
+                       res->start = start;
+               }
+       }
 #endif
 
 #ifdef CONFIG_M68K
-        if (res->flags & IORESOURCE_IO) {
+       if (res->flags & IORESOURCE_IO) {
                if ((res->start + size - 1) >= 1024)
                        res->start = res->end;
        }
index 7039f3cf5b77e5650a99d090d5eabd239ff70ad8..9b0dc433a8c3a6953f223dd6160adbdc22db5b20 100644 (file)
@@ -24,9 +24,9 @@
 #include <linux/timer.h>
 #include <linux/pci.h>
 #include <linux/device.h>
+#include <linux/io.h>
 
 #include <asm/irq.h>
-#include <asm/io.h>
 
 #include <pcmcia/cs_types.h>
 #include <pcmcia/ss.h>
@@ -144,43 +144,44 @@ static int add_interval(struct resource_map *map, u_long base, u_long num)
 
 static int sub_interval(struct resource_map *map, u_long base, u_long num)
 {
-    struct resource_map *p, *q;
-
-    for (p = map; ; p = q) {
-       q = p->next;
-       if (q == map)
-           break;
-       if ((q->base+q->num > base) && (base+num > q->base)) {
-           if (q->base >= base) {
-               if (q->base+q->num <= base+num) {
-                   /* Delete whole block */
-                   p->next = q->next;
-                   kfree(q);
-                   /* don't advance the pointer yet */
-                   q = p;
-               } else {
-                   /* Cut off bit from the front */
-                   q->num = q->base + q->num - base - num;
-                   q->base = base + num;
-               }
-           } else if (q->base+q->num <= base+num) {
-               /* Cut off bit from the end */
-               q->num = base - q->base;
-           } else {
-               /* Split the block into two pieces */
-               p = kmalloc(sizeof(struct resource_map), GFP_KERNEL);
-               if (!p) {
-                   printk(KERN_WARNING "out of memory to update resources\n");
-                   return -ENOMEM;
+       struct resource_map *p, *q;
+
+       for (p = map; ; p = q) {
+               q = p->next;
+               if (q == map)
+                       break;
+               if ((q->base+q->num > base) && (base+num > q->base)) {
+                       if (q->base >= base) {
+                               if (q->base+q->num <= base+num) {
+                                       /* Delete whole block */
+                                       p->next = q->next;
+                                       kfree(q);
+                                       /* don't advance the pointer yet */
+                                       q = p;
+                               } else {
+                                       /* Cut off bit from the front */
+                                       q->num = q->base + q->num - base - num;
+                                       q->base = base + num;
+                               }
+                       } else if (q->base+q->num <= base+num) {
+                               /* Cut off bit from the end */
+                               q->num = base - q->base;
+                       } else {
+                               /* Split the block into two pieces */
+                               p = kmalloc(sizeof(struct resource_map),
+                                       GFP_KERNEL);
+                               if (!p) {
+                                       printk(KERN_WARNING "out of memory to update resources\n");
+                                       return -ENOMEM;
+                               }
+                               p->base = base+num;
+                               p->num = q->base+q->num - p->base;
+                               q->num = base - q->base;
+                               p->next = q->next ; q->next = p;
+                       }
                }
-               p->base = base+num;
-               p->num = q->base+q->num - p->base;
-               q->num = base - q->base;
-               p->next = q->next ; q->next = p;
-           }
        }
-    }
-    return 0;
+       return 0;
 }
 
 /*======================================================================
@@ -194,69 +195,72 @@ static int sub_interval(struct resource_map *map, u_long base, u_long num)
 static void do_io_probe(struct pcmcia_socket *s, unsigned int base,
                        unsigned int num)
 {
-    struct resource *res;
-    struct socket_data *s_data = s->resource_data;
-    unsigned int i, j, bad;
-    int any;
-    u_char *b, hole, most;
-
-    dev_printk(KERN_INFO, &s->dev, "cs: IO port probe %#x-%#x:",
-              base, base+num-1);
-
-    /* First, what does a floating port look like? */
-    b = kzalloc(256, GFP_KERNEL);
-    if (!b) {
-           printk("\n");
-           dev_printk(KERN_ERR, &s->dev,
-                  "do_io_probe: unable to kmalloc 256 bytes");
-            return;
-    }
-    for (i = base, most = 0; i < base+num; i += 8) {
-       res = claim_region(NULL, i, 8, IORESOURCE_IO, "PCMCIA IO probe");
-       if (!res)
-           continue;
-       hole = inb(i);
-       for (j = 1; j < 8; j++)
-           if (inb(i+j) != hole) break;
-       free_region(res);
-       if ((j == 8) && (++b[hole] > b[most]))
-           most = hole;
-       if (b[most] == 127) break;
-    }
-    kfree(b);
-
-    bad = any = 0;
-    for (i = base; i < base+num; i += 8) {
-       res = claim_region(NULL, i, 8, IORESOURCE_IO, "PCMCIA IO probe");
-       if (!res)
-           continue;
-       for (j = 0; j < 8; j++)
-           if (inb(i+j) != most) break;
-       free_region(res);
-       if (j < 8) {
-           if (!any)
-               printk(" excluding");
-           if (!bad)
-               bad = any = i;
-       } else {
-           if (bad) {
-               sub_interval(&s_data->io_db, bad, i-bad);
-               printk(" %#x-%#x", bad, i-1);
-               bad = 0;
-           }
+       struct resource *res;
+       struct socket_data *s_data = s->resource_data;
+       unsigned int i, j, bad;
+       int any;
+       u_char *b, hole, most;
+
+       dev_printk(KERN_INFO, &s->dev, "cs: IO port probe %#x-%#x:",
+               base, base+num-1);
+
+       /* First, what does a floating port look like? */
+       b = kzalloc(256, GFP_KERNEL);
+       if (!b) {
+               printk("\n");
+               dev_printk(KERN_ERR, &s->dev,
+                       "do_io_probe: unable to kmalloc 256 bytes");
+               return;
        }
-    }
-    if (bad) {
-       if ((num > 16) && (bad == base) && (i == base+num)) {
-           printk(" nothing: probe failed.\n");
-           return;
-       } else {
-           sub_interval(&s_data->io_db, bad, i-bad);
-           printk(" %#x-%#x", bad, i-1);
+       for (i = base, most = 0; i < base+num; i += 8) {
+               res = claim_region(NULL, i, 8, IORESOURCE_IO, "PCMCIA ioprobe");
+               if (!res)
+                       continue;
+               hole = inb(i);
+               for (j = 1; j < 8; j++)
+                       if (inb(i+j) != hole)
+                               break;
+               free_region(res);
+               if ((j == 8) && (++b[hole] > b[most]))
+                       most = hole;
+               if (b[most] == 127)
+                       break;
        }
-    }
+       kfree(b);
 
-    printk(any ? "\n" : " clean.\n");
+       bad = any = 0;
+       for (i = base; i < base+num; i += 8) {
+               res = claim_region(NULL, i, 8, IORESOURCE_IO, "PCMCIA ioprobe");
+               if (!res)
+                       continue;
+               for (j = 0; j < 8; j++)
+                       if (inb(i+j) != most)
+                               break;
+               free_region(res);
+               if (j < 8) {
+                       if (!any)
+                               printk(" excluding");
+                       if (!bad)
+                               bad = any = i;
+               } else {
+                       if (bad) {
+                               sub_interval(&s_data->io_db, bad, i-bad);
+                               printk(" %#x-%#x", bad, i-1);
+                               bad = 0;
+                       }
+               }
+       }
+       if (bad) {
+               if ((num > 16) && (bad == base) && (i == base+num)) {
+                       printk(" nothing: probe failed.\n");
+                       return;
+               } else {
+                       sub_interval(&s_data->io_db, bad, i-bad);
+                       printk(" %#x-%#x", bad, i-1);
+               }
+       }
+
+       printk(any ? "\n" : " clean.\n");
 }
 #endif
 
@@ -327,8 +331,9 @@ cis_readable(struct pcmcia_socket *s, unsigned long base, unsigned long size)
        unsigned int info1, info2;
        int ret = 0;
 
-       res1 = claim_region(s, base, size/2, IORESOURCE_MEM, "cs memory probe");
-       res2 = claim_region(s, base + size/2, size/2, IORESOURCE_MEM, "cs memory probe");
+       res1 = claim_region(s, base, size/2, IORESOURCE_MEM, "PCMCIA memprobe");
+       res2 = claim_region(s, base + size/2, size/2, IORESOURCE_MEM,
+                       "PCMCIA memprobe");
 
        if (res1 && res2) {
                ret = readable(s, res1, &info1);
@@ -347,8 +352,9 @@ checksum_match(struct pcmcia_socket *s, unsigned long base, unsigned long size)
        struct resource *res1, *res2;
        int a = -1, b = -1;
 
-       res1 = claim_region(s, base, size/2, IORESOURCE_MEM, "cs memory probe");
-       res2 = claim_region(s, base + size/2, size/2, IORESOURCE_MEM, "cs memory probe");
+       res1 = claim_region(s, base, size/2, IORESOURCE_MEM, "PCMCIA memprobe");
+       res2 = claim_region(s, base + size/2, size/2, IORESOURCE_MEM,
+                       "PCMCIA memprobe");
 
        if (res1 && res2) {
                a = checksum(s, res1);
@@ -371,42 +377,43 @@ checksum_match(struct pcmcia_socket *s, unsigned long base, unsigned long size)
 
 static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s)
 {
-    struct socket_data *s_data = s->resource_data;
-    u_long i, j, bad, fail, step;
-
-    dev_printk(KERN_INFO, &s->dev, "cs: memory probe 0x%06lx-0x%06lx:",
-              base, base+num-1);
-    bad = fail = 0;
-    step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff);
-    /* don't allow too large steps */
-    if (step > 0x800000)
-       step = 0x800000;
-    /* cis_readable wants to map 2x map_size */
-    if (step < 2 * s->map_size)
-       step = 2 * s->map_size;
-    for (i = j = base; i < base+num; i = j + step) {
-       if (!fail) {
-           for (j = i; j < base+num; j += step) {
-               if (cis_readable(s, j, step))
-                   break;
-           }
-           fail = ((i == base) && (j == base+num));
-       }
-       if (fail) {
-           for (j = i; j < base+num; j += 2*step)
-               if (checksum_match(s, j, step) &&
-                   checksum_match(s, j + step, step))
-                   break;
-       }
-       if (i != j) {
-           if (!bad) printk(" excluding");
-           printk(" %#05lx-%#05lx", i, j-1);
-           sub_interval(&s_data->mem_db, i, j-i);
-           bad += j-i;
+       struct socket_data *s_data = s->resource_data;
+       u_long i, j, bad, fail, step;
+
+       dev_printk(KERN_INFO, &s->dev, "cs: memory probe 0x%06lx-0x%06lx:",
+               base, base+num-1);
+       bad = fail = 0;
+       step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff);
+       /* don't allow too large steps */
+       if (step > 0x800000)
+               step = 0x800000;
+       /* cis_readable wants to map 2x map_size */
+       if (step < 2 * s->map_size)
+               step = 2 * s->map_size;
+       for (i = j = base; i < base+num; i = j + step) {
+               if (!fail) {
+                       for (j = i; j < base+num; j += step) {
+                               if (cis_readable(s, j, step))
+                                       break;
+                       }
+                       fail = ((i == base) && (j == base+num));
+               }
+               if (fail) {
+                       for (j = i; j < base+num; j += 2*step)
+                               if (checksum_match(s, j, step) &&
+                                       checksum_match(s, j + step, step))
+                                       break;
+               }
+               if (i != j) {
+                       if (!bad)
+                               printk(" excluding");
+                       printk(" %#05lx-%#05lx", i, j-1);
+                       sub_interval(&s_data->mem_db, i, j-i);
+                       bad += j-i;
+               }
        }
-    }
-    printk(bad ? "\n" : " clean.\n");
-    return (num - bad);
+       printk(bad ? "\n" : " clean.\n");
+       return num - bad;
 }
 
 #ifdef CONFIG_PCMCIA_PROBE
@@ -656,7 +663,7 @@ static struct resource *nonstatic_find_io_region(unsigned long base, int num,
        return res;
 }
 
-static struct resource * nonstatic_find_mem_region(u_long base, u_long num,
+static struct resource *nonstatic_find_mem_region(u_long base, u_long num,
                u_long align, int low, struct pcmcia_socket *s)
 {
        struct resource *res = make_resource(0, num, IORESOURCE_MEM, dev_name(&s->dev));
@@ -794,7 +801,7 @@ static int nonstatic_autoadd_resources(struct pcmcia_socket *s)
                return -EINVAL;
 #endif
 
-       for (i=0; i < PCI_BUS_NUM_RESOURCES; i++) {
+       for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
                res = s->cb_dev->bus->resource[i];
                if (!res)
                        continue;
@@ -908,14 +915,14 @@ static ssize_t show_io_db(struct device *dev,
        for (p = data->io_db.next; p != &data->io_db; p = p->next) {
                if (ret > (PAGE_SIZE - 10))
                        continue;
-               ret += snprintf (&buf[ret], (PAGE_SIZE - ret - 1),
-                                "0x%08lx - 0x%08lx\n",
-                                ((unsigned long) p->base),
-                                ((unsigned long) p->base + p->num - 1));
+               ret += snprintf(&buf[ret], (PAGE_SIZE - ret - 1),
+                               "0x%08lx - 0x%08lx\n",
+                               ((unsigned long) p->base),
+                               ((unsigned long) p->base + p->num - 1));
        }
 
        mutex_unlock(&rsrc_mutex);
-       return (ret);
+       return ret;
 }
 
 static ssize_t store_io_db(struct device *dev,
@@ -927,12 +934,13 @@ static ssize_t store_io_db(struct device *dev,
        unsigned int add = ADD_MANAGED_RESOURCE;
        ssize_t ret = 0;
 
-       ret = sscanf (buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr);
+       ret = sscanf(buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr);
        if (ret != 2) {
-               ret = sscanf (buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr);
+               ret = sscanf(buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr);
                add = REMOVE_MANAGED_RESOURCE;
                if (ret != 2) {
-                       ret = sscanf (buf, "0x%lx - 0x%lx", &start_addr, &end_addr);
+                       ret = sscanf(buf, "0x%lx - 0x%lx", &start_addr,
+                               &end_addr);
                        add = ADD_MANAGED_RESOURCE;
                        if (ret != 2)
                                return -EINVAL;
@@ -963,14 +971,14 @@ static ssize_t show_mem_db(struct device *dev,
        for (p = data->mem_db.next; p != &data->mem_db; p = p->next) {
                if (ret > (PAGE_SIZE - 10))
                        continue;
-               ret += snprintf (&buf[ret], (PAGE_SIZE - ret - 1),
-                                "0x%08lx - 0x%08lx\n",
-                                ((unsigned long) p->base),
-                                ((unsigned long) p->base + p->num - 1));
+               ret += snprintf(&buf[ret], (PAGE_SIZE - ret - 1),
+                               "0x%08lx - 0x%08lx\n",
+                               ((unsigned long) p->base),
+                               ((unsigned long) p->base + p->num - 1));
        }
 
        mutex_unlock(&rsrc_mutex);
-       return (ret);
+       return ret;
 }
 
 static ssize_t store_mem_db(struct device *dev,
@@ -982,12 +990,13 @@ static ssize_t store_mem_db(struct device *dev,
        unsigned int add = ADD_MANAGED_RESOURCE;
        ssize_t ret = 0;
 
-       ret = sscanf (buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr);
+       ret = sscanf(buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr);
        if (ret != 2) {
-               ret = sscanf (buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr);
+               ret = sscanf(buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr);
                add = REMOVE_MANAGED_RESOURCE;
                if (ret != 2) {
-                       ret = sscanf (buf, "0x%lx - 0x%lx", &start_addr, &end_addr);
+                       ret = sscanf(buf, "0x%lx - 0x%lx", &start_addr,
+                               &end_addr);
                        add = ADD_MANAGED_RESOURCE;
                        if (ret != 2)
                                return -EINVAL;
index 78d5aab542f7fdfc8fcf29361cb4b053b9b2bdec..7a456000332a77ada559a04c4c238cdabbc69e6f 100644 (file)
@@ -164,7 +164,7 @@ static ssize_t pccard_store_irq_mask(struct device *dev,
        if (!count)
                return -EINVAL;
 
-       ret = sscanf (buf, "0x%x\n", &mask);
+       ret = sscanf(buf, "0x%x\n", &mask);
 
        if (ret == 1) {
                s->irq_mask &= mask;
@@ -278,7 +278,7 @@ static ssize_t pccard_extract_cis(struct pcmcia_socket *s, char *buf, loff_t off
  free_tuple:
        kfree(tuplebuffer);
 
-       return (ret);
+       return ret;
 }
 
 static ssize_t pccard_show_cis(struct kobject *kobj,
@@ -308,7 +308,7 @@ static ssize_t pccard_show_cis(struct kobject *kobj,
                count = pccard_extract_cis(s, buf, off, count);
        }
 
-       return (count);
+       return count;
 }
 
 static ssize_t pccard_store_cis(struct kobject *kobj,
index 8be4cc447a176a9d1bea0f33b355791dd460b6b1..fe02cfd4b5e905673fddb4f0d9e98391d7379ce2 100644 (file)
@@ -6,7 +6,7 @@
  * Changelog:
  * Aug 2002: Manfred Spraul <manfred@colorfullife.com>
  *     Dynamically adjust the size of the bridge resource
- *     
+ *
  * May 2003: Dominik Brodowski <linux@brodo.de>
  *     Merge pci_socket.c and yenta.c into one file
  */
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/module.h>
+#include <linux/io.h>
 
 #include <pcmcia/cs_types.h>
 #include <pcmcia/ss.h>
 #include <pcmcia/cs.h>
 
-#include <asm/io.h>
-
 #include "yenta_socket.h"
 #include "i82365.h"
 
@@ -55,7 +54,7 @@ static int yenta_probe_cb_irq(struct yenta_socket *socket);
 
 static unsigned int override_bios;
 module_param(override_bios, uint, 0000);
-MODULE_PARM_DESC (override_bios, "yenta ignore bios resource allocation");
+MODULE_PARM_DESC(override_bios, "yenta ignore bios resource allocation");
 
 /*
  * Generate easy-to-use ways of reading a cardbus sockets
@@ -237,24 +236,42 @@ static void yenta_set_power(struct yenta_socket *socket, socket_state_t *state)
                /* i82365SL-DF style */
                if (socket->flags & YENTA_16BIT_POWER_DF) {
                        switch (state->Vcc) {
-                       case 33: reg |= I365_VCC_3V; break;
-                       case 50: reg |= I365_VCC_5V; break;
-                       default: reg = 0; break;
+                       case 33:
+                               reg |= I365_VCC_3V;
+                               break;
+                       case 50:
+                               reg |= I365_VCC_5V;
+                               break;
+                       default:
+                               reg = 0;
+                               break;
                        }
                        switch (state->Vpp) {
                        case 33:
-                       case 50: reg |= I365_VPP1_5V; break;
-                       case 120: reg |= I365_VPP1_12V; break;
+                       case 50:
+                               reg |= I365_VPP1_5V;
+                               break;
+                       case 120:
+                               reg |= I365_VPP1_12V;
+                               break;
                        }
                } else {
                        /* i82365SL-B style */
                        switch (state->Vcc) {
-                       case 50: reg |= I365_VCC_5V; break;
-                       default: reg = 0; break;
+                       case 50:
+                               reg |= I365_VCC_5V;
+                               break;
+                       default:
+                               reg = 0;
+                               break;
                        }
                        switch (state->Vpp) {
-                       case 50: reg |= I365_VPP1_5V | I365_VPP2_5V; break;
-                       case 120: reg |= I365_VPP1_12V | I365_VPP2_12V; break;
+                       case 50:
+                               reg |= I365_VPP1_5V | I365_VPP2_5V;
+                               break;
+                       case 120:
+                               reg |= I365_VPP1_12V | I365_VPP2_12V;
+                               break;
                        }
                }
 
@@ -263,14 +280,26 @@ static void yenta_set_power(struct yenta_socket *socket, socket_state_t *state)
        } else {
                u32 reg = 0;    /* CB_SC_STPCLK? */
                switch (state->Vcc) {
-               case 33: reg = CB_SC_VCC_3V; break;
-               case 50: reg = CB_SC_VCC_5V; break;
-               default: reg = 0; break;
+               case 33:
+                       reg = CB_SC_VCC_3V;
+                       break;
+               case 50:
+                       reg = CB_SC_VCC_5V;
+                       break;
+               default:
+                       reg = 0;
+                       break;
                }
                switch (state->Vpp) {
-               case 33:  reg |= CB_SC_VPP_3V; break;
-               case 50:  reg |= CB_SC_VPP_5V; break;
-               case 120: reg |= CB_SC_VPP_12V; break;
+               case 33:
+                       reg |= CB_SC_VPP_3V;
+                       break;
+               case 50:
+                       reg |= CB_SC_VPP_5V;
+                       break;
+               case 120:
+                       reg |= CB_SC_VPP_12V;
+                       break;
                }
                if (reg != cb_readl(socket, CB_SOCKET_CONTROL))
                        cb_writel(socket, CB_SOCKET_CONTROL, reg);
@@ -314,23 +343,29 @@ static int yenta_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
 
                reg = exca_readb(socket, I365_POWER) & (I365_VCC_MASK|I365_VPP1_MASK);
                reg |= I365_PWR_NORESET;
-               if (state->flags & SS_PWR_AUTO) reg |= I365_PWR_AUTO;
-               if (state->flags & SS_OUTPUT_ENA) reg |= I365_PWR_OUT;
+               if (state->flags & SS_PWR_AUTO)
+                       reg |= I365_PWR_AUTO;
+               if (state->flags & SS_OUTPUT_ENA)
+                       reg |= I365_PWR_OUT;
                if (exca_readb(socket, I365_POWER) != reg)
                        exca_writeb(socket, I365_POWER, reg);
 
                /* CSC interrupt: no ISA irq for CSC */
                reg = I365_CSC_DETECT;
                if (state->flags & SS_IOCARD) {
-                       if (state->csc_mask & SS_STSCHG) reg |= I365_CSC_STSCHG;
+                       if (state->csc_mask & SS_STSCHG)
+                               reg |= I365_CSC_STSCHG;
                } else {
-                       if (state->csc_mask & SS_BATDEAD) reg |= I365_CSC_BVD1;
-                       if (state->csc_mask & SS_BATWARN) reg |= I365_CSC_BVD2;
-                       if (state->csc_mask & SS_READY) reg |= I365_CSC_READY;
+                       if (state->csc_mask & SS_BATDEAD)
+                               reg |= I365_CSC_BVD1;
+                       if (state->csc_mask & SS_BATWARN)
+                               reg |= I365_CSC_BVD2;
+                       if (state->csc_mask & SS_READY)
+                               reg |= I365_CSC_READY;
                }
                exca_writeb(socket, I365_CSCINT, reg);
                exca_readb(socket, I365_CSC);
-               if(sock->zoom_video)
+               if (sock->zoom_video)
                        sock->zoom_video(sock, state->flags & SS_ZVCARD);
        }
        config_writew(socket, CB_BRIDGE_CONTROL, bridge);
@@ -368,9 +403,12 @@ static int yenta_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io
        exca_writew(socket, I365_IO(map)+I365_W_STOP, io->stop);
 
        ioctl = exca_readb(socket, I365_IOCTL) & ~I365_IOCTL_MASK(map);
-       if (io->flags & MAP_0WS) ioctl |= I365_IOCTL_0WS(map);
-       if (io->flags & MAP_16BIT) ioctl |= I365_IOCTL_16BIT(map);
-       if (io->flags & MAP_AUTOSZ) ioctl |= I365_IOCTL_IOCS16(map);
+       if (io->flags & MAP_0WS)
+               ioctl |= I365_IOCTL_0WS(map);
+       if (io->flags & MAP_16BIT)
+               ioctl |= I365_IOCTL_16BIT(map);
+       if (io->flags & MAP_AUTOSZ)
+               ioctl |= I365_IOCTL_IOCS16(map);
        exca_writeb(socket, I365_IOCTL, ioctl);
 
        if (io->flags & MAP_ACTIVE)
@@ -416,10 +454,17 @@ static int yenta_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *
 
        word = (stop >> 12) & 0x0fff;
        switch (to_cycles(mem->speed)) {
-               case 0: break;
-               case 1:  word |= I365_MEM_WS0; break;
-               case 2:  word |= I365_MEM_WS1; break;
-               default: word |= I365_MEM_WS1 | I365_MEM_WS0; break;
+       case 0:
+               break;
+       case 1:
+               word |= I365_MEM_WS0;
+               break;
+       case 2:
+               word |= I365_MEM_WS1;
+               break;
+       default:
+               word |= I365_MEM_WS1 | I365_MEM_WS0;
+               break;
        }
        exca_writew(socket, I365_MEM(map) + I365_W_STOP, word);
 
@@ -547,9 +592,9 @@ static int yenta_sock_suspend(struct pcmcia_socket *sock)
  * max 4 MB, min 16 kB. We try very hard to not get below
  * the "ACC" values, though.
  */
-#define BRIDGE_MEM_MAX 4*1024*1024
-#define BRIDGE_MEM_ACC 128*1024
-#define BRIDGE_MEM_MIN 16*1024
+#define BRIDGE_MEM_MAX (4*1024*1024)
+#define BRIDGE_MEM_ACC (128*1024)
+#define BRIDGE_MEM_MIN (16*1024)
 
 #define BRIDGE_IO_MAX 512
 #define BRIDGE_IO_ACC 256
@@ -574,7 +619,7 @@ static int yenta_search_one_res(struct resource *root, struct resource *res,
                int i;
                size = BRIDGE_MEM_MAX;
                if (size > avail/8) {
-                       size=(avail+1)/8;
+                       size = (avail+1)/8;
                        /* round size down to next power of 2 */
                        i = 0;
                        while ((size /= 2) != 0)
@@ -590,7 +635,7 @@ static int yenta_search_one_res(struct resource *root, struct resource *res,
 
        do {
                if (allocate_resource(root, res, size, start, end, align,
-                                     NULL, NULL)==0) {
+                                     NULL, NULL) == 0) {
                        return 1;
                }
                size = size/2;
@@ -605,8 +650,8 @@ static int yenta_search_res(struct yenta_socket *socket, struct resource *res,
                            u32 min)
 {
        int i;
-       for (i=0; i<PCI_BUS_NUM_RESOURCES; i++) {
-               struct resource * root = socket->dev->bus->resource[i];
+       for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
+               struct resource *root = socket->dev->bus->resource[i];
                if (!root)
                        continue;
 
@@ -704,7 +749,7 @@ static void yenta_allocate_resources(struct yenta_socket *socket)
 static void yenta_free_resources(struct yenta_socket *socket)
 {
        int i;
-       for (i=0;i<4;i++) {
+       for (i = 0; i < 4; i++) {
                struct resource *res;
                res = socket->dev->resource + PCI_BRIDGE_RESOURCES + i;
                if (res->start != 0 && res->end != 0)
@@ -726,7 +771,7 @@ static void __devexit yenta_close(struct pci_dev *dev)
 
        /* we don't want a dying socket registered */
        pcmcia_unregister_socket(&sock->socket);
-       
+
        /* Disable all events so we don't die in an IRQ storm */
        cb_writel(sock, CB_SOCKET_MASK, 0x0);
        exca_writeb(sock, I365_CSCINT, 0);
@@ -898,7 +943,7 @@ static irqreturn_t yenta_probe_handler(int irq, void *dev_id)
 {
        struct yenta_socket *socket = (struct yenta_socket *) dev_id;
        u8 csc;
-        u32 cb_event;
+       u32 cb_event;
 
        /* Clear interrupt status for the event */
        cb_event = cb_readl(socket, CB_SOCKET_EVENT);
@@ -1019,7 +1064,7 @@ static void yenta_fixup_parent_bridge(struct pci_bus *cardbus_bridge)
 {
        struct list_head *tmp;
        unsigned char upper_limit;
-       /*
+       /*
         * We only check and fix the parent bridge: All systems which need
         * this fixup that have been reviewed are laptops and the only bridge
         * which needed fixing was the parent bridge of the CardBus bridge:
@@ -1038,7 +1083,7 @@ static void yenta_fixup_parent_bridge(struct pci_bus *cardbus_bridge)
 
        /* check the bus ranges of all silbling bridges to prevent overlap */
        list_for_each(tmp, &bridge_to_fix->parent->children) {
-               struct pci_bus * silbling = pci_bus_b(tmp);
+               struct pci_bus *silbling = pci_bus_b(tmp);
                /*
                 * If the silbling has a higher secondary bus number
                 * and it's secondary is equal or smaller than our
@@ -1083,7 +1128,7 @@ static void yenta_fixup_parent_bridge(struct pci_bus *cardbus_bridge)
  * interrupt, and that we can map the cardbus area. Fill in the
  * socket information structure..
  */
-static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_id *id)
+static int __devinit yenta_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        struct yenta_socket *socket;
        int ret;
@@ -1302,7 +1347,7 @@ static struct dev_pm_ops yenta_pm_ops = {
 #define YENTA_PM_OPS   NULL
 #endif
 
-#define CB_ID(vend,dev,type)                           \
+#define CB_ID(vend, dev, type)                         \
        {                                               \
                .vendor         = vend,                 \
                .device         = dev,                  \
@@ -1313,7 +1358,7 @@ static struct dev_pm_ops yenta_pm_ops = {
                .driver_data    = CARDBUS_TYPE_##type,  \
        }
 
-static struct pci_device_id yenta_table [] = {
+static struct pci_device_id yenta_table[] = {
        CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1031, TI),
 
        /*
@@ -1403,13 +1448,13 @@ static struct pci_driver yenta_cardbus_driver = {
 
 static int __init yenta_socket_init(void)
 {
-       return pci_register_driver (&yenta_cardbus_driver);
+       return pci_register_driver(&yenta_cardbus_driver);
 }
 
 
-static void __exit yenta_socket_exit (void)
+static void __exit yenta_socket_exit(void)
 {
-       pci_unregister_driver (&yenta_cardbus_driver);
+       pci_unregister_driver(&yenta_cardbus_driver);
 }
 
 
index e8b278f71781a2c3590fd6029f6a1daa34ccfe0f..6a84a8eb8d7ac711ae0fa46b87ea8d63d7be80ff 100644 (file)
@@ -303,7 +303,6 @@ static const u8 mbc_irq_handlers[] = {
 static int __devinit pcf50633_mbc_probe(struct platform_device *pdev)
 {
        struct pcf50633_mbc *mbc;
-       struct pcf50633_subdev_pdata *pdata = pdev->dev.platform_data;
        int ret;
        int i;
        u8 mbcs1;
@@ -313,7 +312,7 @@ static int __devinit pcf50633_mbc_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        platform_set_drvdata(pdev, mbc);
-       mbc->pcf = pdata->pcf;
+       mbc->pcf = dev_to_pcf50633(pdev->dev.parent);
 
        /* Set up IRQ handlers */
        for (i = 0; i < ARRAY_SIZE(mbc_irq_handlers); i++)
index 28b0299c0043694cf19bed7d3bc97b8289db2873..ad4f071e12870a26cbf6d7fb9415590947ba1833 100644 (file)
@@ -184,8 +184,9 @@ static ssize_t charger_state_show(struct device *dev,
 
 static DEVICE_ATTR(charger_state, 0444, charger_state_show, NULL);
 
-static void wm8350_charger_handler(struct wm8350 *wm8350, int irq, void *data)
+static irqreturn_t wm8350_charger_handler(int irq, void *data)
 {
+       struct wm8350 *wm8350 = data;
        struct wm8350_power *power = &wm8350->power;
        struct wm8350_charger_policy *policy = power->policy;
 
@@ -238,6 +239,8 @@ static void wm8350_charger_handler(struct wm8350 *wm8350, int irq, void *data)
        default:
                dev_err(wm8350->dev, "Unknown interrupt %d\n", irq);
        }
+
+       return IRQ_HANDLED;
 }
 
 /*********************************************************************
@@ -387,73 +390,55 @@ static void wm8350_init_charger(struct wm8350 *wm8350)
 {
        /* register our interest in charger events */
        wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT,
-                           wm8350_charger_handler, NULL);
-       wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT);
+                           wm8350_charger_handler, 0, "Battery hot", wm8350);
        wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD,
-                           wm8350_charger_handler, NULL);
-       wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD);
+                           wm8350_charger_handler, 0, "Battery cold", wm8350);
        wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL,
-                           wm8350_charger_handler, NULL);
-       wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL);
+                           wm8350_charger_handler, 0, "Battery fail", wm8350);
        wm8350_register_irq(wm8350, WM8350_IRQ_CHG_TO,
-                           wm8350_charger_handler, NULL);
-       wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_TO);
+                           wm8350_charger_handler, 0,
+                           "Charger timeout", wm8350);
        wm8350_register_irq(wm8350, WM8350_IRQ_CHG_END,
-                           wm8350_charger_handler, NULL);
-       wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_END);
+                           wm8350_charger_handler, 0,
+                           "Charge end", wm8350);
        wm8350_register_irq(wm8350, WM8350_IRQ_CHG_START,
-                           wm8350_charger_handler, NULL);
-       wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_START);
+                           wm8350_charger_handler, 0,
+                           "Charge start", wm8350);
        wm8350_register_irq(wm8350, WM8350_IRQ_CHG_FAST_RDY,
-                           wm8350_charger_handler, NULL);
-       wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_FAST_RDY);
+                           wm8350_charger_handler, 0,
+                           "Fast charge ready", wm8350);
        wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9,
-                           wm8350_charger_handler, NULL);
-       wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9);
+                           wm8350_charger_handler, 0,
+                           "Battery <3.9V", wm8350);
        wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1,
-                           wm8350_charger_handler, NULL);
-       wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1);
+                           wm8350_charger_handler, 0,
+                           "Battery <3.1V", wm8350);
        wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85,
-                           wm8350_charger_handler, NULL);
-       wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85);
+                           wm8350_charger_handler, 0,
+                           "Battery <2.85V", wm8350);
 
        /* and supply change events */
        wm8350_register_irq(wm8350, WM8350_IRQ_EXT_USB_FB,
-                           wm8350_charger_handler, NULL);
-       wm8350_unmask_irq(wm8350, WM8350_IRQ_EXT_USB_FB);
+                           wm8350_charger_handler, 0, "USB", wm8350);
        wm8350_register_irq(wm8350, WM8350_IRQ_EXT_WALL_FB,
-                           wm8350_charger_handler, NULL);
-       wm8350_unmask_irq(wm8350, WM8350_IRQ_EXT_WALL_FB);
+                           wm8350_charger_handler, 0, "Wall", wm8350);
        wm8350_register_irq(wm8350, WM8350_IRQ_EXT_BAT_FB,
-                           wm8350_charger_handler, NULL);
-       wm8350_unmask_irq(wm8350, WM8350_IRQ_EXT_BAT_FB);
+                           wm8350_charger_handler, 0, "Battery", wm8350);
 }
 
 static void free_charger_irq(struct wm8350 *wm8350)
 {
-       wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT);
        wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT);
-       wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD);
        wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD);
-       wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL);
        wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL);
-       wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_TO);
        wm8350_free_irq(wm8350, WM8350_IRQ_CHG_TO);
-       wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_END);
        wm8350_free_irq(wm8350, WM8350_IRQ_CHG_END);
-       wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_START);
        wm8350_free_irq(wm8350, WM8350_IRQ_CHG_START);
-       wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9);
        wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9);
-       wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1);
        wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1);
-       wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85);
        wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85);
-       wm8350_mask_irq(wm8350, WM8350_IRQ_EXT_USB_FB);
        wm8350_free_irq(wm8350, WM8350_IRQ_EXT_USB_FB);
-       wm8350_mask_irq(wm8350, WM8350_IRQ_EXT_WALL_FB);
        wm8350_free_irq(wm8350, WM8350_IRQ_EXT_WALL_FB);
-       wm8350_mask_irq(wm8350, WM8350_IRQ_EXT_BAT_FB);
        wm8350_free_irq(wm8350, WM8350_IRQ_EXT_BAT_FB);
 }
 
index bcbb161bde0b706c6083f2bc6205180dc0fcea09..7cfdd65bebb4185efb9552d2be4afa9f3611385f 100644 (file)
@@ -70,7 +70,7 @@ config REGULATOR_MAX1586
          for PXA27x chips to control VCC_CORE and VCC_USIM voltages.
 
 config REGULATOR_TWL4030
-       bool "TI TWL4030/TWL5030/TPS695x0 PMIC"
+       bool "TI TWL4030/TWL5030/TWL6030/TPS695x0 PMIC"
        depends on TWL4030_CORE
        help
          This driver supports the voltage regulators provided by
index 4257a868377803b0359f49af864fb3b4ad014d57..9ae3cc44e668d97dacaecee4489322de94f8d56e 100644 (file)
@@ -11,7 +11,7 @@ obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o
 obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o
 obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
 obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o
-obj-$(CONFIG_REGULATOR_TWL4030) += twl4030-regulator.o
+obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o
 obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o
 obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o
 obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o
index 0803ffe6236d03526c66df8fbf6e9bdba0150b7f..c8f41dc05b76f772aa58d57d85c0ab231672a87f 100644 (file)
@@ -314,13 +314,15 @@ static int __devinit pcf50633_regulator_probe(struct platform_device *pdev)
        struct pcf50633 *pcf;
 
        /* Already set by core driver */
-       pcf = platform_get_drvdata(pdev);
+       pcf = dev_to_pcf50633(pdev->dev.parent);
 
        rdev = regulator_register(&regulators[pdev->id], &pdev->dev,
                                  pdev->dev.platform_data, pcf);
        if (IS_ERR(rdev))
                return PTR_ERR(rdev);
 
+       platform_set_drvdata(pdev, rdev);
+
        if (pcf->pdata->regulator_registered)
                pcf->pdata->regulator_registered(pcf, pdev->id);
 
@@ -331,6 +333,7 @@ static int __devexit pcf50633_regulator_remove(struct platform_device *pdev)
 {
        struct regulator_dev *rdev = platform_get_drvdata(pdev);
 
+       platform_set_drvdata(pdev, NULL);
        regulator_unregister(rdev);
 
        return 0;
diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c
new file mode 100644 (file)
index 0000000..7ea1c3a
--- /dev/null
@@ -0,0 +1,579 @@
+/*
+ * twl-regulator.c -- support regulators in twl4030/twl6030 family chips
+ *
+ * Copyright (C) 2008 David Brownell
+ *
+ * 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/module.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/i2c/twl.h>
+
+
+/*
+ * The TWL4030/TW5030/TPS659x0/TWL6030 family chips include power management, a
+ * USB OTG transceiver, an RTC, ADC, PWM, and lots more.  Some versions
+ * include an audio codec, battery charger, and more voltage regulators.
+ * These chips are often used in OMAP-based systems.
+ *
+ * This driver implements software-based resource control for various
+ * voltage regulators.  This is usually augmented with state machine
+ * based control.
+ */
+
+struct twlreg_info {
+       /* start of regulator's PM_RECEIVER control register bank */
+       u8                      base;
+
+       /* twl resource ID, for resource control state machine */
+       u8                      id;
+
+       /* voltage in mV = table[VSEL]; table_len must be a power-of-two */
+       u8                      table_len;
+       const u16               *table;
+
+       /* chip constraints on regulator behavior */
+       u16                     min_mV;
+
+       /* used by regulator core */
+       struct regulator_desc   desc;
+};
+
+
+/* LDO control registers ... offset is from the base of its register bank.
+ * The first three registers of all power resource banks help hardware to
+ * manage the various resource groups.
+ */
+/* Common offset in TWL4030/6030 */
+#define VREG_GRP               0
+/* TWL4030 register offsets */
+#define VREG_TYPE              1
+#define VREG_REMAP             2
+#define VREG_DEDICATED         3       /* LDO control */
+/* TWL6030 register offsets */
+#define VREG_TRANS             1
+#define VREG_STATE             2
+#define VREG_VOLTAGE           3
+/* TWL6030 Misc register offsets */
+#define VREG_BC_ALL            1
+#define VREG_BC_REF            2
+#define VREG_BC_PROC           3
+#define VREG_BC_CLK_RST                4
+
+static inline int
+twlreg_read(struct twlreg_info *info, unsigned slave_subgp, unsigned offset)
+{
+       u8 value;
+       int status;
+
+       status = twl_i2c_read_u8(slave_subgp,
+                       &value, info->base + offset);
+       return (status < 0) ? status : value;
+}
+
+static inline int
+twlreg_write(struct twlreg_info *info, unsigned slave_subgp, unsigned offset,
+                                                u8 value)
+{
+       return twl_i2c_write_u8(slave_subgp,
+                       value, info->base + offset);
+}
+
+/*----------------------------------------------------------------------*/
+
+/* generic power resource operations, which work on all regulators */
+
+static int twlreg_grp(struct regulator_dev *rdev)
+{
+       return twlreg_read(rdev_get_drvdata(rdev), TWL_MODULE_PM_RECEIVER,
+                                                                VREG_GRP);
+}
+
+/*
+ * Enable/disable regulators by joining/leaving the P1 (processor) group.
+ * We assume nobody else is updating the DEV_GRP registers.
+ */
+/* definition for 4030 family */
+#define P3_GRP_4030    BIT(7)          /* "peripherals" */
+#define P2_GRP_4030    BIT(6)          /* secondary processor, modem, etc */
+#define P1_GRP_4030    BIT(5)          /* CPU/Linux */
+/* definition for 6030 family */
+#define P3_GRP_6030    BIT(2)          /* secondary processor, modem, etc */
+#define P2_GRP_6030    BIT(1)          /* "peripherals" */
+#define P1_GRP_6030    BIT(0)          /* CPU/Linux */
+
+static int twlreg_is_enabled(struct regulator_dev *rdev)
+{
+       int     state = twlreg_grp(rdev);
+
+       if (state < 0)
+               return state;
+
+       if (twl_class_is_4030())
+               state &= P1_GRP_4030;
+       else
+               state &= P1_GRP_6030;
+       return state;
+}
+
+static int twlreg_enable(struct regulator_dev *rdev)
+{
+       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+       int                     grp;
+
+       grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP);
+       if (grp < 0)
+               return grp;
+
+       if (twl_class_is_4030())
+               grp |= P1_GRP_4030;
+       else
+               grp |= P1_GRP_6030;
+
+       return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp);
+}
+
+static int twlreg_disable(struct regulator_dev *rdev)
+{
+       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+       int                     grp;
+
+       grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP);
+       if (grp < 0)
+               return grp;
+
+       if (twl_class_is_4030())
+               grp &= ~P1_GRP_4030;
+       else
+               grp &= ~P1_GRP_6030;
+
+       return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp);
+}
+
+static int twlreg_get_status(struct regulator_dev *rdev)
+{
+       int     state = twlreg_grp(rdev);
+
+       if (twl_class_is_6030())
+               return 0; /* FIXME return for 6030 regulator */
+
+       if (state < 0)
+               return state;
+       state &= 0x0f;
+
+       /* assume state != WARM_RESET; we'd not be running...  */
+       if (!state)
+               return REGULATOR_STATUS_OFF;
+       return (state & BIT(3))
+               ? REGULATOR_STATUS_NORMAL
+               : REGULATOR_STATUS_STANDBY;
+}
+
+static int twlreg_set_mode(struct regulator_dev *rdev, unsigned mode)
+{
+       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+       unsigned                message;
+       int                     status;
+
+       if (twl_class_is_6030())
+               return 0; /* FIXME return for 6030 regulator */
+
+       /* We can only set the mode through state machine commands... */
+       switch (mode) {
+       case REGULATOR_MODE_NORMAL:
+               message = MSG_SINGULAR(DEV_GRP_P1, info->id, RES_STATE_ACTIVE);
+               break;
+       case REGULATOR_MODE_STANDBY:
+               message = MSG_SINGULAR(DEV_GRP_P1, info->id, RES_STATE_SLEEP);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Ensure the resource is associated with some group */
+       status = twlreg_grp(rdev);
+       if (status < 0)
+               return status;
+       if (!(status & (P3_GRP_4030 | P2_GRP_4030 | P1_GRP_4030)))
+               return -EACCES;
+
+       status = twl_i2c_write_u8(TWL_MODULE_PM_MASTER,
+                       message >> 8, 0x15 /* PB_WORD_MSB */ );
+       if (status >= 0)
+               return status;
+
+       return twl_i2c_write_u8(TWL_MODULE_PM_MASTER,
+                       message, 0x16 /* PB_WORD_LSB */ );
+}
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * Support for adjustable-voltage LDOs uses a four bit (or less) voltage
+ * select field in its control register.   We use tables indexed by VSEL
+ * to record voltages in milliVolts.  (Accuracy is about three percent.)
+ *
+ * Note that VSEL values for VAUX2 changed in twl5030 and newer silicon;
+ * currently handled by listing two slightly different VAUX2 regulators,
+ * only one of which will be configured.
+ *
+ * VSEL values documented as "TI cannot support these values" are flagged
+ * in these tables as UNSUP() values; we normally won't assign them.
+ *
+ * VAUX3 at 3V is incorrectly listed in some TI manuals as unsupported.
+ * TI are revising the twl5030/tps659x0 specs to support that 3.0V setting.
+ */
+#ifdef CONFIG_TWL4030_ALLOW_UNSUPPORTED
+#define UNSUP_MASK     0x0000
+#else
+#define UNSUP_MASK     0x8000
+#endif
+
+#define UNSUP(x)       (UNSUP_MASK | (x))
+#define IS_UNSUP(x)    (UNSUP_MASK & (x))
+#define LDO_MV(x)      (~UNSUP_MASK & (x))
+
+
+static const u16 VAUX1_VSEL_table[] = {
+       UNSUP(1500), UNSUP(1800), 2500, 2800,
+       3000, 3000, 3000, 3000,
+};
+static const u16 VAUX2_4030_VSEL_table[] = {
+       UNSUP(1000), UNSUP(1000), UNSUP(1200), 1300,
+       1500, 1800, UNSUP(1850), 2500,
+       UNSUP(2600), 2800, UNSUP(2850), UNSUP(3000),
+       UNSUP(3150), UNSUP(3150), UNSUP(3150), UNSUP(3150),
+};
+static const u16 VAUX2_VSEL_table[] = {
+       1700, 1700, 1900, 1300,
+       1500, 1800, 2000, 2500,
+       2100, 2800, 2200, 2300,
+       2400, 2400, 2400, 2400,
+};
+static const u16 VAUX3_VSEL_table[] = {
+       1500, 1800, 2500, 2800,
+       3000, 3000, 3000, 3000,
+};
+static const u16 VAUX4_VSEL_table[] = {
+       700, 1000, 1200, UNSUP(1300),
+       1500, 1800, UNSUP(1850), 2500,
+       UNSUP(2600), 2800, UNSUP(2850), UNSUP(3000),
+       UNSUP(3150), UNSUP(3150), UNSUP(3150), UNSUP(3150),
+};
+static const u16 VMMC1_VSEL_table[] = {
+       1850, 2850, 3000, 3150,
+};
+static const u16 VMMC2_VSEL_table[] = {
+       UNSUP(1000), UNSUP(1000), UNSUP(1200), UNSUP(1300),
+       UNSUP(1500), UNSUP(1800), 1850, UNSUP(2500),
+       2600, 2800, 2850, 3000,
+       3150, 3150, 3150, 3150,
+};
+static const u16 VPLL1_VSEL_table[] = {
+       1000, 1200, 1300, 1800,
+       UNSUP(2800), UNSUP(3000), UNSUP(3000), UNSUP(3000),
+};
+static const u16 VPLL2_VSEL_table[] = {
+       700, 1000, 1200, 1300,
+       UNSUP(1500), 1800, UNSUP(1850), UNSUP(2500),
+       UNSUP(2600), UNSUP(2800), UNSUP(2850), UNSUP(3000),
+       UNSUP(3150), UNSUP(3150), UNSUP(3150), UNSUP(3150),
+};
+static const u16 VSIM_VSEL_table[] = {
+       UNSUP(1000), UNSUP(1200), UNSUP(1300), 1800,
+       2800, 3000, 3000, 3000,
+};
+static const u16 VDAC_VSEL_table[] = {
+       1200, 1300, 1800, 1800,
+};
+static const u16 VAUX1_6030_VSEL_table[] = {
+       1000, 1300, 1800, 2500,
+       2800, 2900, 3000, 3000,
+};
+static const u16 VAUX2_6030_VSEL_table[] = {
+       1200, 1800, 2500, 2750,
+       2800, 2800, 2800, 2800,
+};
+static const u16 VAUX3_6030_VSEL_table[] = {
+       1000, 1200, 1300, 1800,
+       2500, 2800, 3000, 3000,
+};
+static const u16 VMMC_VSEL_table[] = {
+       1200, 1800, 2800, 2900,
+       3000, 3000, 3000, 3000,
+};
+static const u16 VPP_VSEL_table[] = {
+       1800, 1900, 2000, 2100,
+       2200, 2300, 2400, 2500,
+};
+static const u16 VUSIM_VSEL_table[] = {
+       1200, 1800, 2500, 2900,
+};
+
+static int twlldo_list_voltage(struct regulator_dev *rdev, unsigned index)
+{
+       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+       int                     mV = info->table[index];
+
+       return IS_UNSUP(mV) ? 0 : (LDO_MV(mV) * 1000);
+}
+
+static int
+twlldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
+{
+       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+       int                     vsel;
+
+       for (vsel = 0; vsel < info->table_len; vsel++) {
+               int mV = info->table[vsel];
+               int uV;
+
+               if (IS_UNSUP(mV))
+                       continue;
+               uV = LDO_MV(mV) * 1000;
+
+               /* REVISIT for VAUX2, first match may not be best/lowest */
+
+               /* use the first in-range value */
+               if (min_uV <= uV && uV <= max_uV)
+                       return twlreg_write(info, TWL_MODULE_PM_RECEIVER,
+                                                       VREG_VOLTAGE, vsel);
+       }
+
+       return -EDOM;
+}
+
+static int twlldo_get_voltage(struct regulator_dev *rdev)
+{
+       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+       int             vsel = twlreg_read(info, TWL_MODULE_PM_RECEIVER,
+                                                               VREG_VOLTAGE);
+
+       if (vsel < 0)
+               return vsel;
+
+       vsel &= info->table_len - 1;
+       return LDO_MV(info->table[vsel]) * 1000;
+}
+
+static struct regulator_ops twlldo_ops = {
+       .list_voltage   = twlldo_list_voltage,
+
+       .set_voltage    = twlldo_set_voltage,
+       .get_voltage    = twlldo_get_voltage,
+
+       .enable         = twlreg_enable,
+       .disable        = twlreg_disable,
+       .is_enabled     = twlreg_is_enabled,
+
+       .set_mode       = twlreg_set_mode,
+
+       .get_status     = twlreg_get_status,
+};
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * Fixed voltage LDOs don't have a VSEL field to update.
+ */
+static int twlfixed_list_voltage(struct regulator_dev *rdev, unsigned index)
+{
+       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+
+       return info->min_mV * 1000;
+}
+
+static int twlfixed_get_voltage(struct regulator_dev *rdev)
+{
+       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+
+       return info->min_mV * 1000;
+}
+
+static struct regulator_ops twlfixed_ops = {
+       .list_voltage   = twlfixed_list_voltage,
+
+       .get_voltage    = twlfixed_get_voltage,
+
+       .enable         = twlreg_enable,
+       .disable        = twlreg_disable,
+       .is_enabled     = twlreg_is_enabled,
+
+       .set_mode       = twlreg_set_mode,
+
+       .get_status     = twlreg_get_status,
+};
+
+/*----------------------------------------------------------------------*/
+
+#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) { \
+       .base = offset, \
+       .id = num, \
+       .table_len = ARRAY_SIZE(label##_VSEL_table), \
+       .table = label##_VSEL_table, \
+       .desc = { \
+               .name = #label, \
+               .id = family##_REG_##label, \
+               .n_voltages = ARRAY_SIZE(label##_VSEL_table), \
+               .ops = &twlldo_ops, \
+               .type = REGULATOR_VOLTAGE, \
+               .owner = THIS_MODULE, \
+               }, \
+       }
+
+#define TWL_FIXED_LDO(label, offset, mVolts, num, family) { \
+       .base = offset, \
+       .id = num, \
+       .min_mV = mVolts, \
+       .desc = { \
+               .name = #label, \
+               .id = family##_REG_##label, \
+               .n_voltages = 1, \
+               .ops = &twlfixed_ops, \
+               .type = REGULATOR_VOLTAGE, \
+               .owner = THIS_MODULE, \
+               }, \
+       }
+
+/*
+ * We list regulators here if systems need some level of
+ * 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),
+       /* 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)
+};
+
+static int twlreg_probe(struct platform_device *pdev)
+{
+       int                             i;
+       struct twlreg_info              *info;
+       struct regulator_init_data      *initdata;
+       struct regulation_constraints   *c;
+       struct regulator_dev            *rdev;
+
+       for (i = 0, info = NULL; i < ARRAY_SIZE(twl_regs); i++) {
+               if (twl_regs[i].desc.id != pdev->id)
+                       continue;
+               info = twl_regs + i;
+               break;
+       }
+       if (!info)
+               return -ENODEV;
+
+       initdata = pdev->dev.platform_data;
+       if (!initdata)
+               return -EINVAL;
+
+       /* Constrain board-specific capabilities according to what
+        * this driver and the chip itself can actually do.
+        */
+       c = &initdata->constraints;
+       c->valid_modes_mask &= REGULATOR_MODE_NORMAL | REGULATOR_MODE_STANDBY;
+       c->valid_ops_mask &= REGULATOR_CHANGE_VOLTAGE
+                               | REGULATOR_CHANGE_MODE
+                               | REGULATOR_CHANGE_STATUS;
+
+       rdev = regulator_register(&info->desc, &pdev->dev, initdata, info);
+       if (IS_ERR(rdev)) {
+               dev_err(&pdev->dev, "can't register %s, %ld\n",
+                               info->desc.name, PTR_ERR(rdev));
+               return PTR_ERR(rdev);
+       }
+       platform_set_drvdata(pdev, rdev);
+
+       /* NOTE:  many regulators support short-circuit IRQs (presentable
+        * as REGULATOR_OVER_CURRENT notifications?) configured via:
+        *  - SC_CONFIG
+        *  - SC_DETECT1 (vintana2, vmmc1/2, vaux1/2/3/4)
+        *  - SC_DETECT2 (vusb, vdac, vio, vdd1/2, vpll2)
+        *  - IT_CONFIG
+        */
+
+       return 0;
+}
+
+static int __devexit twlreg_remove(struct platform_device *pdev)
+{
+       regulator_unregister(platform_get_drvdata(pdev));
+       return 0;
+}
+
+MODULE_ALIAS("platform:twl_reg");
+
+static struct platform_driver twlreg_driver = {
+       .probe          = twlreg_probe,
+       .remove         = __devexit_p(twlreg_remove),
+       /* NOTE: short name, to work around driver model truncation of
+        * "twl_regulator.12" (and friends) to "twl_regulator.1".
+        */
+       .driver.name    = "twl_reg",
+       .driver.owner   = THIS_MODULE,
+};
+
+static int __init twlreg_init(void)
+{
+       return platform_driver_register(&twlreg_driver);
+}
+subsys_initcall(twlreg_init);
+
+static void __exit twlreg_exit(void)
+{
+       platform_driver_unregister(&twlreg_driver);
+}
+module_exit(twlreg_exit)
+
+MODULE_DESCRIPTION("TWL regulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/twl4030-regulator.c b/drivers/regulator/twl4030-regulator.c
deleted file mode 100644 (file)
index e2032fb..0000000
+++ /dev/null
@@ -1,500 +0,0 @@
-/*
- * twl4030-regulator.c -- support regulators in twl4030 family chips
- *
- * Copyright (C) 2008 David Brownell
- *
- * 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/module.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/i2c/twl4030.h>
-
-
-/*
- * The TWL4030/TW5030/TPS659x0 family chips include power management, a
- * USB OTG transceiver, an RTC, ADC, PWM, and lots more.  Some versions
- * include an audio codec, battery charger, and more voltage regulators.
- * These chips are often used in OMAP-based systems.
- *
- * This driver implements software-based resource control for various
- * voltage regulators.  This is usually augmented with state machine
- * based control.
- */
-
-struct twlreg_info {
-       /* start of regulator's PM_RECEIVER control register bank */
-       u8                      base;
-
-       /* twl4030 resource ID, for resource control state machine */
-       u8                      id;
-
-       /* voltage in mV = table[VSEL]; table_len must be a power-of-two */
-       u8                      table_len;
-       const u16               *table;
-
-       /* chip constraints on regulator behavior */
-       u16                     min_mV;
-
-       /* used by regulator core */
-       struct regulator_desc   desc;
-};
-
-
-/* LDO control registers ... offset is from the base of its register bank.
- * The first three registers of all power resource banks help hardware to
- * manage the various resource groups.
- */
-#define VREG_GRP               0
-#define VREG_TYPE              1
-#define VREG_REMAP             2
-#define VREG_DEDICATED         3       /* LDO control */
-
-
-static inline int
-twl4030reg_read(struct twlreg_info *info, unsigned offset)
-{
-       u8 value;
-       int status;
-
-       status = twl4030_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER,
-                       &value, info->base + offset);
-       return (status < 0) ? status : value;
-}
-
-static inline int
-twl4030reg_write(struct twlreg_info *info, unsigned offset, u8 value)
-{
-       return twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
-                       value, info->base + offset);
-}
-
-/*----------------------------------------------------------------------*/
-
-/* generic power resource operations, which work on all regulators */
-
-static int twl4030reg_grp(struct regulator_dev *rdev)
-{
-       return twl4030reg_read(rdev_get_drvdata(rdev), VREG_GRP);
-}
-
-/*
- * Enable/disable regulators by joining/leaving the P1 (processor) group.
- * We assume nobody else is updating the DEV_GRP registers.
- */
-
-#define P3_GRP         BIT(7)          /* "peripherals" */
-#define P2_GRP         BIT(6)          /* secondary processor, modem, etc */
-#define P1_GRP         BIT(5)          /* CPU/Linux */
-
-static int twl4030reg_is_enabled(struct regulator_dev *rdev)
-{
-       int     state = twl4030reg_grp(rdev);
-
-       if (state < 0)
-               return state;
-
-       return (state & P1_GRP) != 0;
-}
-
-static int twl4030reg_enable(struct regulator_dev *rdev)
-{
-       struct twlreg_info      *info = rdev_get_drvdata(rdev);
-       int                     grp;
-
-       grp = twl4030reg_read(info, VREG_GRP);
-       if (grp < 0)
-               return grp;
-
-       grp |= P1_GRP;
-       return twl4030reg_write(info, VREG_GRP, grp);
-}
-
-static int twl4030reg_disable(struct regulator_dev *rdev)
-{
-       struct twlreg_info      *info = rdev_get_drvdata(rdev);
-       int                     grp;
-
-       grp = twl4030reg_read(info, VREG_GRP);
-       if (grp < 0)
-               return grp;
-
-       grp &= ~P1_GRP;
-       return twl4030reg_write(info, VREG_GRP, grp);
-}
-
-static int twl4030reg_get_status(struct regulator_dev *rdev)
-{
-       int     state = twl4030reg_grp(rdev);
-
-       if (state < 0)
-               return state;
-       state &= 0x0f;
-
-       /* assume state != WARM_RESET; we'd not be running...  */
-       if (!state)
-               return REGULATOR_STATUS_OFF;
-       return (state & BIT(3))
-               ? REGULATOR_STATUS_NORMAL
-               : REGULATOR_STATUS_STANDBY;
-}
-
-static int twl4030reg_set_mode(struct regulator_dev *rdev, unsigned mode)
-{
-       struct twlreg_info      *info = rdev_get_drvdata(rdev);
-       unsigned                message;
-       int                     status;
-
-       /* We can only set the mode through state machine commands... */
-       switch (mode) {
-       case REGULATOR_MODE_NORMAL:
-               message = MSG_SINGULAR(DEV_GRP_P1, info->id, RES_STATE_ACTIVE);
-               break;
-       case REGULATOR_MODE_STANDBY:
-               message = MSG_SINGULAR(DEV_GRP_P1, info->id, RES_STATE_SLEEP);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       /* Ensure the resource is associated with some group */
-       status = twl4030reg_grp(rdev);
-       if (status < 0)
-               return status;
-       if (!(status & (P3_GRP | P2_GRP | P1_GRP)))
-               return -EACCES;
-
-       status = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
-                       message >> 8, 0x15 /* PB_WORD_MSB */ );
-       if (status >= 0)
-               return status;
-
-       return twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
-                       message, 0x16 /* PB_WORD_LSB */ );
-}
-
-/*----------------------------------------------------------------------*/
-
-/*
- * Support for adjustable-voltage LDOs uses a four bit (or less) voltage
- * select field in its control register.   We use tables indexed by VSEL
- * to record voltages in milliVolts.  (Accuracy is about three percent.)
- *
- * Note that VSEL values for VAUX2 changed in twl5030 and newer silicon;
- * currently handled by listing two slightly different VAUX2 regulators,
- * only one of which will be configured.
- *
- * VSEL values documented as "TI cannot support these values" are flagged
- * in these tables as UNSUP() values; we normally won't assign them.
- *
- * VAUX3 at 3V is incorrectly listed in some TI manuals as unsupported.
- * TI are revising the twl5030/tps659x0 specs to support that 3.0V setting.
- */
-#ifdef CONFIG_TWL4030_ALLOW_UNSUPPORTED
-#define UNSUP_MASK     0x0000
-#else
-#define UNSUP_MASK     0x8000
-#endif
-
-#define UNSUP(x)       (UNSUP_MASK | (x))
-#define IS_UNSUP(x)    (UNSUP_MASK & (x))
-#define LDO_MV(x)      (~UNSUP_MASK & (x))
-
-
-static const u16 VAUX1_VSEL_table[] = {
-       UNSUP(1500), UNSUP(1800), 2500, 2800,
-       3000, 3000, 3000, 3000,
-};
-static const u16 VAUX2_4030_VSEL_table[] = {
-       UNSUP(1000), UNSUP(1000), UNSUP(1200), 1300,
-       1500, 1800, UNSUP(1850), 2500,
-       UNSUP(2600), 2800, UNSUP(2850), UNSUP(3000),
-       UNSUP(3150), UNSUP(3150), UNSUP(3150), UNSUP(3150),
-};
-static const u16 VAUX2_VSEL_table[] = {
-       1700, 1700, 1900, 1300,
-       1500, 1800, 2000, 2500,
-       2100, 2800, 2200, 2300,
-       2400, 2400, 2400, 2400,
-};
-static const u16 VAUX3_VSEL_table[] = {
-       1500, 1800, 2500, 2800,
-       3000, 3000, 3000, 3000,
-};
-static const u16 VAUX4_VSEL_table[] = {
-       700, 1000, 1200, UNSUP(1300),
-       1500, 1800, UNSUP(1850), 2500,
-       UNSUP(2600), 2800, UNSUP(2850), UNSUP(3000),
-       UNSUP(3150), UNSUP(3150), UNSUP(3150), UNSUP(3150),
-};
-static const u16 VMMC1_VSEL_table[] = {
-       1850, 2850, 3000, 3150,
-};
-static const u16 VMMC2_VSEL_table[] = {
-       UNSUP(1000), UNSUP(1000), UNSUP(1200), UNSUP(1300),
-       UNSUP(1500), UNSUP(1800), 1850, UNSUP(2500),
-       2600, 2800, 2850, 3000,
-       3150, 3150, 3150, 3150,
-};
-static const u16 VPLL1_VSEL_table[] = {
-       1000, 1200, 1300, 1800,
-       UNSUP(2800), UNSUP(3000), UNSUP(3000), UNSUP(3000),
-};
-static const u16 VPLL2_VSEL_table[] = {
-       700, 1000, 1200, 1300,
-       UNSUP(1500), 1800, UNSUP(1850), UNSUP(2500),
-       UNSUP(2600), UNSUP(2800), UNSUP(2850), UNSUP(3000),
-       UNSUP(3150), UNSUP(3150), UNSUP(3150), UNSUP(3150),
-};
-static const u16 VSIM_VSEL_table[] = {
-       UNSUP(1000), UNSUP(1200), UNSUP(1300), 1800,
-       2800, 3000, 3000, 3000,
-};
-static const u16 VDAC_VSEL_table[] = {
-       1200, 1300, 1800, 1800,
-};
-
-
-static int twl4030ldo_list_voltage(struct regulator_dev *rdev, unsigned index)
-{
-       struct twlreg_info      *info = rdev_get_drvdata(rdev);
-       int                     mV = info->table[index];
-
-       return IS_UNSUP(mV) ? 0 : (LDO_MV(mV) * 1000);
-}
-
-static int
-twl4030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
-{
-       struct twlreg_info      *info = rdev_get_drvdata(rdev);
-       int                     vsel;
-
-       for (vsel = 0; vsel < info->table_len; vsel++) {
-               int mV = info->table[vsel];
-               int uV;
-
-               if (IS_UNSUP(mV))
-                       continue;
-               uV = LDO_MV(mV) * 1000;
-
-               /* REVISIT for VAUX2, first match may not be best/lowest */
-
-               /* use the first in-range value */
-               if (min_uV <= uV && uV <= max_uV)
-                       return twl4030reg_write(info, VREG_DEDICATED, vsel);
-       }
-
-       return -EDOM;
-}
-
-static int twl4030ldo_get_voltage(struct regulator_dev *rdev)
-{
-       struct twlreg_info      *info = rdev_get_drvdata(rdev);
-       int                     vsel = twl4030reg_read(info, VREG_DEDICATED);
-
-       if (vsel < 0)
-               return vsel;
-
-       vsel &= info->table_len - 1;
-       return LDO_MV(info->table[vsel]) * 1000;
-}
-
-static struct regulator_ops twl4030ldo_ops = {
-       .list_voltage   = twl4030ldo_list_voltage,
-
-       .set_voltage    = twl4030ldo_set_voltage,
-       .get_voltage    = twl4030ldo_get_voltage,
-
-       .enable         = twl4030reg_enable,
-       .disable        = twl4030reg_disable,
-       .is_enabled     = twl4030reg_is_enabled,
-
-       .set_mode       = twl4030reg_set_mode,
-
-       .get_status     = twl4030reg_get_status,
-};
-
-/*----------------------------------------------------------------------*/
-
-/*
- * Fixed voltage LDOs don't have a VSEL field to update.
- */
-static int twl4030fixed_list_voltage(struct regulator_dev *rdev, unsigned index)
-{
-       struct twlreg_info      *info = rdev_get_drvdata(rdev);
-
-       return info->min_mV * 1000;
-}
-
-static int twl4030fixed_get_voltage(struct regulator_dev *rdev)
-{
-       struct twlreg_info      *info = rdev_get_drvdata(rdev);
-
-       return info->min_mV * 1000;
-}
-
-static struct regulator_ops twl4030fixed_ops = {
-       .list_voltage   = twl4030fixed_list_voltage,
-
-       .get_voltage    = twl4030fixed_get_voltage,
-
-       .enable         = twl4030reg_enable,
-       .disable        = twl4030reg_disable,
-       .is_enabled     = twl4030reg_is_enabled,
-
-       .set_mode       = twl4030reg_set_mode,
-
-       .get_status     = twl4030reg_get_status,
-};
-
-/*----------------------------------------------------------------------*/
-
-#define TWL_ADJUSTABLE_LDO(label, offset, num) { \
-       .base = offset, \
-       .id = num, \
-       .table_len = ARRAY_SIZE(label##_VSEL_table), \
-       .table = label##_VSEL_table, \
-       .desc = { \
-               .name = #label, \
-               .id = TWL4030_REG_##label, \
-               .n_voltages = ARRAY_SIZE(label##_VSEL_table), \
-               .ops = &twl4030ldo_ops, \
-               .type = REGULATOR_VOLTAGE, \
-               .owner = THIS_MODULE, \
-               }, \
-       }
-
-#define TWL_FIXED_LDO(label, offset, mVolts, num) { \
-       .base = offset, \
-       .id = num, \
-       .min_mV = mVolts, \
-       .desc = { \
-               .name = #label, \
-               .id = TWL4030_REG_##label, \
-               .n_voltages = 1, \
-               .ops = &twl4030fixed_ops, \
-               .type = REGULATOR_VOLTAGE, \
-               .owner = THIS_MODULE, \
-               }, \
-       }
-
-/*
- * We list regulators here if systems need some level of
- * software control over them after boot.
- */
-static struct twlreg_info twl4030_regs[] = {
-       TWL_ADJUSTABLE_LDO(VAUX1, 0x17, 1),
-       TWL_ADJUSTABLE_LDO(VAUX2_4030, 0x1b, 2),
-       TWL_ADJUSTABLE_LDO(VAUX2, 0x1b, 2),
-       TWL_ADJUSTABLE_LDO(VAUX3, 0x1f, 3),
-       TWL_ADJUSTABLE_LDO(VAUX4, 0x23, 4),
-       TWL_ADJUSTABLE_LDO(VMMC1, 0x27, 5),
-       TWL_ADJUSTABLE_LDO(VMMC2, 0x2b, 6),
-       /*
-       TWL_ADJUSTABLE_LDO(VPLL1, 0x2f, 7),
-       */
-       TWL_ADJUSTABLE_LDO(VPLL2, 0x33, 8),
-       TWL_ADJUSTABLE_LDO(VSIM, 0x37, 9),
-       TWL_ADJUSTABLE_LDO(VDAC, 0x3b, 10),
-       /*
-       TWL_ADJUSTABLE_LDO(VINTANA1, 0x3f, 11),
-       TWL_ADJUSTABLE_LDO(VINTANA2, 0x43, 12),
-       TWL_ADJUSTABLE_LDO(VINTDIG, 0x47, 13),
-       TWL_SMPS(VIO, 0x4b, 14),
-       TWL_SMPS(VDD1, 0x55, 15),
-       TWL_SMPS(VDD2, 0x63, 16),
-        */
-       TWL_FIXED_LDO(VUSB1V5, 0x71, 1500, 17),
-       TWL_FIXED_LDO(VUSB1V8, 0x74, 1800, 18),
-       TWL_FIXED_LDO(VUSB3V1, 0x77, 3100, 19),
-       /* VUSBCP is managed *only* by the USB subchip */
-};
-
-static int twl4030reg_probe(struct platform_device *pdev)
-{
-       int                             i;
-       struct twlreg_info              *info;
-       struct regulator_init_data      *initdata;
-       struct regulation_constraints   *c;
-       struct regulator_dev            *rdev;
-
-       for (i = 0, info = NULL; i < ARRAY_SIZE(twl4030_regs); i++) {
-               if (twl4030_regs[i].desc.id != pdev->id)
-                       continue;
-               info = twl4030_regs + i;
-               break;
-       }
-       if (!info)
-               return -ENODEV;
-
-       initdata = pdev->dev.platform_data;
-       if (!initdata)
-               return -EINVAL;
-
-       /* Constrain board-specific capabilities according to what
-        * this driver and the chip itself can actually do.
-        */
-       c = &initdata->constraints;
-       c->valid_modes_mask &= REGULATOR_MODE_NORMAL | REGULATOR_MODE_STANDBY;
-       c->valid_ops_mask &= REGULATOR_CHANGE_VOLTAGE
-                               | REGULATOR_CHANGE_MODE
-                               | REGULATOR_CHANGE_STATUS;
-
-       rdev = regulator_register(&info->desc, &pdev->dev, initdata, info);
-       if (IS_ERR(rdev)) {
-               dev_err(&pdev->dev, "can't register %s, %ld\n",
-                               info->desc.name, PTR_ERR(rdev));
-               return PTR_ERR(rdev);
-       }
-       platform_set_drvdata(pdev, rdev);
-
-       /* NOTE:  many regulators support short-circuit IRQs (presentable
-        * as REGULATOR_OVER_CURRENT notifications?) configured via:
-        *  - SC_CONFIG
-        *  - SC_DETECT1 (vintana2, vmmc1/2, vaux1/2/3/4)
-        *  - SC_DETECT2 (vusb, vdac, vio, vdd1/2, vpll2)
-        *  - IT_CONFIG
-        */
-
-       return 0;
-}
-
-static int __devexit twl4030reg_remove(struct platform_device *pdev)
-{
-       regulator_unregister(platform_get_drvdata(pdev));
-       return 0;
-}
-
-MODULE_ALIAS("platform:twl4030_reg");
-
-static struct platform_driver twl4030reg_driver = {
-       .probe          = twl4030reg_probe,
-       .remove         = __devexit_p(twl4030reg_remove),
-       /* NOTE: short name, to work around driver model truncation of
-        * "twl4030_regulator.12" (and friends) to "twl4030_regulator.1".
-        */
-       .driver.name    = "twl4030_reg",
-       .driver.owner   = THIS_MODULE,
-};
-
-static int __init twl4030reg_init(void)
-{
-       return platform_driver_register(&twl4030reg_driver);
-}
-subsys_initcall(twl4030reg_init);
-
-static void __exit twl4030reg_exit(void)
-{
-       platform_driver_unregister(&twl4030reg_driver);
-}
-module_exit(twl4030reg_exit)
-
-MODULE_DESCRIPTION("TWL4030 regulator driver");
-MODULE_LICENSE("GPL");
index 768bd0e5b48bdd00293796554807fb2523ecc01d..1bbff099a546af37a1e4e2179ca52f9ffa478962 100644 (file)
@@ -1330,9 +1330,10 @@ static struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
         },
 };
 
-static void pmic_uv_handler(struct wm8350 *wm8350, int irq, void *data)
+static irqreturn_t pmic_uv_handler(int irq, void *data)
 {
        struct regulator_dev *rdev = (struct regulator_dev *)data;
+       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
 
        mutex_lock(&rdev->mutex);
        if (irq == WM8350_IRQ_CS1 || irq == WM8350_IRQ_CS2)
@@ -1344,6 +1345,8 @@ static void pmic_uv_handler(struct wm8350 *wm8350, int irq, void *data)
                                              REGULATOR_EVENT_UNDER_VOLTAGE,
                                              wm8350);
        mutex_unlock(&rdev->mutex);
+
+       return IRQ_HANDLED;
 }
 
 static int wm8350_regulator_probe(struct platform_device *pdev)
@@ -1388,7 +1391,7 @@ static int wm8350_regulator_probe(struct platform_device *pdev)
 
        /* register regulator IRQ */
        ret = wm8350_register_irq(wm8350, wm8350_reg[pdev->id].irq,
-                                 pmic_uv_handler, rdev);
+                                 pmic_uv_handler, 0, "UV", rdev);
        if (ret < 0) {
                regulator_unregister(rdev);
                dev_err(&pdev->dev, "failed to register regulator %s IRQ\n",
@@ -1396,8 +1399,6 @@ static int wm8350_regulator_probe(struct platform_device *pdev)
                return ret;
        }
 
-       wm8350_unmask_irq(wm8350, wm8350_reg[pdev->id].irq);
-
        return 0;
 }
 
@@ -1406,7 +1407,6 @@ static int wm8350_regulator_remove(struct platform_device *pdev)
        struct regulator_dev *rdev = platform_get_drvdata(pdev);
        struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
 
-       wm8350_mask_irq(wm8350, wm8350_reg[pdev->id].irq);
        wm8350_free_irq(wm8350, wm8350_reg[pdev->id].irq);
 
        regulator_unregister(rdev);
index f2e1004d12c7807f56b129e221a36c23cdc1c3bf..71fbd6e8edf71b9fda76a3df084ba00d50e77681 100644 (file)
@@ -258,14 +258,14 @@ config RTC_DRV_TWL92330
          the Menelaus driver; it's not separate module.
 
 config RTC_DRV_TWL4030
-       tristate "TI TWL4030/TWL5030/TPS659x0"
+       tristate "TI TWL4030/TWL5030/TWL6030/TPS659x0"
        depends on RTC_CLASS && TWL4030_CORE
        help
          If you say yes here you get support for the RTC on the
-         TWL4030 family chips, used mostly with OMAP3 platforms.
+         TWL4030/TWL5030/TWL6030 family chips, used mostly with OMAP3 platforms.
 
          This driver can also be built as a module. If so, the module
-         will be called rtc-twl4030.
+         will be called rtc-twl.
 
 config RTC_DRV_S35390A
        tristate "Seiko Instruments S-35390A"
index af1ba7ae285716667172ed663df8b85ecda301e5..7da6efb3e953407d9be5723797dd7a9c4ece1e30 100644 (file)
@@ -80,7 +80,7 @@ obj-$(CONFIG_RTC_DRV_STK17TA8)        += rtc-stk17ta8.o
 obj-$(CONFIG_RTC_DRV_STMP)     += rtc-stmp3xxx.o
 obj-$(CONFIG_RTC_DRV_SUN4V)    += rtc-sun4v.o
 obj-$(CONFIG_RTC_DRV_TEST)     += rtc-test.o
-obj-$(CONFIG_RTC_DRV_TWL4030)  += rtc-twl4030.o
+obj-$(CONFIG_RTC_DRV_TWL4030)  += rtc-twl.o
 obj-$(CONFIG_RTC_DRV_TX4939)   += rtc-tx4939.o
 obj-$(CONFIG_RTC_DRV_V3020)    += rtc-v3020.o
 obj-$(CONFIG_RTC_DRV_VR41XX)   += rtc-vr41xx.o
index 4c5d5d0c4cfcf13a4cbf462c7d03a8ad8531f99c..9b74e9c9151c6276c42256b8545508521cafcbd3 100644 (file)
@@ -277,16 +277,13 @@ static void pcf50633_rtc_irq(int irq, void *data)
 
 static int __devinit pcf50633_rtc_probe(struct platform_device *pdev)
 {
-       struct pcf50633_subdev_pdata *pdata;
        struct pcf50633_rtc *rtc;
 
-
        rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
        if (!rtc)
                return -ENOMEM;
 
-       pdata = pdev->dev.platform_data;
-       rtc->pcf = pdata->pcf;
+       rtc->pcf = dev_to_pcf50633(pdev->dev.parent);
        platform_set_drvdata(pdev, rtc);
        rtc->rtc_dev = rtc_device_register("pcf50633-rtc", &pdev->dev,
                                &pcf50633_rtc_ops, THIS_MODULE);
diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c
new file mode 100644 (file)
index 0000000..c6a83a2
--- /dev/null
@@ -0,0 +1,610 @@
+/*
+ * rtc-twl.c -- TWL Real Time Clock interface
+ *
+ * Copyright (C) 2007 MontaVista Software, Inc
+ * Author: Alexandre Rusev <source@mvista.com>
+ *
+ * Based on original TI driver twl4030-rtc.c
+ *   Copyright (C) 2006 Texas Instruments, Inc.
+ *
+ * Based on rtc-omap.c
+ *   Copyright (C) 2003 MontaVista Software, Inc.
+ *   Author: George G. Davis <gdavis@mvista.com> or <source@mvista.com>
+ *   Copyright (C) 2006 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+
+#include <linux/i2c/twl.h>
+
+
+/*
+ * RTC block register offsets (use TWL_MODULE_RTC)
+ */
+enum {
+       REG_SECONDS_REG = 0,
+       REG_MINUTES_REG,
+       REG_HOURS_REG,
+       REG_DAYS_REG,
+       REG_MONTHS_REG,
+       REG_YEARS_REG,
+       REG_WEEKS_REG,
+
+       REG_ALARM_SECONDS_REG,
+       REG_ALARM_MINUTES_REG,
+       REG_ALARM_HOURS_REG,
+       REG_ALARM_DAYS_REG,
+       REG_ALARM_MONTHS_REG,
+       REG_ALARM_YEARS_REG,
+
+       REG_RTC_CTRL_REG,
+       REG_RTC_STATUS_REG,
+       REG_RTC_INTERRUPTS_REG,
+
+       REG_RTC_COMP_LSB_REG,
+       REG_RTC_COMP_MSB_REG,
+};
+const static u8 twl4030_rtc_reg_map[] = {
+       [REG_SECONDS_REG] = 0x00,
+       [REG_MINUTES_REG] = 0x01,
+       [REG_HOURS_REG] = 0x02,
+       [REG_DAYS_REG] = 0x03,
+       [REG_MONTHS_REG] = 0x04,
+       [REG_YEARS_REG] = 0x05,
+       [REG_WEEKS_REG] = 0x06,
+
+       [REG_ALARM_SECONDS_REG] = 0x07,
+       [REG_ALARM_MINUTES_REG] = 0x08,
+       [REG_ALARM_HOURS_REG] = 0x09,
+       [REG_ALARM_DAYS_REG] = 0x0A,
+       [REG_ALARM_MONTHS_REG] = 0x0B,
+       [REG_ALARM_YEARS_REG] = 0x0C,
+
+       [REG_RTC_CTRL_REG] = 0x0D,
+       [REG_RTC_STATUS_REG] = 0x0E,
+       [REG_RTC_INTERRUPTS_REG] = 0x0F,
+
+       [REG_RTC_COMP_LSB_REG] = 0x10,
+       [REG_RTC_COMP_MSB_REG] = 0x11,
+};
+const static u8 twl6030_rtc_reg_map[] = {
+       [REG_SECONDS_REG] = 0x00,
+       [REG_MINUTES_REG] = 0x01,
+       [REG_HOURS_REG] = 0x02,
+       [REG_DAYS_REG] = 0x03,
+       [REG_MONTHS_REG] = 0x04,
+       [REG_YEARS_REG] = 0x05,
+       [REG_WEEKS_REG] = 0x06,
+
+       [REG_ALARM_SECONDS_REG] = 0x08,
+       [REG_ALARM_MINUTES_REG] = 0x09,
+       [REG_ALARM_HOURS_REG] = 0x0A,
+       [REG_ALARM_DAYS_REG] = 0x0B,
+       [REG_ALARM_MONTHS_REG] = 0x0C,
+       [REG_ALARM_YEARS_REG] = 0x0D,
+
+       [REG_RTC_CTRL_REG] = 0x10,
+       [REG_RTC_STATUS_REG] = 0x11,
+       [REG_RTC_INTERRUPTS_REG] = 0x12,
+
+       [REG_RTC_COMP_LSB_REG] = 0x13,
+       [REG_RTC_COMP_MSB_REG] = 0x14,
+};
+
+/* RTC_CTRL_REG bitfields */
+#define BIT_RTC_CTRL_REG_STOP_RTC_M              0x01
+#define BIT_RTC_CTRL_REG_ROUND_30S_M             0x02
+#define BIT_RTC_CTRL_REG_AUTO_COMP_M             0x04
+#define BIT_RTC_CTRL_REG_MODE_12_24_M            0x08
+#define BIT_RTC_CTRL_REG_TEST_MODE_M             0x10
+#define BIT_RTC_CTRL_REG_SET_32_COUNTER_M        0x20
+#define BIT_RTC_CTRL_REG_GET_TIME_M              0x40
+
+/* RTC_STATUS_REG bitfields */
+#define BIT_RTC_STATUS_REG_RUN_M                 0x02
+#define BIT_RTC_STATUS_REG_1S_EVENT_M            0x04
+#define BIT_RTC_STATUS_REG_1M_EVENT_M            0x08
+#define BIT_RTC_STATUS_REG_1H_EVENT_M            0x10
+#define BIT_RTC_STATUS_REG_1D_EVENT_M            0x20
+#define BIT_RTC_STATUS_REG_ALARM_M               0x40
+#define BIT_RTC_STATUS_REG_POWER_UP_M            0x80
+
+/* RTC_INTERRUPTS_REG bitfields */
+#define BIT_RTC_INTERRUPTS_REG_EVERY_M           0x03
+#define BIT_RTC_INTERRUPTS_REG_IT_TIMER_M        0x04
+#define BIT_RTC_INTERRUPTS_REG_IT_ALARM_M        0x08
+
+
+/* REG_SECONDS_REG through REG_YEARS_REG is how many registers? */
+#define ALL_TIME_REGS          6
+
+/*----------------------------------------------------------------------*/
+static u8  *rtc_reg_map;
+
+/*
+ * Supports 1 byte read from TWL RTC register.
+ */
+static int twl_rtc_read_u8(u8 *data, u8 reg)
+{
+       int ret;
+
+       ret = twl_i2c_read_u8(TWL_MODULE_RTC, data, (rtc_reg_map[reg]));
+       if (ret < 0)
+               pr_err("twl_rtc: Could not read TWL"
+                      "register %X - error %d\n", reg, ret);
+       return ret;
+}
+
+/*
+ * Supports 1 byte write to TWL RTC registers.
+ */
+static int twl_rtc_write_u8(u8 data, u8 reg)
+{
+       int ret;
+
+       ret = twl_i2c_write_u8(TWL_MODULE_RTC, data, (rtc_reg_map[reg]));
+       if (ret < 0)
+               pr_err("twl_rtc: Could not write TWL"
+                      "register %X - error %d\n", reg, ret);
+       return ret;
+}
+
+/*
+ * Cache the value for timer/alarm interrupts register; this is
+ * only changed by callers holding rtc ops lock (or resume).
+ */
+static unsigned char rtc_irq_bits;
+
+/*
+ * Enable 1/second update and/or alarm interrupts.
+ */
+static int set_rtc_irq_bit(unsigned char bit)
+{
+       unsigned char val;
+       int ret;
+
+       val = rtc_irq_bits | bit;
+       val &= ~BIT_RTC_INTERRUPTS_REG_EVERY_M;
+       ret = twl_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG);
+       if (ret == 0)
+               rtc_irq_bits = val;
+
+       return ret;
+}
+
+/*
+ * Disable update and/or alarm interrupts.
+ */
+static int mask_rtc_irq_bit(unsigned char bit)
+{
+       unsigned char val;
+       int ret;
+
+       val = rtc_irq_bits & ~bit;
+       ret = twl_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG);
+       if (ret == 0)
+               rtc_irq_bits = val;
+
+       return ret;
+}
+
+static int twl_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)
+{
+       int ret;
+
+       if (enabled)
+               ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+       else
+               ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+
+       return ret;
+}
+
+static int twl_rtc_update_irq_enable(struct device *dev, unsigned enabled)
+{
+       int ret;
+
+       if (enabled)
+               ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
+       else
+               ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
+
+       return ret;
+}
+
+/*
+ * Gets current TWL RTC time and date parameters.
+ *
+ * The RTC's time/alarm representation is not what gmtime(3) requires
+ * Linux to use:
+ *
+ *  - Months are 1..12 vs Linux 0-11
+ *  - Years are 0..99 vs Linux 1900..N (we assume 21st century)
+ */
+static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       unsigned char rtc_data[ALL_TIME_REGS + 1];
+       int ret;
+       u8 save_control;
+
+       ret = twl_rtc_read_u8(&save_control, REG_RTC_CTRL_REG);
+       if (ret < 0)
+               return ret;
+
+       save_control |= BIT_RTC_CTRL_REG_GET_TIME_M;
+
+       ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
+       if (ret < 0)
+               return ret;
+
+       ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data,
+                       (rtc_reg_map[REG_SECONDS_REG]), ALL_TIME_REGS);
+
+       if (ret < 0) {
+               dev_err(dev, "rtc_read_time error %d\n", ret);
+               return ret;
+       }
+
+       tm->tm_sec = bcd2bin(rtc_data[0]);
+       tm->tm_min = bcd2bin(rtc_data[1]);
+       tm->tm_hour = bcd2bin(rtc_data[2]);
+       tm->tm_mday = bcd2bin(rtc_data[3]);
+       tm->tm_mon = bcd2bin(rtc_data[4]) - 1;
+       tm->tm_year = bcd2bin(rtc_data[5]) + 100;
+
+       return ret;
+}
+
+static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       unsigned char save_control;
+       unsigned char rtc_data[ALL_TIME_REGS + 1];
+       int ret;
+
+       rtc_data[1] = bin2bcd(tm->tm_sec);
+       rtc_data[2] = bin2bcd(tm->tm_min);
+       rtc_data[3] = bin2bcd(tm->tm_hour);
+       rtc_data[4] = bin2bcd(tm->tm_mday);
+       rtc_data[5] = bin2bcd(tm->tm_mon + 1);
+       rtc_data[6] = bin2bcd(tm->tm_year - 100);
+
+       /* Stop RTC while updating the TC registers */
+       ret = twl_rtc_read_u8(&save_control, REG_RTC_CTRL_REG);
+       if (ret < 0)
+               goto out;
+
+       save_control &= ~BIT_RTC_CTRL_REG_STOP_RTC_M;
+       twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
+       if (ret < 0)
+               goto out;
+
+       /* update all the time registers in one shot */
+       ret = twl_i2c_write(TWL_MODULE_RTC, rtc_data,
+               (rtc_reg_map[REG_SECONDS_REG]), ALL_TIME_REGS);
+       if (ret < 0) {
+               dev_err(dev, "rtc_set_time error %d\n", ret);
+               goto out;
+       }
+
+       /* Start back RTC */
+       save_control |= BIT_RTC_CTRL_REG_STOP_RTC_M;
+       ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
+
+out:
+       return ret;
+}
+
+/*
+ * Gets current TWL RTC alarm time.
+ */
+static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+       unsigned char rtc_data[ALL_TIME_REGS + 1];
+       int ret;
+
+       ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data,
+                       (rtc_reg_map[REG_ALARM_SECONDS_REG]), ALL_TIME_REGS);
+       if (ret < 0) {
+               dev_err(dev, "rtc_read_alarm error %d\n", ret);
+               return ret;
+       }
+
+       /* some of these fields may be wildcard/"match all" */
+       alm->time.tm_sec = bcd2bin(rtc_data[0]);
+       alm->time.tm_min = bcd2bin(rtc_data[1]);
+       alm->time.tm_hour = bcd2bin(rtc_data[2]);
+       alm->time.tm_mday = bcd2bin(rtc_data[3]);
+       alm->time.tm_mon = bcd2bin(rtc_data[4]) - 1;
+       alm->time.tm_year = bcd2bin(rtc_data[5]) + 100;
+
+       /* report cached alarm enable state */
+       if (rtc_irq_bits & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M)
+               alm->enabled = 1;
+
+       return ret;
+}
+
+static int twl_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+       unsigned char alarm_data[ALL_TIME_REGS + 1];
+       int ret;
+
+       ret = twl_rtc_alarm_irq_enable(dev, 0);
+       if (ret)
+               goto out;
+
+       alarm_data[1] = bin2bcd(alm->time.tm_sec);
+       alarm_data[2] = bin2bcd(alm->time.tm_min);
+       alarm_data[3] = bin2bcd(alm->time.tm_hour);
+       alarm_data[4] = bin2bcd(alm->time.tm_mday);
+       alarm_data[5] = bin2bcd(alm->time.tm_mon + 1);
+       alarm_data[6] = bin2bcd(alm->time.tm_year - 100);
+
+       /* update all the alarm registers in one shot */
+       ret = twl_i2c_write(TWL_MODULE_RTC, alarm_data,
+               (rtc_reg_map[REG_ALARM_SECONDS_REG]), ALL_TIME_REGS);
+       if (ret) {
+               dev_err(dev, "rtc_set_alarm error %d\n", ret);
+               goto out;
+       }
+
+       if (alm->enabled)
+               ret = twl_rtc_alarm_irq_enable(dev, 1);
+out:
+       return ret;
+}
+
+static irqreturn_t twl_rtc_interrupt(int irq, void *rtc)
+{
+       unsigned long events = 0;
+       int ret = IRQ_NONE;
+       int res;
+       u8 rd_reg;
+
+#ifdef CONFIG_LOCKDEP
+       /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which
+        * we don't want and can't tolerate.  Although it might be
+        * friendlier not to borrow this thread context...
+        */
+       local_irq_enable();
+#endif
+
+       res = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG);
+       if (res)
+               goto out;
+       /*
+        * Figure out source of interrupt: ALARM or TIMER in RTC_STATUS_REG.
+        * only one (ALARM or RTC) interrupt source may be enabled
+        * at time, we also could check our results
+        * by reading RTS_INTERRUPTS_REGISTER[IT_TIMER,IT_ALARM]
+        */
+       if (rd_reg & BIT_RTC_STATUS_REG_ALARM_M)
+               events |= RTC_IRQF | RTC_AF;
+       else
+               events |= RTC_IRQF | RTC_UF;
+
+       res = twl_rtc_write_u8(rd_reg | BIT_RTC_STATUS_REG_ALARM_M,
+                                  REG_RTC_STATUS_REG);
+       if (res)
+               goto out;
+
+       if (twl_class_is_4030()) {
+               /* Clear on Read enabled. RTC_IT bit of TWL4030_INT_PWR_ISR1
+                * needs 2 reads to clear the interrupt. One read is done in
+                * do_twl_pwrirq(). Doing the second read, to clear
+                * the bit.
+                *
+                * FIXME the reason PWR_ISR1 needs an extra read is that
+                * RTC_IF retriggered until we cleared REG_ALARM_M above.
+                * But re-reading like this is a bad hack; by doing so we
+                * risk wrongly clearing status for some other IRQ (losing
+                * the interrupt).  Be smarter about handling RTC_UF ...
+                */
+               res = twl_i2c_read_u8(TWL4030_MODULE_INT,
+                       &rd_reg, TWL4030_INT_PWR_ISR1);
+               if (res)
+                       goto out;
+       }
+
+       /* Notify RTC core on event */
+       rtc_update_irq(rtc, 1, events);
+
+       ret = IRQ_HANDLED;
+out:
+       return ret;
+}
+
+static struct rtc_class_ops twl_rtc_ops = {
+       .read_time      = twl_rtc_read_time,
+       .set_time       = twl_rtc_set_time,
+       .read_alarm     = twl_rtc_read_alarm,
+       .set_alarm      = twl_rtc_set_alarm,
+       .alarm_irq_enable = twl_rtc_alarm_irq_enable,
+       .update_irq_enable = twl_rtc_update_irq_enable,
+};
+
+/*----------------------------------------------------------------------*/
+
+static int __devinit twl_rtc_probe(struct platform_device *pdev)
+{
+       struct rtc_device *rtc;
+       int ret = 0;
+       int irq = platform_get_irq(pdev, 0);
+       u8 rd_reg;
+
+       if (irq <= 0)
+               return -EINVAL;
+
+       rtc = rtc_device_register(pdev->name,
+                                 &pdev->dev, &twl_rtc_ops, THIS_MODULE);
+       if (IS_ERR(rtc)) {
+               ret = PTR_ERR(rtc);
+               dev_err(&pdev->dev, "can't register RTC device, err %ld\n",
+                       PTR_ERR(rtc));
+               goto out0;
+
+       }
+
+       platform_set_drvdata(pdev, rtc);
+
+       ret = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG);
+       if (ret < 0)
+               goto out1;
+
+       if (rd_reg & BIT_RTC_STATUS_REG_POWER_UP_M)
+               dev_warn(&pdev->dev, "Power up reset detected.\n");
+
+       if (rd_reg & BIT_RTC_STATUS_REG_ALARM_M)
+               dev_warn(&pdev->dev, "Pending Alarm interrupt detected.\n");
+
+       /* Clear RTC Power up reset and pending alarm interrupts */
+       ret = twl_rtc_write_u8(rd_reg, REG_RTC_STATUS_REG);
+       if (ret < 0)
+               goto out1;
+
+       ret = request_irq(irq, twl_rtc_interrupt,
+                               IRQF_TRIGGER_RISING,
+                               dev_name(&rtc->dev), rtc);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "IRQ is not free.\n");
+               goto out1;
+       }
+
+       if (twl_class_is_6030()) {
+               twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK,
+                       REG_INT_MSK_LINE_A);
+               twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK,
+                       REG_INT_MSK_STS_A);
+       }
+
+       /* Check RTC module status, Enable if it is off */
+       ret = twl_rtc_read_u8(&rd_reg, REG_RTC_CTRL_REG);
+       if (ret < 0)
+               goto out2;
+
+       if (!(rd_reg & BIT_RTC_CTRL_REG_STOP_RTC_M)) {
+               dev_info(&pdev->dev, "Enabling TWL-RTC.\n");
+               rd_reg = BIT_RTC_CTRL_REG_STOP_RTC_M;
+               ret = twl_rtc_write_u8(rd_reg, REG_RTC_CTRL_REG);
+               if (ret < 0)
+                       goto out2;
+       }
+
+       /* init cached IRQ enable bits */
+       ret = twl_rtc_read_u8(&rtc_irq_bits, REG_RTC_INTERRUPTS_REG);
+       if (ret < 0)
+               goto out2;
+
+       return ret;
+
+out2:
+       free_irq(irq, rtc);
+out1:
+       rtc_device_unregister(rtc);
+out0:
+       return ret;
+}
+
+/*
+ * Disable all TWL RTC module interrupts.
+ * Sets status flag to free.
+ */
+static int __devexit twl_rtc_remove(struct platform_device *pdev)
+{
+       /* leave rtc running, but disable irqs */
+       struct rtc_device *rtc = platform_get_drvdata(pdev);
+       int irq = platform_get_irq(pdev, 0);
+
+       mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+       mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
+       if (twl_class_is_6030()) {
+               twl6030_interrupt_mask(TWL6030_RTC_INT_MASK,
+                       REG_INT_MSK_LINE_A);
+               twl6030_interrupt_mask(TWL6030_RTC_INT_MASK,
+                       REG_INT_MSK_STS_A);
+       }
+
+
+       free_irq(irq, rtc);
+
+       rtc_device_unregister(rtc);
+       platform_set_drvdata(pdev, NULL);
+       return 0;
+}
+
+static void twl_rtc_shutdown(struct platform_device *pdev)
+{
+       /* mask timer interrupts, but leave alarm interrupts on to enable
+          power-on when alarm is triggered */
+       mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
+}
+
+#ifdef CONFIG_PM
+
+static unsigned char irqstat;
+
+static int twl_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       irqstat = rtc_irq_bits;
+
+       mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
+       return 0;
+}
+
+static int twl_rtc_resume(struct platform_device *pdev)
+{
+       set_rtc_irq_bit(irqstat);
+       return 0;
+}
+
+#else
+#define twl_rtc_suspend NULL
+#define twl_rtc_resume  NULL
+#endif
+
+MODULE_ALIAS("platform:twl_rtc");
+
+static struct platform_driver twl4030rtc_driver = {
+       .probe          = twl_rtc_probe,
+       .remove         = __devexit_p(twl_rtc_remove),
+       .shutdown       = twl_rtc_shutdown,
+       .suspend        = twl_rtc_suspend,
+       .resume         = twl_rtc_resume,
+       .driver         = {
+               .owner  = THIS_MODULE,
+               .name   = "twl_rtc",
+       },
+};
+
+static int __init twl_rtc_init(void)
+{
+       if (twl_class_is_4030())
+               rtc_reg_map = (u8 *) twl4030_rtc_reg_map;
+       else
+               rtc_reg_map = (u8 *) twl6030_rtc_reg_map;
+
+       return platform_driver_register(&twl4030rtc_driver);
+}
+module_init(twl_rtc_init);
+
+static void __exit twl_rtc_exit(void)
+{
+       platform_driver_unregister(&twl4030rtc_driver);
+}
+module_exit(twl_rtc_exit);
+
+MODULE_AUTHOR("Texas Instruments, MontaVista Software");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-twl4030.c b/drivers/rtc/rtc-twl4030.c
deleted file mode 100644 (file)
index 9c8c70c..0000000
+++ /dev/null
@@ -1,540 +0,0 @@
-/*
- * rtc-twl4030.c -- TWL4030 Real Time Clock interface
- *
- * Copyright (C) 2007 MontaVista Software, Inc
- * Author: Alexandre Rusev <source@mvista.com>
- *
- * Based on original TI driver twl4030-rtc.c
- *   Copyright (C) 2006 Texas Instruments, Inc.
- *
- * Based on rtc-omap.c
- *   Copyright (C) 2003 MontaVista Software, Inc.
- *   Author: George G. Davis <gdavis@mvista.com> or <source@mvista.com>
- *   Copyright (C) 2006 David Brownell
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/rtc.h>
-#include <linux/bcd.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-
-#include <linux/i2c/twl4030.h>
-
-
-/*
- * RTC block register offsets (use TWL_MODULE_RTC)
- */
-#define REG_SECONDS_REG                          0x00
-#define REG_MINUTES_REG                          0x01
-#define REG_HOURS_REG                            0x02
-#define REG_DAYS_REG                             0x03
-#define REG_MONTHS_REG                           0x04
-#define REG_YEARS_REG                            0x05
-#define REG_WEEKS_REG                            0x06
-
-#define REG_ALARM_SECONDS_REG                    0x07
-#define REG_ALARM_MINUTES_REG                    0x08
-#define REG_ALARM_HOURS_REG                      0x09
-#define REG_ALARM_DAYS_REG                       0x0A
-#define REG_ALARM_MONTHS_REG                     0x0B
-#define REG_ALARM_YEARS_REG                      0x0C
-
-#define REG_RTC_CTRL_REG                         0x0D
-#define REG_RTC_STATUS_REG                       0x0E
-#define REG_RTC_INTERRUPTS_REG                   0x0F
-
-#define REG_RTC_COMP_LSB_REG                     0x10
-#define REG_RTC_COMP_MSB_REG                     0x11
-
-/* RTC_CTRL_REG bitfields */
-#define BIT_RTC_CTRL_REG_STOP_RTC_M              0x01
-#define BIT_RTC_CTRL_REG_ROUND_30S_M             0x02
-#define BIT_RTC_CTRL_REG_AUTO_COMP_M             0x04
-#define BIT_RTC_CTRL_REG_MODE_12_24_M            0x08
-#define BIT_RTC_CTRL_REG_TEST_MODE_M             0x10
-#define BIT_RTC_CTRL_REG_SET_32_COUNTER_M        0x20
-#define BIT_RTC_CTRL_REG_GET_TIME_M              0x40
-
-/* RTC_STATUS_REG bitfields */
-#define BIT_RTC_STATUS_REG_RUN_M                 0x02
-#define BIT_RTC_STATUS_REG_1S_EVENT_M            0x04
-#define BIT_RTC_STATUS_REG_1M_EVENT_M            0x08
-#define BIT_RTC_STATUS_REG_1H_EVENT_M            0x10
-#define BIT_RTC_STATUS_REG_1D_EVENT_M            0x20
-#define BIT_RTC_STATUS_REG_ALARM_M               0x40
-#define BIT_RTC_STATUS_REG_POWER_UP_M            0x80
-
-/* RTC_INTERRUPTS_REG bitfields */
-#define BIT_RTC_INTERRUPTS_REG_EVERY_M           0x03
-#define BIT_RTC_INTERRUPTS_REG_IT_TIMER_M        0x04
-#define BIT_RTC_INTERRUPTS_REG_IT_ALARM_M        0x08
-
-
-/* REG_SECONDS_REG through REG_YEARS_REG is how many registers? */
-#define ALL_TIME_REGS          6
-
-/*----------------------------------------------------------------------*/
-
-/*
- * Supports 1 byte read from TWL4030 RTC register.
- */
-static int twl4030_rtc_read_u8(u8 *data, u8 reg)
-{
-       int ret;
-
-       ret = twl4030_i2c_read_u8(TWL4030_MODULE_RTC, data, reg);
-       if (ret < 0)
-               pr_err("twl4030_rtc: Could not read TWL4030"
-                      "register %X - error %d\n", reg, ret);
-       return ret;
-}
-
-/*
- * Supports 1 byte write to TWL4030 RTC registers.
- */
-static int twl4030_rtc_write_u8(u8 data, u8 reg)
-{
-       int ret;
-
-       ret = twl4030_i2c_write_u8(TWL4030_MODULE_RTC, data, reg);
-       if (ret < 0)
-               pr_err("twl4030_rtc: Could not write TWL4030"
-                      "register %X - error %d\n", reg, ret);
-       return ret;
-}
-
-/*
- * Cache the value for timer/alarm interrupts register; this is
- * only changed by callers holding rtc ops lock (or resume).
- */
-static unsigned char rtc_irq_bits;
-
-/*
- * Enable 1/second update and/or alarm interrupts.
- */
-static int set_rtc_irq_bit(unsigned char bit)
-{
-       unsigned char val;
-       int ret;
-
-       val = rtc_irq_bits | bit;
-       val &= ~BIT_RTC_INTERRUPTS_REG_EVERY_M;
-       ret = twl4030_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG);
-       if (ret == 0)
-               rtc_irq_bits = val;
-
-       return ret;
-}
-
-/*
- * Disable update and/or alarm interrupts.
- */
-static int mask_rtc_irq_bit(unsigned char bit)
-{
-       unsigned char val;
-       int ret;
-
-       val = rtc_irq_bits & ~bit;
-       ret = twl4030_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG);
-       if (ret == 0)
-               rtc_irq_bits = val;
-
-       return ret;
-}
-
-static int twl4030_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)
-{
-       int ret;
-
-       if (enabled)
-               ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
-       else
-               ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
-
-       return ret;
-}
-
-static int twl4030_rtc_update_irq_enable(struct device *dev, unsigned enabled)
-{
-       int ret;
-
-       if (enabled)
-               ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
-       else
-               ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
-
-       return ret;
-}
-
-/*
- * Gets current TWL4030 RTC time and date parameters.
- *
- * The RTC's time/alarm representation is not what gmtime(3) requires
- * Linux to use:
- *
- *  - Months are 1..12 vs Linux 0-11
- *  - Years are 0..99 vs Linux 1900..N (we assume 21st century)
- */
-static int twl4030_rtc_read_time(struct device *dev, struct rtc_time *tm)
-{
-       unsigned char rtc_data[ALL_TIME_REGS + 1];
-       int ret;
-       u8 save_control;
-
-       ret = twl4030_rtc_read_u8(&save_control, REG_RTC_CTRL_REG);
-       if (ret < 0)
-               return ret;
-
-       save_control |= BIT_RTC_CTRL_REG_GET_TIME_M;
-
-       ret = twl4030_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
-       if (ret < 0)
-               return ret;
-
-       ret = twl4030_i2c_read(TWL4030_MODULE_RTC, rtc_data,
-                              REG_SECONDS_REG, ALL_TIME_REGS);
-
-       if (ret < 0) {
-               dev_err(dev, "rtc_read_time error %d\n", ret);
-               return ret;
-       }
-
-       tm->tm_sec = bcd2bin(rtc_data[0]);
-       tm->tm_min = bcd2bin(rtc_data[1]);
-       tm->tm_hour = bcd2bin(rtc_data[2]);
-       tm->tm_mday = bcd2bin(rtc_data[3]);
-       tm->tm_mon = bcd2bin(rtc_data[4]) - 1;
-       tm->tm_year = bcd2bin(rtc_data[5]) + 100;
-
-       return ret;
-}
-
-static int twl4030_rtc_set_time(struct device *dev, struct rtc_time *tm)
-{
-       unsigned char save_control;
-       unsigned char rtc_data[ALL_TIME_REGS + 1];
-       int ret;
-
-       rtc_data[1] = bin2bcd(tm->tm_sec);
-       rtc_data[2] = bin2bcd(tm->tm_min);
-       rtc_data[3] = bin2bcd(tm->tm_hour);
-       rtc_data[4] = bin2bcd(tm->tm_mday);
-       rtc_data[5] = bin2bcd(tm->tm_mon + 1);
-       rtc_data[6] = bin2bcd(tm->tm_year - 100);
-
-       /* Stop RTC while updating the TC registers */
-       ret = twl4030_rtc_read_u8(&save_control, REG_RTC_CTRL_REG);
-       if (ret < 0)
-               goto out;
-
-       save_control &= ~BIT_RTC_CTRL_REG_STOP_RTC_M;
-       twl4030_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
-       if (ret < 0)
-               goto out;
-
-       /* update all the time registers in one shot */
-       ret = twl4030_i2c_write(TWL4030_MODULE_RTC, rtc_data,
-                       REG_SECONDS_REG, ALL_TIME_REGS);
-       if (ret < 0) {
-               dev_err(dev, "rtc_set_time error %d\n", ret);
-               goto out;
-       }
-
-       /* Start back RTC */
-       save_control |= BIT_RTC_CTRL_REG_STOP_RTC_M;
-       ret = twl4030_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
-
-out:
-       return ret;
-}
-
-/*
- * Gets current TWL4030 RTC alarm time.
- */
-static int twl4030_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
-{
-       unsigned char rtc_data[ALL_TIME_REGS + 1];
-       int ret;
-
-       ret = twl4030_i2c_read(TWL4030_MODULE_RTC, rtc_data,
-                              REG_ALARM_SECONDS_REG, ALL_TIME_REGS);
-       if (ret < 0) {
-               dev_err(dev, "rtc_read_alarm error %d\n", ret);
-               return ret;
-       }
-
-       /* some of these fields may be wildcard/"match all" */
-       alm->time.tm_sec = bcd2bin(rtc_data[0]);
-       alm->time.tm_min = bcd2bin(rtc_data[1]);
-       alm->time.tm_hour = bcd2bin(rtc_data[2]);
-       alm->time.tm_mday = bcd2bin(rtc_data[3]);
-       alm->time.tm_mon = bcd2bin(rtc_data[4]) - 1;
-       alm->time.tm_year = bcd2bin(rtc_data[5]) + 100;
-
-       /* report cached alarm enable state */
-       if (rtc_irq_bits & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M)
-               alm->enabled = 1;
-
-       return ret;
-}
-
-static int twl4030_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
-{
-       unsigned char alarm_data[ALL_TIME_REGS + 1];
-       int ret;
-
-       ret = twl4030_rtc_alarm_irq_enable(dev, 0);
-       if (ret)
-               goto out;
-
-       alarm_data[1] = bin2bcd(alm->time.tm_sec);
-       alarm_data[2] = bin2bcd(alm->time.tm_min);
-       alarm_data[3] = bin2bcd(alm->time.tm_hour);
-       alarm_data[4] = bin2bcd(alm->time.tm_mday);
-       alarm_data[5] = bin2bcd(alm->time.tm_mon + 1);
-       alarm_data[6] = bin2bcd(alm->time.tm_year - 100);
-
-       /* update all the alarm registers in one shot */
-       ret = twl4030_i2c_write(TWL4030_MODULE_RTC, alarm_data,
-                       REG_ALARM_SECONDS_REG, ALL_TIME_REGS);
-       if (ret) {
-               dev_err(dev, "rtc_set_alarm error %d\n", ret);
-               goto out;
-       }
-
-       if (alm->enabled)
-               ret = twl4030_rtc_alarm_irq_enable(dev, 1);
-out:
-       return ret;
-}
-
-static irqreturn_t twl4030_rtc_interrupt(int irq, void *rtc)
-{
-       unsigned long events = 0;
-       int ret = IRQ_NONE;
-       int res;
-       u8 rd_reg;
-
-#ifdef CONFIG_LOCKDEP
-       /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which
-        * we don't want and can't tolerate.  Although it might be
-        * friendlier not to borrow this thread context...
-        */
-       local_irq_enable();
-#endif
-
-       res = twl4030_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG);
-       if (res)
-               goto out;
-       /*
-        * Figure out source of interrupt: ALARM or TIMER in RTC_STATUS_REG.
-        * only one (ALARM or RTC) interrupt source may be enabled
-        * at time, we also could check our results
-        * by reading RTS_INTERRUPTS_REGISTER[IT_TIMER,IT_ALARM]
-        */
-       if (rd_reg & BIT_RTC_STATUS_REG_ALARM_M)
-               events |= RTC_IRQF | RTC_AF;
-       else
-               events |= RTC_IRQF | RTC_UF;
-
-       res = twl4030_rtc_write_u8(rd_reg | BIT_RTC_STATUS_REG_ALARM_M,
-                                  REG_RTC_STATUS_REG);
-       if (res)
-               goto out;
-
-       /* Clear on Read enabled. RTC_IT bit of TWL4030_INT_PWR_ISR1
-        * needs 2 reads to clear the interrupt. One read is done in
-        * do_twl4030_pwrirq(). Doing the second read, to clear
-        * the bit.
-        *
-        * FIXME the reason PWR_ISR1 needs an extra read is that
-        * RTC_IF retriggered until we cleared REG_ALARM_M above.
-        * But re-reading like this is a bad hack; by doing so we
-        * risk wrongly clearing status for some other IRQ (losing
-        * the interrupt).  Be smarter about handling RTC_UF ...
-        */
-       res = twl4030_i2c_read_u8(TWL4030_MODULE_INT,
-                       &rd_reg, TWL4030_INT_PWR_ISR1);
-       if (res)
-               goto out;
-
-       /* Notify RTC core on event */
-       rtc_update_irq(rtc, 1, events);
-
-       ret = IRQ_HANDLED;
-out:
-       return ret;
-}
-
-static struct rtc_class_ops twl4030_rtc_ops = {
-       .read_time      = twl4030_rtc_read_time,
-       .set_time       = twl4030_rtc_set_time,
-       .read_alarm     = twl4030_rtc_read_alarm,
-       .set_alarm      = twl4030_rtc_set_alarm,
-       .alarm_irq_enable = twl4030_rtc_alarm_irq_enable,
-       .update_irq_enable = twl4030_rtc_update_irq_enable,
-};
-
-/*----------------------------------------------------------------------*/
-
-static int __devinit twl4030_rtc_probe(struct platform_device *pdev)
-{
-       struct rtc_device *rtc;
-       int ret = 0;
-       int irq = platform_get_irq(pdev, 0);
-       u8 rd_reg;
-
-       if (irq <= 0)
-               return -EINVAL;
-
-       rtc = rtc_device_register(pdev->name,
-                                 &pdev->dev, &twl4030_rtc_ops, THIS_MODULE);
-       if (IS_ERR(rtc)) {
-               ret = PTR_ERR(rtc);
-               dev_err(&pdev->dev, "can't register RTC device, err %ld\n",
-                       PTR_ERR(rtc));
-               goto out0;
-
-       }
-
-       platform_set_drvdata(pdev, rtc);
-
-       ret = twl4030_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG);
-       if (ret < 0)
-               goto out1;
-
-       if (rd_reg & BIT_RTC_STATUS_REG_POWER_UP_M)
-               dev_warn(&pdev->dev, "Power up reset detected.\n");
-
-       if (rd_reg & BIT_RTC_STATUS_REG_ALARM_M)
-               dev_warn(&pdev->dev, "Pending Alarm interrupt detected.\n");
-
-       /* Clear RTC Power up reset and pending alarm interrupts */
-       ret = twl4030_rtc_write_u8(rd_reg, REG_RTC_STATUS_REG);
-       if (ret < 0)
-               goto out1;
-
-       ret = request_irq(irq, twl4030_rtc_interrupt,
-                               IRQF_TRIGGER_RISING,
-                               dev_name(&rtc->dev), rtc);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "IRQ is not free.\n");
-               goto out1;
-       }
-
-       /* Check RTC module status, Enable if it is off */
-       ret = twl4030_rtc_read_u8(&rd_reg, REG_RTC_CTRL_REG);
-       if (ret < 0)
-               goto out2;
-
-       if (!(rd_reg & BIT_RTC_CTRL_REG_STOP_RTC_M)) {
-               dev_info(&pdev->dev, "Enabling TWL4030-RTC.\n");
-               rd_reg = BIT_RTC_CTRL_REG_STOP_RTC_M;
-               ret = twl4030_rtc_write_u8(rd_reg, REG_RTC_CTRL_REG);
-               if (ret < 0)
-                       goto out2;
-       }
-
-       /* init cached IRQ enable bits */
-       ret = twl4030_rtc_read_u8(&rtc_irq_bits, REG_RTC_INTERRUPTS_REG);
-       if (ret < 0)
-               goto out2;
-
-       return ret;
-
-out2:
-       free_irq(irq, rtc);
-out1:
-       rtc_device_unregister(rtc);
-out0:
-       return ret;
-}
-
-/*
- * Disable all TWL4030 RTC module interrupts.
- * Sets status flag to free.
- */
-static int __devexit twl4030_rtc_remove(struct platform_device *pdev)
-{
-       /* leave rtc running, but disable irqs */
-       struct rtc_device *rtc = platform_get_drvdata(pdev);
-       int irq = platform_get_irq(pdev, 0);
-
-       mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
-       mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
-
-       free_irq(irq, rtc);
-
-       rtc_device_unregister(rtc);
-       platform_set_drvdata(pdev, NULL);
-       return 0;
-}
-
-static void twl4030_rtc_shutdown(struct platform_device *pdev)
-{
-       /* mask timer interrupts, but leave alarm interrupts on to enable
-          power-on when alarm is triggered */
-       mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
-}
-
-#ifdef CONFIG_PM
-
-static unsigned char irqstat;
-
-static int twl4030_rtc_suspend(struct platform_device *pdev, pm_message_t state)
-{
-       irqstat = rtc_irq_bits;
-
-       mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
-       return 0;
-}
-
-static int twl4030_rtc_resume(struct platform_device *pdev)
-{
-       set_rtc_irq_bit(irqstat);
-       return 0;
-}
-
-#else
-#define twl4030_rtc_suspend NULL
-#define twl4030_rtc_resume  NULL
-#endif
-
-MODULE_ALIAS("platform:twl4030_rtc");
-
-static struct platform_driver twl4030rtc_driver = {
-       .probe          = twl4030_rtc_probe,
-       .remove         = __devexit_p(twl4030_rtc_remove),
-       .shutdown       = twl4030_rtc_shutdown,
-       .suspend        = twl4030_rtc_suspend,
-       .resume         = twl4030_rtc_resume,
-       .driver         = {
-               .owner  = THIS_MODULE,
-               .name   = "twl4030_rtc",
-       },
-};
-
-static int __init twl4030_rtc_init(void)
-{
-       return platform_driver_register(&twl4030rtc_driver);
-}
-module_init(twl4030_rtc_init);
-
-static void __exit twl4030_rtc_exit(void)
-{
-       platform_driver_unregister(&twl4030rtc_driver);
-}
-module_exit(twl4030_rtc_exit);
-
-MODULE_AUTHOR("Texas Instruments, MontaVista Software");
-MODULE_LICENSE("GPL");
index c91edc572eb609f3c78449099fabf04d0e76af8d..f16486635a8efab098e21e22c1ada0c42f91b2da 100644 (file)
@@ -315,9 +315,9 @@ static int wm8350_rtc_update_irq_enable(struct device *dev,
        return 0;
 }
 
-static void wm8350_rtc_alarm_handler(struct wm8350 *wm8350, int irq,
-                                    void *data)
+static irqreturn_t wm8350_rtc_alarm_handler(int irq, void *data)
 {
+       struct wm8350 *wm8350 = data;
        struct rtc_device *rtc = wm8350->rtc.rtc;
        int ret;
 
@@ -330,14 +330,18 @@ static void wm8350_rtc_alarm_handler(struct wm8350 *wm8350, int irq,
                dev_err(&(wm8350->rtc.pdev->dev),
                        "Failed to disable alarm: %d\n", ret);
        }
+
+       return IRQ_HANDLED;
 }
 
-static void wm8350_rtc_update_handler(struct wm8350 *wm8350, int irq,
-                                     void *data)
+static irqreturn_t wm8350_rtc_update_handler(int irq, void *data)
 {
+       struct wm8350 *wm8350 = data;
        struct rtc_device *rtc = wm8350->rtc.rtc;
 
        rtc_update_irq(rtc, 1, RTC_IRQF | RTC_UF);
+
+       return IRQ_HANDLED;
 }
 
 static const struct rtc_class_ops wm8350_rtc_ops = {
@@ -455,15 +459,14 @@ static int wm8350_rtc_probe(struct platform_device *pdev)
                return ret;
        }
 
-       wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_SEC);
-       wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_PER);
-
        wm8350_register_irq(wm8350, WM8350_IRQ_RTC_SEC,
-                           wm8350_rtc_update_handler, NULL);
+                           wm8350_rtc_update_handler, 0,
+                           "RTC Seconds", wm8350);
+       wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_SEC);
 
        wm8350_register_irq(wm8350, WM8350_IRQ_RTC_ALM,
-                           wm8350_rtc_alarm_handler, NULL);
-       wm8350_unmask_irq(wm8350, WM8350_IRQ_RTC_ALM);
+                           wm8350_rtc_alarm_handler, 0,
+                           "RTC Alarm", wm8350);
 
        return 0;
 }
@@ -473,8 +476,6 @@ static int __devexit wm8350_rtc_remove(struct platform_device *pdev)
        struct wm8350 *wm8350 = platform_get_drvdata(pdev);
        struct wm8350_rtc *wm_rtc = &wm8350->rtc;
 
-       wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_SEC);
-
        wm8350_free_irq(wm8350, WM8350_IRQ_RTC_SEC);
        wm8350_free_irq(wm8350, WM8350_IRQ_RTC_ALM);
 
index 395c04c2b00fcd5cca85a696bccddf6f540b7064..98c04cac43c1d87467ee60f43807c0dbc654409b 100644 (file)
@@ -113,11 +113,9 @@ static inline int iucv_dbf_passes(debug_info_t *dbf_grp, int level)
 #define IUCV_DBF_TEXT_(name, level, text...) \
        do { \
                if (iucv_dbf_passes(iucv_dbf_##name, level)) { \
-                       char* iucv_dbf_txt_buf = \
-                                       get_cpu_var(iucv_dbf_txt_buf); \
-                       sprintf(iucv_dbf_txt_buf, text); \
-                       debug_text_event(iucv_dbf_##name, level, \
-                                               iucv_dbf_txt_buf); \
+                       char* __buf = get_cpu_var(iucv_dbf_txt_buf); \
+                       sprintf(__buf, text); \
+                       debug_text_event(iucv_dbf_##name, level, __buf); \
                        put_cpu_var(iucv_dbf_txt_buf); \
                } \
        } while (0)
index 28fce65b85949709491a5c74d1e950d0b6b5b1ef..2d9d70359360719ea3851ee8ad33fba70f884635 100644 (file)
@@ -169,6 +169,12 @@ config SPI_OMAP24XX
          SPI master controller for OMAP24xx/OMAP34xx Multichannel SPI
          (McSPI) modules.
 
+config SPI_OMAP_100K
+       tristate "OMAP SPI 100K"
+       depends on SPI_MASTER && (ARCH_OMAP850 || ARCH_OMAP730)
+       help
+         OMAP SPI 100K master controller for omap7xx boards.
+
 config SPI_ORION
        tristate "Orion SPI master (EXPERIMENTAL)"
        depends on PLAT_ORION && EXPERIMENTAL
@@ -220,6 +226,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_SH_MSIOF
+       tristate "SuperH MSIOF SPI controller"
+       depends on SUPERH && HAVE_CLK
+       select SPI_BITBANG
+       help
+         SPI driver for SuperH MSIOF blocks.
+
 config SPI_SH_SCI
        tristate "SuperH SCI SPI controller"
        depends on SUPERH
@@ -240,15 +253,38 @@ config SPI_TXX9
          SPI driver for Toshiba TXx9 MIPS SoCs
 
 config SPI_XILINX
-       tristate "Xilinx SPI controller"
-       depends on (XILINX_VIRTEX || MICROBLAZE) && EXPERIMENTAL
+       tristate "Xilinx SPI controller common module"
+       depends on HAS_IOMEM && EXPERIMENTAL
        select SPI_BITBANG
+       select SPI_XILINX_OF if (XILINX_VIRTEX || MICROBLAZE)
        help
          This exposes the SPI controller IP from the Xilinx EDK.
 
          See the "OPB Serial Peripheral Interface (SPI) (v1.00e)"
          Product Specification document (DS464) for hardware details.
 
+         Or for the DS570, see "XPS Serial Peripheral Interface (SPI) (v2.00b)"
+
+config SPI_XILINX_OF
+       tristate "Xilinx SPI controller OF device"
+       depends on SPI_XILINX && (XILINX_VIRTEX || MICROBLAZE)
+       help
+         This is the OF driver for the SPI controller IP from the Xilinx EDK.
+
+config SPI_XILINX_PLTFM
+       tristate "Xilinx SPI controller platform device"
+       depends on SPI_XILINX
+       help
+         This is the platform driver for the SPI controller IP
+         from the Xilinx EDK.
+
+config SPI_NUC900
+       tristate "Nuvoton NUC900 series SPI"
+       depends on ARCH_W90X900 && EXPERIMENTAL
+       select SPI_BITBANG
+       help
+         SPI driver for Nuvoton NUC900 series ARM SoCs
+
 #
 # Add new SPI master controllers in alphabetical order above this line
 #
index e3f092a9afa5668d98e66479aa9c4dbf09b7479a..ed8c1675b52f8c1af6918eb016fe871b85ccf973 100644 (file)
@@ -22,6 +22,7 @@ obj-$(CONFIG_SPI_LM70_LLP)            += spi_lm70llp.o
 obj-$(CONFIG_SPI_PXA2XX)               += pxa2xx_spi.o
 obj-$(CONFIG_SPI_OMAP_UWIRE)           += omap_uwire.o
 obj-$(CONFIG_SPI_OMAP24XX)             += omap2_mcspi.o
+obj-$(CONFIG_SPI_OMAP_100K)            += omap_spi_100k.o
 obj-$(CONFIG_SPI_ORION)                        += orion_spi.o
 obj-$(CONFIG_SPI_PL022)                        += amba-pl022.o
 obj-$(CONFIG_SPI_MPC52xx_PSC)          += mpc52xx_psc_spi.o
@@ -32,8 +33,12 @@ obj-$(CONFIG_SPI_S3C24XX_GPIO)               += spi_s3c24xx_gpio.o
 obj-$(CONFIG_SPI_S3C24XX)              += spi_s3c24xx.o
 obj-$(CONFIG_SPI_TXX9)                 += spi_txx9.o
 obj-$(CONFIG_SPI_XILINX)               += xilinx_spi.o
+obj-$(CONFIG_SPI_XILINX_OF)            += xilinx_spi_of.o
+obj-$(CONFIG_SPI_XILINX_PLTFM)         += xilinx_spi_pltfm.o
 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
 #      ... add above this line ...
 
 # SPI protocol drivers (device/link on bus)
index 76cbc1a66598a87ad32fcfbcd3207c59f296a175..cfd5ff9508fadd2f607d33495b5066cc34b1bbd1 100644 (file)
@@ -237,8 +237,14 @@ static int au1550_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t)
        unsigned bpw, hz;
        u32 cfg, stat;
 
-       bpw = t ? t->bits_per_word : spi->bits_per_word;
-       hz = t ? t->speed_hz : spi->max_speed_hz;
+       bpw = spi->bits_per_word;
+       hz = spi->max_speed_hz;
+       if (t) {
+               if (t->bits_per_word)
+                       bpw = t->bits_per_word;
+               if (t->speed_hz)
+                       hz = t->speed_hz;
+       }
 
        if (bpw < 4 || bpw > 24) {
                dev_err(&spi->dev, "setupxfer: invalid bits_per_word=%d\n",
index ef8379b2c172a0aad58e7a176cc9ebb8e29017b1..45bfe645817332f7a3754237815c263e909582ea 100644 (file)
@@ -18,9 +18,9 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/spi/spi.h>
-#include <linux/spi/mpc52xx_spi.h>
 #include <linux/of_spi.h>
 #include <linux/io.h>
+#include <linux/of_gpio.h>
 #include <asm/time.h>
 #include <asm/mpc52xx.h>
 
@@ -53,7 +53,7 @@ MODULE_LICENSE("GPL");
 /* FSM state return values */
 #define FSM_STOP       0       /* Nothing more for the state machine to */
                                /* do.  If something interesting happens */
-                               /* then and IRQ will be received */
+                               /* then an IRQ will be received */
 #define FSM_POLL       1       /* need to poll for completion, an IRQ is */
                                /* not expected */
 #define FSM_CONTINUE   2       /* Keep iterating the state machine */
@@ -61,13 +61,12 @@ MODULE_LICENSE("GPL");
 /* Driver internal data */
 struct mpc52xx_spi {
        struct spi_master *master;
-       u32 sysclk;
        void __iomem *regs;
        int irq0;       /* MODF irq */
        int irq1;       /* SPIF irq */
-       int ipb_freq;
+       unsigned int ipb_freq;
 
-       /* Statistics */
+       /* Statistics; not used now, but will be reintroduced for debugfs */
        int msg_count;
        int wcol_count;
        int wcol_ticks;
@@ -79,7 +78,6 @@ struct mpc52xx_spi {
        spinlock_t lock;
        struct work_struct work;
 
-
        /* Details of current transfer (length, and buffer pointers) */
        struct spi_message *message;    /* current message */
        struct spi_transfer *transfer;  /* current transfer */
@@ -89,6 +87,8 @@ struct mpc52xx_spi {
        u8 *rx_buf;
        const u8 *tx_buf;
        int cs_change;
+       int gpio_cs_count;
+       unsigned int *gpio_cs;
 };
 
 /*
@@ -96,7 +96,13 @@ struct mpc52xx_spi {
  */
 static void mpc52xx_spi_chipsel(struct mpc52xx_spi *ms, int value)
 {
-       out_8(ms->regs + SPI_PORTDATA, value ? 0 : 0x08);
+       int cs;
+
+       if (ms->gpio_cs_count > 0) {
+               cs = ms->message->spi->chip_select;
+               gpio_set_value(ms->gpio_cs[cs], value ? 0 : 1);
+       } else
+               out_8(ms->regs + SPI_PORTDATA, value ? 0 : 0x08);
 }
 
 /*
@@ -221,7 +227,7 @@ static int mpc52xx_spi_fsmstate_transfer(int irq, struct mpc52xx_spi *ms,
                ms->wcol_tx_timestamp = get_tbl();
                data = 0;
                if (ms->tx_buf)
-                       data = *(ms->tx_buf-1);
+                       data = *(ms->tx_buf - 1);
                out_8(ms->regs + SPI_DATA, data); /* try again */
                return FSM_CONTINUE;
        } else if (status & SPI_STATUS_MODF) {
@@ -390,7 +396,9 @@ static int __devinit mpc52xx_spi_probe(struct of_device *op,
        struct spi_master *master;
        struct mpc52xx_spi *ms;
        void __iomem *regs;
-       int rc;
+       u8 ctrl1;
+       int rc, i = 0;
+       int gpio_cs;
 
        /* MMIO registers */
        dev_dbg(&op->dev, "probing mpc5200 SPI device\n");
@@ -399,7 +407,8 @@ static int __devinit mpc52xx_spi_probe(struct of_device *op,
                return -ENODEV;
 
        /* initialize the device */
-       out_8(regs+SPI_CTRL1, SPI_CTRL1_SPIE | SPI_CTRL1_SPE | SPI_CTRL1_MSTR);
+       ctrl1 = SPI_CTRL1_SPIE | SPI_CTRL1_SPE | SPI_CTRL1_MSTR;
+       out_8(regs + SPI_CTRL1, ctrl1);
        out_8(regs + SPI_CTRL2, 0x0);
        out_8(regs + SPI_DATADIR, 0xe); /* Set output pins */
        out_8(regs + SPI_PORTDATA, 0x8);        /* Deassert /SS signal */
@@ -409,6 +418,8 @@ static int __devinit mpc52xx_spi_probe(struct of_device *op,
         * on the SPI bus.  This fault will also occur if the SPI signals
         * are not connected to any pins (port_config setting) */
        in_8(regs + SPI_STATUS);
+       out_8(regs + SPI_CTRL1, ctrl1);
+
        in_8(regs + SPI_DATA);
        if (in_8(regs + SPI_STATUS) & SPI_STATUS_MODF) {
                dev_err(&op->dev, "mode fault; is port_config correct?\n");
@@ -422,10 +433,12 @@ static int __devinit mpc52xx_spi_probe(struct of_device *op,
                rc = -ENOMEM;
                goto err_alloc;
        }
+
        master->bus_num = -1;
-       master->num_chipselect = 1;
        master->setup = mpc52xx_spi_setup;
        master->transfer = mpc52xx_spi_transfer;
+       master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
+
        dev_set_drvdata(&op->dev, master);
 
        ms = spi_master_get_devdata(master);
@@ -435,16 +448,51 @@ static int __devinit mpc52xx_spi_probe(struct of_device *op,
        ms->irq1 = irq_of_parse_and_map(op->node, 1);
        ms->state = mpc52xx_spi_fsmstate_idle;
        ms->ipb_freq = mpc5xxx_get_bus_frequency(op->node);
+       ms->gpio_cs_count = of_gpio_count(op->node);
+       if (ms->gpio_cs_count > 0) {
+               master->num_chipselect = ms->gpio_cs_count;
+               ms->gpio_cs = kmalloc(ms->gpio_cs_count * sizeof(unsigned int),
+                               GFP_KERNEL);
+               if (!ms->gpio_cs) {
+                       rc = -ENOMEM;
+                       goto err_alloc;
+               }
+
+               for (i = 0; i < ms->gpio_cs_count; i++) {
+                       gpio_cs = of_get_gpio(op->node, i);
+                       if (gpio_cs < 0) {
+                               dev_err(&op->dev,
+                                       "could not parse the gpio field "
+                                       "in oftree\n");
+                               rc = -ENODEV;
+                               goto err_gpio;
+                       }
+
+                       rc = gpio_request(gpio_cs, dev_name(&op->dev));
+                       if (rc) {
+                               dev_err(&op->dev,
+                                       "can't request spi cs gpio #%d "
+                                       "on gpio line %d\n", i, gpio_cs);
+                               goto err_gpio;
+                       }
+
+                       gpio_direction_output(gpio_cs, 1);
+                       ms->gpio_cs[i] = gpio_cs;
+               }
+       } else {
+               master->num_chipselect = 1;
+       }
+
        spin_lock_init(&ms->lock);
        INIT_LIST_HEAD(&ms->queue);
        INIT_WORK(&ms->work, mpc52xx_spi_wq);
 
        /* Decide if interrupts can be used */
        if (ms->irq0 && ms->irq1) {
-               rc = request_irq(ms->irq0, mpc52xx_spi_irq, IRQF_SAMPLE_RANDOM,
+               rc = request_irq(ms->irq0, mpc52xx_spi_irq, 0,
                                  "mpc5200-spi-modf", ms);
-               rc |= request_irq(ms->irq1, mpc52xx_spi_irq, IRQF_SAMPLE_RANDOM,
-                                 "mpc5200-spi-spiF", ms);
+               rc |= request_irq(ms->irq1, mpc52xx_spi_irq, 0,
+                                 "mpc5200-spi-spif", ms);
                if (rc) {
                        free_irq(ms->irq0, ms);
                        free_irq(ms->irq1, ms);
@@ -471,6 +519,11 @@ static int __devinit mpc52xx_spi_probe(struct of_device *op,
  err_register:
        dev_err(&ms->master->dev, "initialization failed\n");
        spi_master_put(master);
+ err_gpio:
+       while (i-- > 0)
+               gpio_free(ms->gpio_cs[i]);
+
+       kfree(ms->gpio_cs);
  err_alloc:
  err_init:
        iounmap(regs);
@@ -481,10 +534,15 @@ static int __devexit mpc52xx_spi_remove(struct of_device *op)
 {
        struct spi_master *master = dev_get_drvdata(&op->dev);
        struct mpc52xx_spi *ms = spi_master_get_devdata(master);
+       int i;
 
        free_irq(ms->irq0, ms);
        free_irq(ms->irq1, ms);
 
+       for (i = 0; i < ms->gpio_cs_count; i++)
+               gpio_free(ms->gpio_cs[i]);
+
+       kfree(ms->gpio_cs);
        spi_unregister_master(master);
        spi_master_put(master);
        iounmap(ms->regs);
diff --git a/drivers/spi/omap_spi_100k.c b/drivers/spi/omap_spi_100k.c
new file mode 100644 (file)
index 0000000..5355d90
--- /dev/null
@@ -0,0 +1,635 @@
+/*
+ * OMAP7xx SPI 100k controller driver
+ * Author: Fabrice Crohas <fcrohas@gmail.com>
+ * from original omap1_mcspi driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation
+ * Author:      Samuel Ortiz <samuel.ortiz@nokia.com> and
+ *              Juha Yrj�l� <juha.yrjola@nokia.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/interrupt.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#include <linux/spi/spi.h>
+
+#include <plat/clock.h>
+
+#define OMAP1_SPI100K_MAX_FREQ          48000000
+
+#define ICR_SPITAS      (OMAP7XX_ICR_BASE + 0x12)
+
+#define SPI_SETUP1      0x00
+#define SPI_SETUP2      0x02
+#define SPI_CTRL        0x04
+#define SPI_STATUS      0x06
+#define SPI_TX_LSB      0x08
+#define SPI_TX_MSB      0x0a
+#define SPI_RX_LSB      0x0c
+#define SPI_RX_MSB      0x0e
+
+#define SPI_SETUP1_INT_READ_ENABLE      (1UL << 5)
+#define SPI_SETUP1_INT_WRITE_ENABLE     (1UL << 4)
+#define SPI_SETUP1_CLOCK_DIVISOR(x)     ((x) << 1)
+#define SPI_SETUP1_CLOCK_ENABLE         (1UL << 0)
+
+#define SPI_SETUP2_ACTIVE_EDGE_FALLING  (0UL << 0)
+#define SPI_SETUP2_ACTIVE_EDGE_RISING   (1UL << 0)
+#define SPI_SETUP2_NEGATIVE_LEVEL       (0UL << 5)
+#define SPI_SETUP2_POSITIVE_LEVEL       (1UL << 5)
+#define SPI_SETUP2_LEVEL_TRIGGER        (0UL << 10)
+#define SPI_SETUP2_EDGE_TRIGGER         (1UL << 10)
+
+#define SPI_CTRL_SEN(x)                 ((x) << 7)
+#define SPI_CTRL_WORD_SIZE(x)           (((x) - 1) << 2)
+#define SPI_CTRL_WR                     (1UL << 1)
+#define SPI_CTRL_RD                     (1UL << 0)
+
+#define SPI_STATUS_WE                   (1UL << 1)
+#define SPI_STATUS_RD                   (1UL << 0)
+
+#define WRITE 0
+#define READ  1
+
+
+/* use PIO for small transfers, avoiding DMA setup/teardown overhead and
+ * cache operations; better heuristics consider wordsize and bitrate.
+ */
+#define DMA_MIN_BYTES                   8
+
+#define SPI_RUNNING    0
+#define SPI_SHUTDOWN   1
+
+struct omap1_spi100k {
+       struct work_struct      work;
+
+       /* lock protects queue and registers */
+       spinlock_t              lock;
+       struct list_head        msg_queue;
+       struct spi_master       *master;
+       struct clk              *ick;
+       struct clk              *fck;
+
+       /* Virtual base address of the controller */
+       void __iomem            *base;
+
+       /* State of the SPI */
+       unsigned int            state;
+};
+
+struct omap1_spi100k_cs {
+       void __iomem            *base;
+       int                     word_len;
+};
+
+static struct workqueue_struct *omap1_spi100k_wq;
+
+#define MOD_REG_BIT(val, mask, set) do { \
+       if (set) \
+               val |= mask; \
+       else \
+               val &= ~mask; \
+} while (0)
+
+static void spi100k_enable_clock(struct spi_master *master)
+{
+       unsigned int val;
+       struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
+
+       /* enable SPI */
+       val = readw(spi100k->base + SPI_SETUP1);
+       val |= SPI_SETUP1_CLOCK_ENABLE;
+       writew(val, spi100k->base + SPI_SETUP1);
+}
+
+static void spi100k_disable_clock(struct spi_master *master)
+{
+       unsigned int val;
+       struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
+
+       /* disable SPI */
+       val = readw(spi100k->base + SPI_SETUP1);
+       val &= ~SPI_SETUP1_CLOCK_ENABLE;
+       writew(val, spi100k->base + SPI_SETUP1);
+}
+
+static void spi100k_write_data(struct spi_master *master, int len, int data)
+{
+       struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
+
+       /* write 16-bit word */
+       spi100k_enable_clock(master);
+       writew( data , spi100k->base + SPI_TX_MSB);
+
+       writew(SPI_CTRL_SEN(0) |
+              SPI_CTRL_WORD_SIZE(len) |
+              SPI_CTRL_WR,
+              spi100k->base + SPI_CTRL);
+
+       /* Wait for bit ack send change */
+       while((readw(spi100k->base + SPI_STATUS) & SPI_STATUS_WE) != SPI_STATUS_WE);
+       udelay(1000);
+
+       spi100k_disable_clock(master);
+}
+
+static int spi100k_read_data(struct spi_master *master, int len)
+{
+       int dataH,dataL;
+       struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
+
+       spi100k_enable_clock(master);
+       writew(SPI_CTRL_SEN(0) |
+              SPI_CTRL_WORD_SIZE(len) |
+              SPI_CTRL_RD,
+              spi100k->base + SPI_CTRL);
+
+       while((readw(spi100k->base + SPI_STATUS) & SPI_STATUS_RD) != SPI_STATUS_RD);
+       udelay(1000);
+
+       dataL = readw(spi100k->base + SPI_RX_LSB);
+       dataH = readw(spi100k->base + SPI_RX_MSB);
+       spi100k_disable_clock(master);
+
+       return dataL;
+}
+
+static void spi100k_open(struct spi_master *master)
+{
+       /* get control of SPI */
+       struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
+
+       writew(SPI_SETUP1_INT_READ_ENABLE |
+              SPI_SETUP1_INT_WRITE_ENABLE |
+              SPI_SETUP1_CLOCK_DIVISOR(0), spi100k->base + SPI_SETUP1);
+
+       /* configure clock and interrupts */
+       writew(SPI_SETUP2_ACTIVE_EDGE_FALLING |
+              SPI_SETUP2_NEGATIVE_LEVEL |
+              SPI_SETUP2_LEVEL_TRIGGER, spi100k->base + SPI_SETUP2);
+}
+
+static void omap1_spi100k_force_cs(struct omap1_spi100k *spi100k, int enable)
+{
+       if (enable)
+               writew(0x05fc, spi100k->base + SPI_CTRL);
+       else
+               writew(0x05fd, spi100k->base + SPI_CTRL);
+}
+
+static unsigned
+omap1_spi100k_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
+{
+       struct omap1_spi100k    *spi100k;
+       struct omap1_spi100k_cs *cs = spi->controller_state;
+       unsigned int            count, c;
+       int                     word_len;
+
+       spi100k = spi_master_get_devdata(spi->master);
+       count = xfer->len;
+       c = count;
+       word_len = cs->word_len;
+
+       /* RX_ONLY mode needs dummy data in TX reg */
+       if (xfer->tx_buf == NULL)
+               spi100k_write_data(spi->master,word_len, 0);
+
+       if (word_len <= 8) {
+               u8              *rx;
+               const u8        *tx;
+
+               rx = xfer->rx_buf;
+               tx = xfer->tx_buf;
+               do {
+                       c-=1;
+                       if (xfer->tx_buf != NULL)
+                               spi100k_write_data(spi->master,word_len, *tx);
+                       if (xfer->rx_buf != NULL)
+                               *rx = spi100k_read_data(spi->master,word_len);
+               } while(c);
+       } else if (word_len <= 16) {
+               u16             *rx;
+               const u16       *tx;
+
+               rx = xfer->rx_buf;
+               tx = xfer->tx_buf;
+               do {
+                       c-=2;
+                       if (xfer->tx_buf != NULL)
+                               spi100k_write_data(spi->master,word_len, *tx++);
+                       if (xfer->rx_buf != NULL)
+                               *rx++ = spi100k_read_data(spi->master,word_len);
+               } while(c);
+       } else if (word_len <= 32) {
+               u32             *rx;
+               const u32       *tx;
+
+               rx = xfer->rx_buf;
+               tx = xfer->tx_buf;
+               do {
+                       c-=4;
+                       if (xfer->tx_buf != NULL)
+                               spi100k_write_data(spi->master,word_len, *tx);
+                       if (xfer->rx_buf != NULL)
+                               *rx = spi100k_read_data(spi->master,word_len);
+               } while(c);
+       }
+       return count - c;
+}
+
+/* called only when no transfer is active to this device */
+static int omap1_spi100k_setup_transfer(struct spi_device *spi,
+               struct spi_transfer *t)
+{
+       struct omap1_spi100k *spi100k = spi_master_get_devdata(spi->master);
+       struct omap1_spi100k_cs *cs = spi->controller_state;
+       u8 word_len = spi->bits_per_word;
+
+       if (t != NULL && t->bits_per_word)
+               word_len = t->bits_per_word;
+       if (!word_len)
+               word_len = 8;
+
+       if (spi->bits_per_word > 32)
+               return -EINVAL;
+       cs->word_len = word_len;
+
+       /* SPI init before transfer */
+       writew(0x3e , spi100k->base + SPI_SETUP1);
+       writew(0x00 , spi100k->base + SPI_STATUS);
+       writew(0x3e , spi100k->base + SPI_CTRL);
+
+       return 0;
+}
+
+/* the spi->mode bits understood by this driver: */
+#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH)
+
+static int omap1_spi100k_setup(struct spi_device *spi)
+{
+       int                     ret;
+       struct omap1_spi100k    *spi100k;
+       struct omap1_spi100k_cs *cs = spi->controller_state;
+
+       if (spi->bits_per_word < 4 || spi->bits_per_word > 32) {
+                dev_dbg(&spi->dev, "setup: unsupported %d bit words\n",
+                       spi->bits_per_word);
+                return -EINVAL;
+       }
+
+       spi100k = spi_master_get_devdata(spi->master);
+
+       if (!cs) {
+               cs = kzalloc(sizeof *cs, GFP_KERNEL);
+               if (!cs)
+                       return -ENOMEM;
+               cs->base = spi100k->base + spi->chip_select * 0x14;
+               spi->controller_state = cs;
+       }
+
+       spi100k_open(spi->master);
+
+       clk_enable(spi100k->ick);
+       clk_enable(spi100k->fck);
+
+       ret = omap1_spi100k_setup_transfer(spi, NULL);
+
+       clk_disable(spi100k->ick);
+       clk_disable(spi100k->fck);
+
+       return ret;
+}
+
+static void omap1_spi100k_work(struct work_struct *work)
+{
+       struct omap1_spi100k    *spi100k;
+       int status = 0;
+
+       spi100k = container_of(work, struct omap1_spi100k, work);
+       spin_lock_irq(&spi100k->lock);
+
+       clk_enable(spi100k->ick);
+       clk_enable(spi100k->fck);
+
+       /* We only enable one channel at a time -- the one whose message is
+        * at the head of the queue -- although this controller would gladly
+        * arbitrate among multiple channels.  This corresponds to "single
+        * channel" master mode.  As a side effect, we need to manage the
+        * chipselect with the FORCE bit ... CS != channel enable.
+        */
+        while (!list_empty(&spi100k->msg_queue)) {
+               struct spi_message              *m;
+               struct spi_device               *spi;
+               struct spi_transfer             *t = NULL;
+               int                             cs_active = 0;
+               struct omap1_spi100k_cs         *cs;
+               int                             par_override = 0;
+
+               m = container_of(spi100k->msg_queue.next, struct spi_message,
+                                queue);
+
+               list_del_init(&m->queue);
+               spin_unlock_irq(&spi100k->lock);
+
+               spi = m->spi;
+               cs = spi->controller_state;
+
+               list_for_each_entry(t, &m->transfers, transfer_list) {
+                       if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
+                               status = -EINVAL;
+                               break;
+                       }
+                       if (par_override || t->speed_hz || t->bits_per_word) {
+                               par_override = 1;
+                               status = omap1_spi100k_setup_transfer(spi, t);
+                               if (status < 0)
+                                       break;
+                               if (!t->speed_hz && !t->bits_per_word)
+                                       par_override = 0;
+                       }
+
+                       if (!cs_active) {
+                               omap1_spi100k_force_cs(spi100k, 1);
+                               cs_active = 1;
+                       }
+
+                       if (t->len) {
+                               unsigned count;
+
+                               /* RX_ONLY mode needs dummy data in TX reg */
+                               if (t->tx_buf == NULL)
+                                       spi100k_write_data(spi->master, 8, 0);
+
+                               count = omap1_spi100k_txrx_pio(spi, t);
+                               m->actual_length += count;
+
+                               if (count != t->len) {
+                                       status = -EIO;
+                                       break;
+                               }
+                       }
+
+                       if (t->delay_usecs)
+                               udelay(t->delay_usecs);
+
+                       /* ignore the "leave it on after last xfer" hint */
+
+                       if (t->cs_change) {
+                               omap1_spi100k_force_cs(spi100k, 0);
+                               cs_active = 0;
+                       }
+               }
+
+               /* Restore defaults if they were overriden */
+               if (par_override) {
+                       par_override = 0;
+                       status = omap1_spi100k_setup_transfer(spi, NULL);
+               }
+
+               if (cs_active)
+                       omap1_spi100k_force_cs(spi100k, 0);
+
+               m->status = status;
+               m->complete(m->context);
+
+               spin_lock_irq(&spi100k->lock);
+       }
+
+       clk_disable(spi100k->ick);
+       clk_disable(spi100k->fck);
+       spin_unlock_irq(&spi100k->lock);
+
+       if (status < 0)
+               printk(KERN_WARNING "spi transfer failed with %d\n", status);
+}
+
+static int omap1_spi100k_transfer(struct spi_device *spi, struct spi_message *m)
+{
+       struct omap1_spi100k    *spi100k;
+       unsigned long           flags;
+       struct spi_transfer     *t;
+
+       m->actual_length = 0;
+       m->status = -EINPROGRESS;
+
+       spi100k = spi_master_get_devdata(spi->master);
+
+       /* Don't accept new work if we're shutting down */
+       if (spi100k->state == SPI_SHUTDOWN)
+               return -ESHUTDOWN;
+
+       /* reject invalid messages and transfers */
+       if (list_empty(&m->transfers) || !m->complete)
+               return -EINVAL;
+
+       list_for_each_entry(t, &m->transfers, transfer_list) {
+               const void      *tx_buf = t->tx_buf;
+               void            *rx_buf = t->rx_buf;
+               unsigned        len = t->len;
+
+               if (t->speed_hz > OMAP1_SPI100K_MAX_FREQ
+                               || (len && !(rx_buf || tx_buf))
+                               || (t->bits_per_word &&
+                                       (  t->bits_per_word < 4
+                                       || t->bits_per_word > 32))) {
+                       dev_dbg(&spi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
+                                       t->speed_hz,
+                                       len,
+                                       tx_buf ? "tx" : "",
+                                       rx_buf ? "rx" : "",
+                                       t->bits_per_word);
+                       return -EINVAL;
+               }
+
+               if (t->speed_hz && t->speed_hz < OMAP1_SPI100K_MAX_FREQ/(1<<16)) {
+                       dev_dbg(&spi->dev, "%d Hz max exceeds %d\n",
+                                       t->speed_hz,
+                                       OMAP1_SPI100K_MAX_FREQ/(1<<16));
+                       return -EINVAL;
+               }
+
+       }
+
+       spin_lock_irqsave(&spi100k->lock, flags);
+       list_add_tail(&m->queue, &spi100k->msg_queue);
+       queue_work(omap1_spi100k_wq, &spi100k->work);
+       spin_unlock_irqrestore(&spi100k->lock, flags);
+
+       return 0;
+}
+
+static int __init omap1_spi100k_reset(struct omap1_spi100k *spi100k)
+{
+       return 0;
+}
+
+static int __devinit omap1_spi100k_probe(struct platform_device *pdev)
+{
+       struct spi_master       *master;
+       struct omap1_spi100k    *spi100k;
+       int                     status = 0;
+
+       if (!pdev->id)
+               return -EINVAL;
+
+       master = spi_alloc_master(&pdev->dev, sizeof *spi100k);
+       if (master == NULL) {
+               dev_dbg(&pdev->dev, "master allocation failed\n");
+               return -ENOMEM;
+       }
+
+       if (pdev->id != -1)
+              master->bus_num = pdev->id;
+
+       master->setup = omap1_spi100k_setup;
+       master->transfer = omap1_spi100k_transfer;
+       master->cleanup = NULL;
+       master->num_chipselect = 2;
+       master->mode_bits = MODEBITS;
+
+       dev_set_drvdata(&pdev->dev, master);
+
+       spi100k = spi_master_get_devdata(master);
+       spi100k->master = master;
+
+       /*
+        * The memory region base address is taken as the platform_data.
+        * You should allocate this with ioremap() before initializing
+        * the SPI.
+        */
+       spi100k->base = (void __iomem *) pdev->dev.platform_data;
+
+       INIT_WORK(&spi100k->work, omap1_spi100k_work);
+
+       spin_lock_init(&spi100k->lock);
+       INIT_LIST_HEAD(&spi100k->msg_queue);
+       spi100k->ick = clk_get(&pdev->dev, "ick");
+       if (IS_ERR(spi100k->ick)) {
+               dev_dbg(&pdev->dev, "can't get spi100k_ick\n");
+               status = PTR_ERR(spi100k->ick);
+               goto err1;
+       }
+
+       spi100k->fck = clk_get(&pdev->dev, "fck");
+       if (IS_ERR(spi100k->fck)) {
+               dev_dbg(&pdev->dev, "can't get spi100k_fck\n");
+               status = PTR_ERR(spi100k->fck);
+               goto err2;
+       }
+
+       if (omap1_spi100k_reset(spi100k) < 0)
+               goto err3;
+
+       status = spi_register_master(master);
+       if (status < 0)
+               goto err3;
+
+       spi100k->state = SPI_RUNNING;
+
+       return status;
+
+err3:
+       clk_put(spi100k->fck);
+err2:
+       clk_put(spi100k->ick);
+err1:
+       spi_master_put(master);
+       return status;
+}
+
+static int __exit omap1_spi100k_remove(struct platform_device *pdev)
+{
+       struct spi_master       *master;
+       struct omap1_spi100k    *spi100k;
+       struct resource         *r;
+       unsigned                limit = 500;
+       unsigned long           flags;
+       int                     status = 0;
+
+       master = dev_get_drvdata(&pdev->dev);
+       spi100k = spi_master_get_devdata(master);
+
+       spin_lock_irqsave(&spi100k->lock, flags);
+
+       spi100k->state = SPI_SHUTDOWN;
+       while (!list_empty(&spi100k->msg_queue) && limit--) {
+               spin_unlock_irqrestore(&spi100k->lock, flags);
+               msleep(10);
+               spin_lock_irqsave(&spi100k->lock, flags);
+       }
+
+       if (!list_empty(&spi100k->msg_queue))
+               status = -EBUSY;
+
+       spin_unlock_irqrestore(&spi100k->lock, flags);
+
+       if (status != 0)
+               return status;
+
+       clk_put(spi100k->fck);
+       clk_put(spi100k->ick);
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       spi_unregister_master(master);
+
+       return 0;
+}
+
+static struct platform_driver omap1_spi100k_driver = {
+       .driver = {
+               .name           = "omap1_spi100k",
+               .owner          = THIS_MODULE,
+       },
+       .remove         = __exit_p(omap1_spi100k_remove),
+};
+
+
+static int __init omap1_spi100k_init(void)
+{
+       omap1_spi100k_wq = create_singlethread_workqueue(
+                       omap1_spi100k_driver.driver.name);
+
+       if (omap1_spi100k_wq == NULL)
+               return -1;
+
+       return platform_driver_probe(&omap1_spi100k_driver, omap1_spi100k_probe);
+}
+
+static void __exit omap1_spi100k_exit(void)
+{
+       platform_driver_unregister(&omap1_spi100k_driver);
+
+       destroy_workqueue(omap1_spi100k_wq);
+}
+
+module_init(omap1_spi100k_init);
+module_exit(omap1_spi100k_exit);
+
+MODULE_DESCRIPTION("OMAP7xx SPI 100k controller driver");
+MODULE_AUTHOR("Fabrice Crohas <fcrohas@gmail.com>");
+MODULE_LICENSE("GPL");
+
index 89c22efedfb0db8102339a06a35847205424771a..1893f1e96dc4906da0a92d1d4de38492781faa53 100644 (file)
@@ -44,6 +44,9 @@
 #define MXC_CSPIINT            0x0c
 #define MXC_RESET              0x1c
 
+#define MX3_CSPISTAT           0x14
+#define MX3_CSPISTAT_RR                (1 << 3)
+
 /* generic defines to abstract from the different register layouts */
 #define MXC_INT_RR     (1 << 0) /* Receive data ready interrupt */
 #define MXC_INT_TE     (1 << 1) /* Transmit FIFO empty interrupt */
@@ -205,7 +208,7 @@ static int mx31_config(struct spi_imx_data *spi_imx,
 
        if (cpu_is_mx31())
                reg |= (config->bpw - 1) << MX31_CSPICTRL_BC_SHIFT;
-       else if (cpu_is_mx35()) {
+       else if (cpu_is_mx25() || cpu_is_mx35()) {
                reg |= (config->bpw - 1) << MX35_CSPICTRL_BL_SHIFT;
                reg |= MX31_CSPICTRL_SSCTL;
        }
@@ -219,7 +222,7 @@ static int mx31_config(struct spi_imx_data *spi_imx,
        if (config->cs < 0) {
                if (cpu_is_mx31())
                        reg |= (config->cs + 32) << MX31_CSPICTRL_CS_SHIFT;
-               else if (cpu_is_mx35())
+               else if (cpu_is_mx25() || cpu_is_mx35())
                        reg |= (config->cs + 32) << MX35_CSPICTRL_CS_SHIFT;
        }
 
@@ -481,7 +484,7 @@ static void spi_imx_cleanup(struct spi_device *spi)
 {
 }
 
-static int __init spi_imx_probe(struct platform_device *pdev)
+static int __devinit spi_imx_probe(struct platform_device *pdev)
 {
        struct spi_imx_master *mxc_platform_info;
        struct spi_master *master;
@@ -489,7 +492,7 @@ static int __init spi_imx_probe(struct platform_device *pdev)
        struct resource *res;
        int i, ret;
 
-       mxc_platform_info = (struct spi_imx_master *)pdev->dev.platform_data;
+       mxc_platform_info = dev_get_platdata(&pdev->dev);
        if (!mxc_platform_info) {
                dev_err(&pdev->dev, "can't get the platform data\n");
                return -EINVAL;
@@ -513,11 +516,12 @@ static int __init spi_imx_probe(struct platform_device *pdev)
                        continue;
                ret = gpio_request(spi_imx->chipselect[i], DRIVER_NAME);
                if (ret) {
-                       i--;
-                       while (i > 0)
+                       while (i > 0) {
+                               i--;
                                if (spi_imx->chipselect[i] >= 0)
-                                       gpio_free(spi_imx->chipselect[i--]);
-                       dev_err(&pdev->dev, "can't get cs gpios");
+                                       gpio_free(spi_imx->chipselect[i]);
+                       }
+                       dev_err(&pdev->dev, "can't get cs gpios\n");
                        goto out_master_put;
                }
        }
@@ -551,7 +555,7 @@ static int __init spi_imx_probe(struct platform_device *pdev)
        }
 
        spi_imx->irq = platform_get_irq(pdev, 0);
-       if (!spi_imx->irq) {
+       if (spi_imx->irq <= 0) {
                ret = -EINVAL;
                goto out_iounmap;
        }
@@ -562,7 +566,7 @@ static int __init spi_imx_probe(struct platform_device *pdev)
                goto out_iounmap;
        }
 
-       if (cpu_is_mx31() || cpu_is_mx35()) {
+       if (cpu_is_mx25() || cpu_is_mx31() || cpu_is_mx35()) {
                spi_imx->intctrl = mx31_intctrl;
                spi_imx->config = mx31_config;
                spi_imx->trigger = mx31_trigger;
@@ -590,9 +594,14 @@ static int __init spi_imx_probe(struct platform_device *pdev)
        clk_enable(spi_imx->clk);
        spi_imx->spi_clk = clk_get_rate(spi_imx->clk);
 
-       if (!cpu_is_mx31() || !cpu_is_mx35())
+       if (cpu_is_mx1() || cpu_is_mx21() || cpu_is_mx27())
                writel(1, spi_imx->base + MXC_RESET);
 
+       /* drain receive buffer */
+       if (cpu_is_mx25() || cpu_is_mx31() || cpu_is_mx35())
+               while (readl(spi_imx->base + MX3_CSPISTAT) & MX3_CSPISTAT_RR)
+                       readl(spi_imx->base + MXC_CSPIRXDATA);
+
        spi_imx->intctrl(spi_imx, 0);
 
        ret = spi_bitbang_start(&spi_imx->bitbang);
@@ -625,7 +634,7 @@ out_master_put:
        return ret;
 }
 
-static int __exit spi_imx_remove(struct platform_device *pdev)
+static int __devexit spi_imx_remove(struct platform_device *pdev)
 {
        struct spi_master *master = platform_get_drvdata(pdev);
        struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -659,7 +668,7 @@ static struct platform_driver spi_imx_driver = {
                   .owner = THIS_MODULE,
                   },
        .probe = spi_imx_probe,
-       .remove = __exit_p(spi_imx_remove),
+       .remove = __devexit_p(spi_imx_remove),
 };
 
 static int __init spi_imx_init(void)
index 930135dc73baffd70c526518eba4d9eeee9f9b27..e9390d747bfcf35e018747fcfc6a1b2e529ef486 100644 (file)
@@ -1356,7 +1356,7 @@ static int __devexit plat_mpc8xxx_spi_remove(struct platform_device *pdev)
 MODULE_ALIAS("platform:mpc8xxx_spi");
 static struct platform_driver mpc8xxx_spi_driver = {
        .probe = plat_mpc8xxx_spi_probe,
-       .remove = __exit_p(plat_mpc8xxx_spi_remove),
+       .remove = __devexit_p(plat_mpc8xxx_spi_remove),
        .driver = {
                .name = "mpc8xxx_spi",
                .owner = THIS_MODULE,
diff --git a/drivers/spi/spi_nuc900.c b/drivers/spi/spi_nuc900.c
new file mode 100644 (file)
index 0000000..b319f9b
--- /dev/null
@@ -0,0 +1,504 @@
+/* linux/drivers/spi/spi_nuc900.c
+ *
+ * Copyright (c) 2009 Nuvoton technology.
+ * Wan ZongShun <mcuos.com@gmail.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/init.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+
+#include <mach/nuc900_spi.h>
+
+/* usi registers offset */
+#define USI_CNT                0x00
+#define USI_DIV                0x04
+#define USI_SSR                0x08
+#define USI_RX0                0x10
+#define USI_TX0                0x10
+
+/* usi register bit */
+#define ENINT          (0x01 << 17)
+#define ENFLG          (0x01 << 16)
+#define TXNUM          (0x03 << 8)
+#define TXNEG          (0x01 << 2)
+#define RXNEG          (0x01 << 1)
+#define LSB            (0x01 << 10)
+#define SELECTLEV      (0x01 << 2)
+#define SELECTPOL      (0x01 << 31)
+#define SELECTSLAVE    0x01
+#define GOBUSY         0x01
+
+struct nuc900_spi {
+       struct spi_bitbang       bitbang;
+       struct completion        done;
+       void __iomem            *regs;
+       int                      irq;
+       int                      len;
+       int                      count;
+       const unsigned char     *tx;
+       unsigned char           *rx;
+       struct clk              *clk;
+       struct resource         *ioarea;
+       struct spi_master       *master;
+       struct spi_device       *curdev;
+       struct device           *dev;
+       struct nuc900_spi_info *pdata;
+       spinlock_t              lock;
+       struct resource         *res;
+};
+
+static inline struct nuc900_spi *to_hw(struct spi_device *sdev)
+{
+       return spi_master_get_devdata(sdev->master);
+}
+
+static void nuc900_slave_select(struct spi_device *spi, unsigned int ssr)
+{
+       struct nuc900_spi *hw = to_hw(spi);
+       unsigned int val;
+       unsigned int cs = spi->mode & SPI_CS_HIGH ? 1 : 0;
+       unsigned int cpol = spi->mode & SPI_CPOL ? 1 : 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&hw->lock, flags);
+
+       val = __raw_readl(hw->regs + USI_SSR);
+
+       if (!cs)
+               val &= ~SELECTLEV;
+       else
+               val |= SELECTLEV;
+
+       if (!ssr)
+               val &= ~SELECTSLAVE;
+       else
+               val |= SELECTSLAVE;
+
+       __raw_writel(val, hw->regs + USI_SSR);
+
+       val = __raw_readl(hw->regs + USI_CNT);
+
+       if (!cpol)
+               val &= ~SELECTPOL;
+       else
+               val |= SELECTPOL;
+
+       __raw_writel(val, hw->regs + USI_CNT);
+
+       spin_unlock_irqrestore(&hw->lock, flags);
+}
+
+static void nuc900_spi_chipsel(struct spi_device *spi, int value)
+{
+       switch (value) {
+       case BITBANG_CS_INACTIVE:
+               nuc900_slave_select(spi, 0);
+               break;
+
+       case BITBANG_CS_ACTIVE:
+               nuc900_slave_select(spi, 1);
+               break;
+       }
+}
+
+static void nuc900_spi_setup_txnum(struct nuc900_spi *hw,
+                                                       unsigned int txnum)
+{
+       unsigned int val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&hw->lock, flags);
+
+       val = __raw_readl(hw->regs + USI_CNT);
+
+       if (!txnum)
+               val &= ~TXNUM;
+       else
+               val |= txnum << 0x08;
+
+       __raw_writel(val, hw->regs + USI_CNT);
+
+       spin_unlock_irqrestore(&hw->lock, flags);
+
+}
+
+static void nuc900_spi_setup_txbitlen(struct nuc900_spi *hw,
+                                                       unsigned int txbitlen)
+{
+       unsigned int val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&hw->lock, flags);
+
+       val = __raw_readl(hw->regs + USI_CNT);
+
+       val |= (txbitlen << 0x03);
+
+       __raw_writel(val, hw->regs + USI_CNT);
+
+       spin_unlock_irqrestore(&hw->lock, flags);
+}
+
+static void nuc900_spi_gobusy(struct nuc900_spi *hw)
+{
+       unsigned int val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&hw->lock, flags);
+
+       val = __raw_readl(hw->regs + USI_CNT);
+
+       val |= GOBUSY;
+
+       __raw_writel(val, hw->regs + USI_CNT);
+
+       spin_unlock_irqrestore(&hw->lock, flags);
+}
+
+static int nuc900_spi_setupxfer(struct spi_device *spi,
+                                struct spi_transfer *t)
+{
+       return 0;
+}
+
+static int nuc900_spi_setup(struct spi_device *spi)
+{
+       return 0;
+}
+
+static inline unsigned int hw_txbyte(struct nuc900_spi *hw, int count)
+{
+       return hw->tx ? hw->tx[count] : 0;
+}
+
+static int nuc900_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
+{
+       struct nuc900_spi *hw = to_hw(spi);
+
+       hw->tx = t->tx_buf;
+       hw->rx = t->rx_buf;
+       hw->len = t->len;
+       hw->count = 0;
+
+       __raw_writel(hw_txbyte(hw, 0x0), hw->regs + USI_TX0);
+
+       nuc900_spi_gobusy(hw);
+
+       wait_for_completion(&hw->done);
+
+       return hw->count;
+}
+
+static irqreturn_t nuc900_spi_irq(int irq, void *dev)
+{
+       struct nuc900_spi *hw = dev;
+       unsigned int status;
+       unsigned int count = hw->count;
+
+       status = __raw_readl(hw->regs + USI_CNT);
+       __raw_writel(status, hw->regs + USI_CNT);
+
+       if (status & ENFLG) {
+               hw->count++;
+
+               if (hw->rx)
+                       hw->rx[count] = __raw_readl(hw->regs + USI_RX0);
+               count++;
+
+               if (count < hw->len) {
+                       __raw_writel(hw_txbyte(hw, count), hw->regs + USI_TX0);
+                       nuc900_spi_gobusy(hw);
+               } else {
+                       complete(&hw->done);
+               }
+
+               return IRQ_HANDLED;
+       }
+
+       complete(&hw->done);
+       return IRQ_HANDLED;
+}
+
+static void nuc900_tx_edge(struct nuc900_spi *hw, unsigned int edge)
+{
+       unsigned int val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&hw->lock, flags);
+
+       val = __raw_readl(hw->regs + USI_CNT);
+
+       if (edge)
+               val |= TXNEG;
+       else
+               val &= ~TXNEG;
+       __raw_writel(val, hw->regs + USI_CNT);
+
+       spin_unlock_irqrestore(&hw->lock, flags);
+}
+
+static void nuc900_rx_edge(struct nuc900_spi *hw, unsigned int edge)
+{
+       unsigned int val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&hw->lock, flags);
+
+       val = __raw_readl(hw->regs + USI_CNT);
+
+       if (edge)
+               val |= RXNEG;
+       else
+               val &= ~RXNEG;
+       __raw_writel(val, hw->regs + USI_CNT);
+
+       spin_unlock_irqrestore(&hw->lock, flags);
+}
+
+static void nuc900_send_first(struct nuc900_spi *hw, unsigned int lsb)
+{
+       unsigned int val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&hw->lock, flags);
+
+       val = __raw_readl(hw->regs + USI_CNT);
+
+       if (lsb)
+               val |= LSB;
+       else
+               val &= ~LSB;
+       __raw_writel(val, hw->regs + USI_CNT);
+
+       spin_unlock_irqrestore(&hw->lock, flags);
+}
+
+static void nuc900_set_sleep(struct nuc900_spi *hw, unsigned int sleep)
+{
+       unsigned int val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&hw->lock, flags);
+
+       val = __raw_readl(hw->regs + USI_CNT);
+
+       if (sleep)
+               val |= (sleep << 12);
+       else
+               val &= ~(0x0f << 12);
+       __raw_writel(val, hw->regs + USI_CNT);
+
+       spin_unlock_irqrestore(&hw->lock, flags);
+}
+
+static void nuc900_enable_int(struct nuc900_spi *hw)
+{
+       unsigned int val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&hw->lock, flags);
+
+       val = __raw_readl(hw->regs + USI_CNT);
+
+       val |= ENINT;
+
+       __raw_writel(val, hw->regs + USI_CNT);
+
+       spin_unlock_irqrestore(&hw->lock, flags);
+}
+
+static void nuc900_set_divider(struct nuc900_spi *hw)
+{
+       __raw_writel(hw->pdata->divider, hw->regs + USI_DIV);
+}
+
+static void nuc900_init_spi(struct nuc900_spi *hw)
+{
+       clk_enable(hw->clk);
+       spin_lock_init(&hw->lock);
+
+       nuc900_tx_edge(hw, hw->pdata->txneg);
+       nuc900_rx_edge(hw, hw->pdata->rxneg);
+       nuc900_send_first(hw, hw->pdata->lsb);
+       nuc900_set_sleep(hw, hw->pdata->sleep);
+       nuc900_spi_setup_txbitlen(hw, hw->pdata->txbitlen);
+       nuc900_spi_setup_txnum(hw, hw->pdata->txnum);
+       nuc900_set_divider(hw);
+       nuc900_enable_int(hw);
+}
+
+static int __devinit nuc900_spi_probe(struct platform_device *pdev)
+{
+       struct nuc900_spi *hw;
+       struct spi_master *master;
+       int err = 0;
+
+       master = spi_alloc_master(&pdev->dev, sizeof(struct nuc900_spi));
+       if (master == NULL) {
+               dev_err(&pdev->dev, "No memory for spi_master\n");
+               err = -ENOMEM;
+               goto err_nomem;
+       }
+
+       hw = spi_master_get_devdata(master);
+       memset(hw, 0, sizeof(struct nuc900_spi));
+
+       hw->master = spi_master_get(master);
+       hw->pdata  = pdev->dev.platform_data;
+       hw->dev = &pdev->dev;
+
+       if (hw->pdata == NULL) {
+               dev_err(&pdev->dev, "No platform data supplied\n");
+               err = -ENOENT;
+               goto err_pdata;
+       }
+
+       platform_set_drvdata(pdev, hw);
+       init_completion(&hw->done);
+
+       master->mode_bits          = SPI_MODE_0;
+       master->num_chipselect     = hw->pdata->num_cs;
+       master->bus_num            = hw->pdata->bus_num;
+       hw->bitbang.master         = hw->master;
+       hw->bitbang.setup_transfer = nuc900_spi_setupxfer;
+       hw->bitbang.chipselect     = nuc900_spi_chipsel;
+       hw->bitbang.txrx_bufs      = nuc900_spi_txrx;
+       hw->bitbang.master->setup  = nuc900_spi_setup;
+
+       hw->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (hw->res == NULL) {
+               dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
+               err = -ENOENT;
+               goto err_pdata;
+       }
+
+       hw->ioarea = request_mem_region(hw->res->start,
+                                       resource_size(hw->res), pdev->name);
+
+       if (hw->ioarea == NULL) {
+               dev_err(&pdev->dev, "Cannot reserve region\n");
+               err = -ENXIO;
+               goto err_pdata;
+       }
+
+       hw->regs = ioremap(hw->res->start, resource_size(hw->res));
+       if (hw->regs == NULL) {
+               dev_err(&pdev->dev, "Cannot map IO\n");
+               err = -ENXIO;
+               goto err_iomap;
+       }
+
+       hw->irq = platform_get_irq(pdev, 0);
+       if (hw->irq < 0) {
+               dev_err(&pdev->dev, "No IRQ specified\n");
+               err = -ENOENT;
+               goto err_irq;
+       }
+
+       err = request_irq(hw->irq, nuc900_spi_irq, 0, pdev->name, hw);
+       if (err) {
+               dev_err(&pdev->dev, "Cannot claim IRQ\n");
+               goto err_irq;
+       }
+
+       hw->clk = clk_get(&pdev->dev, "spi");
+       if (IS_ERR(hw->clk)) {
+               dev_err(&pdev->dev, "No clock for device\n");
+               err = PTR_ERR(hw->clk);
+               goto err_clk;
+       }
+
+       mfp_set_groupg(&pdev->dev);
+       nuc900_init_spi(hw);
+
+       err = spi_bitbang_start(&hw->bitbang);
+       if (err) {
+               dev_err(&pdev->dev, "Failed to register SPI master\n");
+               goto err_register;
+       }
+
+       return 0;
+
+err_register:
+       clk_disable(hw->clk);
+       clk_put(hw->clk);
+err_clk:
+       free_irq(hw->irq, hw);
+err_irq:
+       iounmap(hw->regs);
+err_iomap:
+       release_mem_region(hw->res->start, resource_size(hw->res));
+       kfree(hw->ioarea);
+err_pdata:
+       spi_master_put(hw->master);;
+
+err_nomem:
+       return err;
+}
+
+static int __devexit nuc900_spi_remove(struct platform_device *dev)
+{
+       struct nuc900_spi *hw = platform_get_drvdata(dev);
+
+       free_irq(hw->irq, hw);
+
+       platform_set_drvdata(dev, NULL);
+
+       spi_unregister_master(hw->master);
+
+       clk_disable(hw->clk);
+       clk_put(hw->clk);
+
+       iounmap(hw->regs);
+
+       release_mem_region(hw->res->start, resource_size(hw->res));
+       kfree(hw->ioarea);
+
+       spi_master_put(hw->master);
+       return 0;
+}
+
+static struct platform_driver nuc900_spi_driver = {
+       .probe          = nuc900_spi_probe,
+       .remove         = __devexit_p(nuc900_spi_remove),
+       .driver         = {
+               .name   = "nuc900-spi",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init nuc900_spi_init(void)
+{
+       return platform_driver_register(&nuc900_spi_driver);
+}
+
+static void __exit nuc900_spi_exit(void)
+{
+       platform_driver_unregister(&nuc900_spi_driver);
+}
+
+module_init(nuc900_spi_init);
+module_exit(nuc900_spi_exit);
+
+MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
+MODULE_DESCRIPTION("nuc900 spi driver!");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:nuc900-spi");
diff --git a/drivers/spi/spi_sh_msiof.c b/drivers/spi/spi_sh_msiof.c
new file mode 100644 (file)
index 0000000..51e5e1d
--- /dev/null
@@ -0,0 +1,691 @@
+/*
+ * SuperH MSIOF SPI Master Interface
+ *
+ * Copyright (c) 2009 Magnus Damm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/completion.h>
+#include <linux/pm_runtime.h>
+#include <linux/gpio.h>
+#include <linux/bitmap.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+#include <linux/spi/sh_msiof.h>
+
+#include <asm/spi.h>
+#include <asm/unaligned.h>
+
+struct sh_msiof_spi_priv {
+       struct spi_bitbang bitbang; /* must be first for spi_bitbang.c */
+       void __iomem *mapbase;
+       struct clk *clk;
+       struct platform_device *pdev;
+       struct sh_msiof_spi_info *info;
+       struct completion done;
+       unsigned long flags;
+       int tx_fifo_size;
+       int rx_fifo_size;
+};
+
+#define TMDR1  0x00
+#define TMDR2  0x04
+#define TMDR3  0x08
+#define RMDR1  0x10
+#define RMDR2  0x14
+#define RMDR3  0x18
+#define TSCR   0x20
+#define RSCR   0x22
+#define CTR    0x28
+#define FCTR   0x30
+#define STR    0x40
+#define IER    0x44
+#define TDR1   0x48
+#define TDR2   0x4c
+#define TFDR   0x50
+#define RDR1   0x58
+#define RDR2   0x5c
+#define RFDR   0x60
+
+#define CTR_TSCKE (1 << 15)
+#define CTR_TFSE  (1 << 14)
+#define CTR_TXE   (1 << 9)
+#define CTR_RXE   (1 << 8)
+
+#define STR_TEOF  (1 << 23)
+#define STR_REOF  (1 << 7)
+
+static unsigned long sh_msiof_read(struct sh_msiof_spi_priv *p, int reg_offs)
+{
+       switch (reg_offs) {
+       case TSCR:
+       case RSCR:
+               return ioread16(p->mapbase + reg_offs);
+       default:
+               return ioread32(p->mapbase + reg_offs);
+       }
+}
+
+static void sh_msiof_write(struct sh_msiof_spi_priv *p, int reg_offs,
+                          unsigned long value)
+{
+       switch (reg_offs) {
+       case TSCR:
+       case RSCR:
+               iowrite16(value, p->mapbase + reg_offs);
+               break;
+       default:
+               iowrite32(value, p->mapbase + reg_offs);
+               break;
+       }
+}
+
+static int sh_msiof_modify_ctr_wait(struct sh_msiof_spi_priv *p,
+                                   unsigned long clr, unsigned long set)
+{
+       unsigned long mask = clr | set;
+       unsigned long data;
+       int k;
+
+       data = sh_msiof_read(p, CTR);
+       data &= ~clr;
+       data |= set;
+       sh_msiof_write(p, CTR, data);
+
+       for (k = 100; k > 0; k--) {
+               if ((sh_msiof_read(p, CTR) & mask) == set)
+                       break;
+
+               udelay(10);
+       }
+
+       return k > 0 ? 0 : -ETIMEDOUT;
+}
+
+static irqreturn_t sh_msiof_spi_irq(int irq, void *data)
+{
+       struct sh_msiof_spi_priv *p = data;
+
+       /* just disable the interrupt and wake up */
+       sh_msiof_write(p, IER, 0);
+       complete(&p->done);
+
+       return IRQ_HANDLED;
+}
+
+static struct {
+       unsigned short div;
+       unsigned short scr;
+} const sh_msiof_spi_clk_table[] = {
+       { 1, 0x0007 },
+       { 2, 0x0000 },
+       { 4, 0x0001 },
+       { 8, 0x0002 },
+       { 16, 0x0003 },
+       { 32, 0x0004 },
+       { 64, 0x1f00 },
+       { 128, 0x1f01 },
+       { 256, 0x1f02 },
+       { 512, 0x1f03 },
+       { 1024, 0x1f04 },
+};
+
+static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p,
+                                     unsigned long parent_rate,
+                                     unsigned long spi_hz)
+{
+       unsigned long div = 1024;
+       size_t k;
+
+       if (!WARN_ON(!spi_hz || !parent_rate))
+               div = parent_rate / spi_hz;
+
+       /* TODO: make more fine grained */
+
+       for (k = 0; k < ARRAY_SIZE(sh_msiof_spi_clk_table); k++) {
+               if (sh_msiof_spi_clk_table[k].div >= div)
+                       break;
+       }
+
+       k = min_t(int, k, ARRAY_SIZE(sh_msiof_spi_clk_table) - 1);
+
+       sh_msiof_write(p, TSCR, sh_msiof_spi_clk_table[k].scr);
+       sh_msiof_write(p, RSCR, sh_msiof_spi_clk_table[k].scr);
+}
+
+static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p,
+                                     int cpol, int cpha,
+                                     int tx_hi_z, int lsb_first)
+{
+       unsigned long tmp;
+       int edge;
+
+       /*
+        * CPOL CPHA     TSCKIZ RSCKIZ TEDG REDG(!)
+        *    0    0         10     10    1    0
+        *    0    1         10     10    0    1
+        *    1    0         11     11    0    1
+        *    1    1         11     11    1    0
+        *
+        * (!) Note: REDG is inverted recommended data sheet setting
+        */
+
+       sh_msiof_write(p, FCTR, 0);
+       sh_msiof_write(p, TMDR1, 0xe2000005 | (lsb_first << 24));
+       sh_msiof_write(p, RMDR1, 0x22000005 | (lsb_first << 24));
+
+       tmp = 0xa0000000;
+       tmp |= cpol << 30; /* TSCKIZ */
+       tmp |= cpol << 28; /* RSCKIZ */
+
+       edge = cpol ? cpha : !cpha;
+
+       tmp |= edge << 27; /* TEDG */
+       tmp |= !edge << 26; /* REDG */
+       tmp |= (tx_hi_z ? 2 : 0) << 22; /* TXDIZ */
+       sh_msiof_write(p, CTR, tmp);
+}
+
+static void sh_msiof_spi_set_mode_regs(struct sh_msiof_spi_priv *p,
+                                      const void *tx_buf, void *rx_buf,
+                                      int bits, int words)
+{
+       unsigned long dr2;
+
+       dr2 = ((bits - 1) << 24) | ((words - 1) << 16);
+
+       if (tx_buf)
+               sh_msiof_write(p, TMDR2, dr2);
+       else
+               sh_msiof_write(p, TMDR2, dr2 | 1);
+
+       if (rx_buf)
+               sh_msiof_write(p, RMDR2, dr2);
+
+       sh_msiof_write(p, IER, STR_TEOF | STR_REOF);
+}
+
+static void sh_msiof_reset_str(struct sh_msiof_spi_priv *p)
+{
+       sh_msiof_write(p, STR, sh_msiof_read(p, STR));
+}
+
+static void sh_msiof_spi_write_fifo_8(struct sh_msiof_spi_priv *p,
+                                     const void *tx_buf, int words, int fs)
+{
+       const unsigned char *buf_8 = tx_buf;
+       int k;
+
+       for (k = 0; k < words; k++)
+               sh_msiof_write(p, TFDR, buf_8[k] << fs);
+}
+
+static void sh_msiof_spi_write_fifo_16(struct sh_msiof_spi_priv *p,
+                                      const void *tx_buf, int words, int fs)
+{
+       const unsigned short *buf_16 = tx_buf;
+       int k;
+
+       for (k = 0; k < words; k++)
+               sh_msiof_write(p, TFDR, buf_16[k] << fs);
+}
+
+static void sh_msiof_spi_write_fifo_16u(struct sh_msiof_spi_priv *p,
+                                       const void *tx_buf, int words, int fs)
+{
+       const unsigned short *buf_16 = tx_buf;
+       int k;
+
+       for (k = 0; k < words; k++)
+               sh_msiof_write(p, TFDR, get_unaligned(&buf_16[k]) << fs);
+}
+
+static void sh_msiof_spi_write_fifo_32(struct sh_msiof_spi_priv *p,
+                                      const void *tx_buf, int words, int fs)
+{
+       const unsigned int *buf_32 = tx_buf;
+       int k;
+
+       for (k = 0; k < words; k++)
+               sh_msiof_write(p, TFDR, buf_32[k] << fs);
+}
+
+static void sh_msiof_spi_write_fifo_32u(struct sh_msiof_spi_priv *p,
+                                       const void *tx_buf, int words, int fs)
+{
+       const unsigned int *buf_32 = tx_buf;
+       int k;
+
+       for (k = 0; k < words; k++)
+               sh_msiof_write(p, TFDR, get_unaligned(&buf_32[k]) << fs);
+}
+
+static void sh_msiof_spi_read_fifo_8(struct sh_msiof_spi_priv *p,
+                                    void *rx_buf, int words, int fs)
+{
+       unsigned char *buf_8 = rx_buf;
+       int k;
+
+       for (k = 0; k < words; k++)
+               buf_8[k] = sh_msiof_read(p, RFDR) >> fs;
+}
+
+static void sh_msiof_spi_read_fifo_16(struct sh_msiof_spi_priv *p,
+                                     void *rx_buf, int words, int fs)
+{
+       unsigned short *buf_16 = rx_buf;
+       int k;
+
+       for (k = 0; k < words; k++)
+               buf_16[k] = sh_msiof_read(p, RFDR) >> fs;
+}
+
+static void sh_msiof_spi_read_fifo_16u(struct sh_msiof_spi_priv *p,
+                                      void *rx_buf, int words, int fs)
+{
+       unsigned short *buf_16 = rx_buf;
+       int k;
+
+       for (k = 0; k < words; k++)
+               put_unaligned(sh_msiof_read(p, RFDR) >> fs, &buf_16[k]);
+}
+
+static void sh_msiof_spi_read_fifo_32(struct sh_msiof_spi_priv *p,
+                                     void *rx_buf, int words, int fs)
+{
+       unsigned int *buf_32 = rx_buf;
+       int k;
+
+       for (k = 0; k < words; k++)
+               buf_32[k] = sh_msiof_read(p, RFDR) >> fs;
+}
+
+static void sh_msiof_spi_read_fifo_32u(struct sh_msiof_spi_priv *p,
+                                      void *rx_buf, int words, int fs)
+{
+       unsigned int *buf_32 = rx_buf;
+       int k;
+
+       for (k = 0; k < words; k++)
+               put_unaligned(sh_msiof_read(p, RFDR) >> fs, &buf_32[k]);
+}
+
+static int sh_msiof_spi_bits(struct spi_device *spi, struct spi_transfer *t)
+{
+       int bits;
+
+       bits = t ? t->bits_per_word : 0;
+       bits = bits ? bits : spi->bits_per_word;
+       return bits;
+}
+
+static unsigned long sh_msiof_spi_hz(struct spi_device *spi,
+                                    struct spi_transfer *t)
+{
+       unsigned long hz;
+
+       hz = t ? t->speed_hz : 0;
+       hz = hz ? hz : spi->max_speed_hz;
+       return hz;
+}
+
+static int sh_msiof_spi_setup_transfer(struct spi_device *spi,
+                                      struct spi_transfer *t)
+{
+       int bits;
+
+       /* noting to check hz values against since parent clock is disabled */
+
+       bits = sh_msiof_spi_bits(spi, t);
+       if (bits < 8)
+               return -EINVAL;
+       if (bits > 32)
+               return -EINVAL;
+
+       return spi_bitbang_setup_transfer(spi, t);
+}
+
+static void sh_msiof_spi_chipselect(struct spi_device *spi, int is_on)
+{
+       struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master);
+       int value;
+
+       /* chip select is active low unless SPI_CS_HIGH is set */
+       if (spi->mode & SPI_CS_HIGH)
+               value = (is_on == BITBANG_CS_ACTIVE) ? 1 : 0;
+       else
+               value = (is_on == BITBANG_CS_ACTIVE) ? 0 : 1;
+
+       if (is_on == BITBANG_CS_ACTIVE) {
+               if (!test_and_set_bit(0, &p->flags)) {
+                       pm_runtime_get_sync(&p->pdev->dev);
+                       clk_enable(p->clk);
+               }
+
+               /* Configure pins before asserting CS */
+               sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL),
+                                         !!(spi->mode & SPI_CPHA),
+                                         !!(spi->mode & SPI_3WIRE),
+                                         !!(spi->mode & SPI_LSB_FIRST));
+       }
+
+       /* use spi->controller data for CS (same strategy as spi_gpio) */
+       gpio_set_value((unsigned)spi->controller_data, value);
+
+       if (is_on == BITBANG_CS_INACTIVE) {
+               if (test_and_clear_bit(0, &p->flags)) {
+                       clk_disable(p->clk);
+                       pm_runtime_put(&p->pdev->dev);
+               }
+       }
+}
+
+static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p,
+                                 void (*tx_fifo)(struct sh_msiof_spi_priv *,
+                                                 const void *, int, int),
+                                 void (*rx_fifo)(struct sh_msiof_spi_priv *,
+                                                 void *, int, int),
+                                 const void *tx_buf, void *rx_buf,
+                                 int words, int bits)
+{
+       int fifo_shift;
+       int ret;
+
+       /* limit maximum word transfer to rx/tx fifo size */
+       if (tx_buf)
+               words = min_t(int, words, p->tx_fifo_size);
+       if (rx_buf)
+               words = min_t(int, words, p->rx_fifo_size);
+
+       /* the fifo contents need shifting */
+       fifo_shift = 32 - bits;
+
+       /* setup msiof transfer mode registers */
+       sh_msiof_spi_set_mode_regs(p, tx_buf, rx_buf, bits, words);
+
+       /* write tx fifo */
+       if (tx_buf)
+               tx_fifo(p, tx_buf, words, fifo_shift);
+
+       /* setup clock and rx/tx signals */
+       ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TSCKE);
+       if (rx_buf)
+               ret = ret ? ret : sh_msiof_modify_ctr_wait(p, 0, CTR_RXE);
+       ret = ret ? ret : sh_msiof_modify_ctr_wait(p, 0, CTR_TXE);
+
+       /* start by setting frame bit */
+       INIT_COMPLETION(p->done);
+       ret = ret ? ret : sh_msiof_modify_ctr_wait(p, 0, CTR_TFSE);
+       if (ret) {
+               dev_err(&p->pdev->dev, "failed to start hardware\n");
+               goto err;
+       }
+
+       /* wait for tx fifo to be emptied / rx fifo to be filled */
+       wait_for_completion(&p->done);
+
+       /* read rx fifo */
+       if (rx_buf)
+               rx_fifo(p, rx_buf, words, fifo_shift);
+
+       /* clear status bits */
+       sh_msiof_reset_str(p);
+
+       /* shut down frame, tx/tx and clock signals */
+       ret = sh_msiof_modify_ctr_wait(p, CTR_TFSE, 0);
+       ret = ret ? ret : sh_msiof_modify_ctr_wait(p, CTR_TXE, 0);
+       if (rx_buf)
+               ret = ret ? ret : sh_msiof_modify_ctr_wait(p, CTR_RXE, 0);
+       ret = ret ? ret : sh_msiof_modify_ctr_wait(p, CTR_TSCKE, 0);
+       if (ret) {
+               dev_err(&p->pdev->dev, "failed to shut down hardware\n");
+               goto err;
+       }
+
+       return words;
+
+ err:
+       sh_msiof_write(p, IER, 0);
+       return ret;
+}
+
+static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
+{
+       struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master);
+       void (*tx_fifo)(struct sh_msiof_spi_priv *, const void *, int, int);
+       void (*rx_fifo)(struct sh_msiof_spi_priv *, void *, int, int);
+       int bits;
+       int bytes_per_word;
+       int bytes_done;
+       int words;
+       int n;
+
+       bits = sh_msiof_spi_bits(spi, t);
+
+       /* setup bytes per word and fifo read/write functions */
+       if (bits <= 8) {
+               bytes_per_word = 1;
+               tx_fifo = sh_msiof_spi_write_fifo_8;
+               rx_fifo = sh_msiof_spi_read_fifo_8;
+       } else if (bits <= 16) {
+               bytes_per_word = 2;
+               if ((unsigned long)t->tx_buf & 0x01)
+                       tx_fifo = sh_msiof_spi_write_fifo_16u;
+               else
+                       tx_fifo = sh_msiof_spi_write_fifo_16;
+
+               if ((unsigned long)t->rx_buf & 0x01)
+                       rx_fifo = sh_msiof_spi_read_fifo_16u;
+               else
+                       rx_fifo = sh_msiof_spi_read_fifo_16;
+       } else {
+               bytes_per_word = 4;
+               if ((unsigned long)t->tx_buf & 0x03)
+                       tx_fifo = sh_msiof_spi_write_fifo_32u;
+               else
+                       tx_fifo = sh_msiof_spi_write_fifo_32;
+
+               if ((unsigned long)t->rx_buf & 0x03)
+                       rx_fifo = sh_msiof_spi_read_fifo_32u;
+               else
+                       rx_fifo = sh_msiof_spi_read_fifo_32;
+       }
+
+       /* setup clocks (clock already enabled in chipselect()) */
+       sh_msiof_spi_set_clk_regs(p, clk_get_rate(p->clk),
+                                 sh_msiof_spi_hz(spi, t));
+
+       /* transfer in fifo sized chunks */
+       words = t->len / bytes_per_word;
+       bytes_done = 0;
+
+       while (bytes_done < t->len) {
+               n = sh_msiof_spi_txrx_once(p, tx_fifo, rx_fifo,
+                                          t->tx_buf + bytes_done,
+                                          t->rx_buf + bytes_done,
+                                          words, bits);
+               if (n < 0)
+                       break;
+
+               bytes_done += n * bytes_per_word;
+               words -= n;
+       }
+
+       return bytes_done;
+}
+
+static u32 sh_msiof_spi_txrx_word(struct spi_device *spi, unsigned nsecs,
+                                 u32 word, u8 bits)
+{
+       BUG(); /* unused but needed by bitbang code */
+       return 0;
+}
+
+static int sh_msiof_spi_probe(struct platform_device *pdev)
+{
+       struct resource *r;
+       struct spi_master *master;
+       struct sh_msiof_spi_priv *p;
+       char clk_name[16];
+       int i;
+       int ret;
+
+       master = spi_alloc_master(&pdev->dev, sizeof(struct sh_msiof_spi_priv));
+       if (master == NULL) {
+               dev_err(&pdev->dev, "failed to allocate spi master\n");
+               ret = -ENOMEM;
+               goto err0;
+       }
+
+       p = spi_master_get_devdata(master);
+
+       platform_set_drvdata(pdev, p);
+       p->info = pdev->dev.platform_data;
+       init_completion(&p->done);
+
+       snprintf(clk_name, sizeof(clk_name), "msiof%d", pdev->id);
+       p->clk = clk_get(&pdev->dev, clk_name);
+       if (IS_ERR(p->clk)) {
+               dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
+               ret = PTR_ERR(p->clk);
+               goto err1;
+       }
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       i = platform_get_irq(pdev, 0);
+       if (!r || i < 0) {
+               dev_err(&pdev->dev, "cannot get platform resources\n");
+               ret = -ENOENT;
+               goto err2;
+       }
+       p->mapbase = ioremap_nocache(r->start, resource_size(r));
+       if (!p->mapbase) {
+               dev_err(&pdev->dev, "unable to ioremap\n");
+               ret = -ENXIO;
+               goto err2;
+       }
+
+       ret = request_irq(i, sh_msiof_spi_irq, IRQF_DISABLED,
+                         dev_name(&pdev->dev), p);
+       if (ret) {
+               dev_err(&pdev->dev, "unable to request irq\n");
+               goto err3;
+       }
+
+       p->pdev = pdev;
+       pm_runtime_enable(&pdev->dev);
+
+       /* The standard version of MSIOF use 64 word FIFOs */
+       p->tx_fifo_size = 64;
+       p->rx_fifo_size = 64;
+
+       /* Platform data may override FIFO sizes */
+       if (p->info->tx_fifo_override)
+               p->tx_fifo_size = p->info->tx_fifo_override;
+       if (p->info->rx_fifo_override)
+               p->rx_fifo_size = p->info->rx_fifo_override;
+
+       /* init master and bitbang code */
+       master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+       master->mode_bits |= SPI_LSB_FIRST | SPI_3WIRE;
+       master->flags = 0;
+       master->bus_num = pdev->id;
+       master->num_chipselect = p->info->num_chipselect;
+       master->setup = spi_bitbang_setup;
+       master->cleanup = spi_bitbang_cleanup;
+
+       p->bitbang.master = master;
+       p->bitbang.chipselect = sh_msiof_spi_chipselect;
+       p->bitbang.setup_transfer = sh_msiof_spi_setup_transfer;
+       p->bitbang.txrx_bufs = sh_msiof_spi_txrx;
+       p->bitbang.txrx_word[SPI_MODE_0] = sh_msiof_spi_txrx_word;
+       p->bitbang.txrx_word[SPI_MODE_1] = sh_msiof_spi_txrx_word;
+       p->bitbang.txrx_word[SPI_MODE_2] = sh_msiof_spi_txrx_word;
+       p->bitbang.txrx_word[SPI_MODE_3] = sh_msiof_spi_txrx_word;
+
+       ret = spi_bitbang_start(&p->bitbang);
+       if (ret == 0)
+               return 0;
+
+       pm_runtime_disable(&pdev->dev);
+ err3:
+       iounmap(p->mapbase);
+ err2:
+       clk_put(p->clk);
+ err1:
+       spi_master_put(master);
+ err0:
+       return ret;
+}
+
+static int sh_msiof_spi_remove(struct platform_device *pdev)
+{
+       struct sh_msiof_spi_priv *p = platform_get_drvdata(pdev);
+       int ret;
+
+       ret = spi_bitbang_stop(&p->bitbang);
+       if (!ret) {
+               pm_runtime_disable(&pdev->dev);
+               free_irq(platform_get_irq(pdev, 0), sh_msiof_spi_irq);
+               iounmap(p->mapbase);
+               clk_put(p->clk);
+               spi_master_put(p->bitbang.master);
+       }
+       return ret;
+}
+
+static int sh_msiof_spi_runtime_nop(struct device *dev)
+{
+       /* Runtime PM callback shared between ->runtime_suspend()
+        * and ->runtime_resume(). Simply returns success.
+        *
+        * This driver re-initializes all registers after
+        * pm_runtime_get_sync() anyway so there is no need
+        * to save and restore registers here.
+        */
+       return 0;
+}
+
+static struct dev_pm_ops sh_msiof_spi_dev_pm_ops = {
+       .runtime_suspend = sh_msiof_spi_runtime_nop,
+       .runtime_resume = sh_msiof_spi_runtime_nop,
+};
+
+static struct platform_driver sh_msiof_spi_drv = {
+       .probe          = sh_msiof_spi_probe,
+       .remove         = sh_msiof_spi_remove,
+       .driver         = {
+               .name           = "spi_sh_msiof",
+               .owner          = THIS_MODULE,
+               .pm             = &sh_msiof_spi_dev_pm_ops,
+       },
+};
+
+static int __init sh_msiof_spi_init(void)
+{
+       return platform_driver_register(&sh_msiof_spi_drv);
+}
+module_init(sh_msiof_spi_init);
+
+static void __exit sh_msiof_spi_exit(void)
+{
+       platform_driver_unregister(&sh_msiof_spi_drv);
+}
+module_exit(sh_msiof_spi_exit);
+
+MODULE_DESCRIPTION("SuperH MSIOF SPI Master Interface Driver");
+MODULE_AUTHOR("Magnus Damm");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:spi_sh_msiof");
index 20d7322e2f7163713a086e8dadd4c6e6213567bb..9c446e6003d5c16bae4b9b7c5cb589411bc79770 100644 (file)
@@ -266,15 +266,15 @@ static int spidev_message(struct spidev_data *spidev,
                k_tmp->delay_usecs = u_tmp->delay_usecs;
                k_tmp->speed_hz = u_tmp->speed_hz;
 #ifdef VERBOSE
-               dev_dbg(&spi->dev,
+               dev_dbg(&spidev->spi->dev,
                        "  xfer len %zd %s%s%s%dbits %u usec %uHz\n",
                        u_tmp->len,
                        u_tmp->rx_buf ? "rx " : "",
                        u_tmp->tx_buf ? "tx " : "",
                        u_tmp->cs_change ? "cs " : "",
-                       u_tmp->bits_per_word ? : spi->bits_per_word,
+                       u_tmp->bits_per_word ? : spidev->spi->bits_per_word,
                        u_tmp->delay_usecs,
-                       u_tmp->speed_hz ? : spi->max_speed_hz);
+                       u_tmp->speed_hz ? : spidev->spi->max_speed_hz);
 #endif
                spi_message_add_tail(k_tmp, &msg);
        }
index 5a143b9f63611278da3e00ea51894f22df558a61..9f386379c16974285c48c48932075d4025471b90 100644 (file)
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <linux/platform_device.h>
-
-#include <linux/of_platform.h>
-#include <linux/of_device.h>
-#include <linux/of_spi.h>
 
 #include <linux/spi/spi.h>
 #include <linux/spi/spi_bitbang.h>
 #include <linux/io.h>
 
+#include "xilinx_spi.h"
+#include <linux/spi/xilinx_spi.h>
+
 #define XILINX_SPI_NAME "xilinx_spi"
 
 /* Register definitions as per "OPB Serial Peripheral Interface (SPI) (v1.00e)
  * Product Specification", DS464
  */
-#define XSPI_CR_OFFSET         0x62    /* 16-bit Control Register */
+#define XSPI_CR_OFFSET         0x60    /* Control Register */
 
 #define XSPI_CR_ENABLE         0x02
 #define XSPI_CR_MASTER_MODE    0x04
@@ -40,8 +38,9 @@
 #define XSPI_CR_RXFIFO_RESET   0x40
 #define XSPI_CR_MANUAL_SSELECT 0x80
 #define XSPI_CR_TRANS_INHIBIT  0x100
+#define XSPI_CR_LSB_FIRST      0x200
 
-#define XSPI_SR_OFFSET         0x67    /* 8-bit Status Register */
+#define XSPI_SR_OFFSET         0x64    /* Status Register */
 
 #define XSPI_SR_RX_EMPTY_MASK  0x01    /* Receive FIFO is empty */
 #define XSPI_SR_RX_FULL_MASK   0x02    /* Receive FIFO is full */
@@ -49,8 +48,8 @@
 #define XSPI_SR_TX_FULL_MASK   0x08    /* Transmit FIFO is full */
 #define XSPI_SR_MODE_FAULT_MASK        0x10    /* Mode fault error */
 
-#define XSPI_TXD_OFFSET                0x6b    /* 8-bit Data Transmit Register */
-#define XSPI_RXD_OFFSET                0x6f    /* 8-bit Data Receive Register */
+#define XSPI_TXD_OFFSET                0x68    /* Data Transmit Register */
+#define XSPI_RXD_OFFSET                0x6c    /* Data Receive Register */
 
 #define XSPI_SSR_OFFSET                0x70    /* 32-bit Slave Select Register */
 
@@ -70,6 +69,7 @@
 #define XSPI_INTR_TX_UNDERRUN          0x08    /* TxFIFO was underrun */
 #define XSPI_INTR_RX_FULL              0x10    /* RxFIFO is full */
 #define XSPI_INTR_RX_OVERRUN           0x20    /* RxFIFO was overrun */
+#define XSPI_INTR_TX_HALF_EMPTY                0x40    /* TxFIFO is half empty */
 
 #define XIPIF_V123B_RESETR_OFFSET      0x40    /* IPIF reset register */
 #define XIPIF_V123B_RESET_MASK         0x0a    /* the value to write */
@@ -78,35 +78,85 @@ struct xilinx_spi {
        /* bitbang has to be first */
        struct spi_bitbang bitbang;
        struct completion done;
-
+       struct resource mem; /* phys mem */
        void __iomem    *regs;  /* virt. address of the control registers */
 
        u32             irq;
 
-       u32             speed_hz; /* SCK has a fixed frequency of speed_hz Hz */
-
        u8 *rx_ptr;             /* pointer in the Tx buffer */
        const u8 *tx_ptr;       /* pointer in the Rx buffer */
        int remaining_bytes;    /* the number of bytes left to transfer */
+       u8 bits_per_word;
+       unsigned int (*read_fn) (void __iomem *);
+       void (*write_fn) (u32, void __iomem *);
+       void (*tx_fn) (struct xilinx_spi *);
+       void (*rx_fn) (struct xilinx_spi *);
 };
 
-static void xspi_init_hw(void __iomem *regs_base)
+static void xspi_tx8(struct xilinx_spi *xspi)
+{
+       xspi->write_fn(*xspi->tx_ptr, xspi->regs + XSPI_TXD_OFFSET);
+       xspi->tx_ptr++;
+}
+
+static void xspi_tx16(struct xilinx_spi *xspi)
+{
+       xspi->write_fn(*(u16 *)(xspi->tx_ptr), xspi->regs + XSPI_TXD_OFFSET);
+       xspi->tx_ptr += 2;
+}
+
+static void xspi_tx32(struct xilinx_spi *xspi)
+{
+       xspi->write_fn(*(u32 *)(xspi->tx_ptr), xspi->regs + XSPI_TXD_OFFSET);
+       xspi->tx_ptr += 4;
+}
+
+static void xspi_rx8(struct xilinx_spi *xspi)
+{
+       u32 data = xspi->read_fn(xspi->regs + XSPI_RXD_OFFSET);
+       if (xspi->rx_ptr) {
+               *xspi->rx_ptr = data & 0xff;
+               xspi->rx_ptr++;
+       }
+}
+
+static void xspi_rx16(struct xilinx_spi *xspi)
 {
+       u32 data = xspi->read_fn(xspi->regs + XSPI_RXD_OFFSET);
+       if (xspi->rx_ptr) {
+               *(u16 *)(xspi->rx_ptr) = data & 0xffff;
+               xspi->rx_ptr += 2;
+       }
+}
+
+static void xspi_rx32(struct xilinx_spi *xspi)
+{
+       u32 data = xspi->read_fn(xspi->regs + XSPI_RXD_OFFSET);
+       if (xspi->rx_ptr) {
+               *(u32 *)(xspi->rx_ptr) = data;
+               xspi->rx_ptr += 4;
+       }
+}
+
+static void xspi_init_hw(struct xilinx_spi *xspi)
+{
+       void __iomem *regs_base = xspi->regs;
+
        /* Reset the SPI device */
-       out_be32(regs_base + XIPIF_V123B_RESETR_OFFSET,
-                XIPIF_V123B_RESET_MASK);
+       xspi->write_fn(XIPIF_V123B_RESET_MASK,
+               regs_base + XIPIF_V123B_RESETR_OFFSET);
        /* Disable all the interrupts just in case */
-       out_be32(regs_base + XIPIF_V123B_IIER_OFFSET, 0);
+       xspi->write_fn(0, regs_base + XIPIF_V123B_IIER_OFFSET);
        /* Enable the global IPIF interrupt */
-       out_be32(regs_base + XIPIF_V123B_DGIER_OFFSET,
-                XIPIF_V123B_GINTR_ENABLE);
+       xspi->write_fn(XIPIF_V123B_GINTR_ENABLE,
+               regs_base + XIPIF_V123B_DGIER_OFFSET);
        /* Deselect the slave on the SPI bus */
-       out_be32(regs_base + XSPI_SSR_OFFSET, 0xffff);
+       xspi->write_fn(0xffff, regs_base + XSPI_SSR_OFFSET);
        /* Disable the transmitter, enable Manual Slave Select Assertion,
         * put SPI controller into master mode, and enable it */
-       out_be16(regs_base + XSPI_CR_OFFSET,
-                XSPI_CR_TRANS_INHIBIT | XSPI_CR_MANUAL_SSELECT
-                | XSPI_CR_MASTER_MODE | XSPI_CR_ENABLE);
+       xspi->write_fn(XSPI_CR_TRANS_INHIBIT | XSPI_CR_MANUAL_SSELECT |
+               XSPI_CR_MASTER_MODE | XSPI_CR_ENABLE | XSPI_CR_TXFIFO_RESET |
+               XSPI_CR_RXFIFO_RESET, regs_base + XSPI_CR_OFFSET);
 }
 
 static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
@@ -115,16 +165,16 @@ static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
 
        if (is_on == BITBANG_CS_INACTIVE) {
                /* Deselect the slave on the SPI bus */
-               out_be32(xspi->regs + XSPI_SSR_OFFSET, 0xffff);
+               xspi->write_fn(0xffff, xspi->regs + XSPI_SSR_OFFSET);
        } else if (is_on == BITBANG_CS_ACTIVE) {
                /* Set the SPI clock phase and polarity */
-               u16 cr = in_be16(xspi->regs + XSPI_CR_OFFSET)
+               u16 cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET)
                         & ~XSPI_CR_MODE_MASK;
                if (spi->mode & SPI_CPHA)
                        cr |= XSPI_CR_CPHA;
                if (spi->mode & SPI_CPOL)
                        cr |= XSPI_CR_CPOL;
-               out_be16(xspi->regs + XSPI_CR_OFFSET, cr);
+               xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET);
 
                /* We do not check spi->max_speed_hz here as the SPI clock
                 * frequency is not software programmable (the IP block design
@@ -132,25 +182,27 @@ static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
                 */
 
                /* Activate the chip select */
-               out_be32(xspi->regs + XSPI_SSR_OFFSET,
-                        ~(0x0001 << spi->chip_select));
+               xspi->write_fn(~(0x0001 << spi->chip_select),
+                       xspi->regs + XSPI_SSR_OFFSET);
        }
 }
 
 /* spi_bitbang requires custom setup_transfer() to be defined if there is a
  * custom txrx_bufs(). We have nothing to setup here as the SPI IP block
- * supports just 8 bits per word, and SPI clock can't be changed in software.
- * Check for 8 bits per word. Chip select delay calculations could be
+ * supports 8 or 16 bits per word which cannot be changed in software.
+ * SPI clock can't be changed in software either.
+ * Check for correct bits per word. Chip select delay calculations could be
  * added here as soon as bitbang_work() can be made aware of the delay value.
  */
 static int xilinx_spi_setup_transfer(struct spi_device *spi,
                struct spi_transfer *t)
 {
+       struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
        u8 bits_per_word;
 
        bits_per_word = (t && t->bits_per_word)
                         ? t->bits_per_word : spi->bits_per_word;
-       if (bits_per_word != 8) {
+       if (bits_per_word != xspi->bits_per_word) {
                dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
                        __func__, bits_per_word);
                return -EINVAL;
@@ -161,17 +213,16 @@ static int xilinx_spi_setup_transfer(struct spi_device *spi,
 
 static int xilinx_spi_setup(struct spi_device *spi)
 {
-       struct spi_bitbang *bitbang;
-       struct xilinx_spi *xspi;
-       int retval;
-
-       xspi = spi_master_get_devdata(spi->master);
-       bitbang = &xspi->bitbang;
-
-       retval = xilinx_spi_setup_transfer(spi, NULL);
-       if (retval < 0)
-               return retval;
-
+       /* always return 0, we can not check the number of bits.
+        * There are cases when SPI setup is called before any driver is
+        * there, in that case the SPI core defaults to 8 bits, which we
+        * do not support in some cases. But if we return an error, the
+        * SPI device would not be registered and no driver can get hold of it
+        * When the driver is there, it will call SPI setup again with the
+        * correct number of bits per transfer.
+        * If a driver setups with the wrong bit number, it will fail when
+        * it tries to do a transfer
+        */
        return 0;
 }
 
@@ -180,15 +231,14 @@ static void xilinx_spi_fill_tx_fifo(struct xilinx_spi *xspi)
        u8 sr;
 
        /* Fill the Tx FIFO with as many bytes as possible */
-       sr = in_8(xspi->regs + XSPI_SR_OFFSET);
+       sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
        while ((sr & XSPI_SR_TX_FULL_MASK) == 0 && xspi->remaining_bytes > 0) {
-               if (xspi->tx_ptr) {
-                       out_8(xspi->regs + XSPI_TXD_OFFSET, *xspi->tx_ptr++);
-               } else {
-                       out_8(xspi->regs + XSPI_TXD_OFFSET, 0);
-               }
-               xspi->remaining_bytes--;
-               sr = in_8(xspi->regs + XSPI_SR_OFFSET);
+               if (xspi->tx_ptr)
+                       xspi->tx_fn(xspi);
+               else
+                       xspi->write_fn(0, xspi->regs + XSPI_TXD_OFFSET);
+               xspi->remaining_bytes -= xspi->bits_per_word / 8;
+               sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
        }
 }
 
@@ -210,18 +260,19 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
        /* Enable the transmit empty interrupt, which we use to determine
         * progress on the transmission.
         */
-       ipif_ier = in_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET);
-       out_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET,
-                ipif_ier | XSPI_INTR_TX_EMPTY);
+       ipif_ier = xspi->read_fn(xspi->regs + XIPIF_V123B_IIER_OFFSET);
+       xspi->write_fn(ipif_ier | XSPI_INTR_TX_EMPTY,
+               xspi->regs + XIPIF_V123B_IIER_OFFSET);
 
        /* Start the transfer by not inhibiting the transmitter any longer */
-       cr = in_be16(xspi->regs + XSPI_CR_OFFSET) & ~XSPI_CR_TRANS_INHIBIT;
-       out_be16(xspi->regs + XSPI_CR_OFFSET, cr);
+       cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET) &
+               ~XSPI_CR_TRANS_INHIBIT;
+       xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET);
 
        wait_for_completion(&xspi->done);
 
        /* Disable the transmit empty interrupt */
-       out_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET, ipif_ier);
+       xspi->write_fn(ipif_ier, xspi->regs + XIPIF_V123B_IIER_OFFSET);
 
        return t->len - xspi->remaining_bytes;
 }
@@ -238,8 +289,8 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
        u32 ipif_isr;
 
        /* Get the IPIF interrupts, and clear them immediately */
-       ipif_isr = in_be32(xspi->regs + XIPIF_V123B_IISR_OFFSET);
-       out_be32(xspi->regs + XIPIF_V123B_IISR_OFFSET, ipif_isr);
+       ipif_isr = xspi->read_fn(xspi->regs + XIPIF_V123B_IISR_OFFSET);
+       xspi->write_fn(ipif_isr, xspi->regs + XIPIF_V123B_IISR_OFFSET);
 
        if (ipif_isr & XSPI_INTR_TX_EMPTY) {    /* Transmission completed */
                u16 cr;
@@ -250,20 +301,15 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
                 * transmitter while the Isr refills the transmit register/FIFO,
                 * or make sure it is stopped if we're done.
                 */
-               cr = in_be16(xspi->regs + XSPI_CR_OFFSET);
-               out_be16(xspi->regs + XSPI_CR_OFFSET,
-                        cr | XSPI_CR_TRANS_INHIBIT);
+               cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET);
+               xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT,
+                       xspi->regs + XSPI_CR_OFFSET);
 
                /* Read out all the data from the Rx FIFO */
-               sr = in_8(xspi->regs + XSPI_SR_OFFSET);
+               sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
                while ((sr & XSPI_SR_RX_EMPTY_MASK) == 0) {
-                       u8 data;
-
-                       data = in_8(xspi->regs + XSPI_RXD_OFFSET);
-                       if (xspi->rx_ptr) {
-                               *xspi->rx_ptr++ = data;
-                       }
-                       sr = in_8(xspi->regs + XSPI_SR_OFFSET);
+                       xspi->rx_fn(xspi);
+                       sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
                }
 
                /* See if there is more data to send */
@@ -272,7 +318,7 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
                        /* Start the transfer by not inhibiting the
                         * transmitter any longer
                         */
-                       out_be16(xspi->regs + XSPI_CR_OFFSET, cr);
+                       xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET);
                } else {
                        /* No more data to send.
                         * Indicate the transfer is completed.
@@ -284,40 +330,22 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __init xilinx_spi_of_probe(struct of_device *ofdev,
-                                       const struct of_device_id *match)
+struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
+       u32 irq, s16 bus_num)
 {
        struct spi_master *master;
        struct xilinx_spi *xspi;
-       struct resource r_irq_struct;
-       struct resource r_mem_struct;
-
-       struct resource *r_irq = &r_irq_struct;
-       struct resource *r_mem = &r_mem_struct;
-       int rc = 0;
-       const u32 *prop;
-       int len;
-
-       /* Get resources(memory, IRQ) associated with the device */
-       master = spi_alloc_master(&ofdev->dev, sizeof(struct xilinx_spi));
+       struct xspi_platform_data *pdata = dev->platform_data;
+       int ret;
 
-       if (master == NULL) {
-               return -ENOMEM;
+       if (!pdata) {
+               dev_err(dev, "No platform data attached\n");
+               return NULL;
        }
 
-       dev_set_drvdata(&ofdev->dev, master);
-
-       rc = of_address_to_resource(ofdev->node, 0, r_mem);
-       if (rc) {
-               dev_warn(&ofdev->dev, "invalid address\n");
-               goto put_master;
-       }
-
-       rc = of_irq_to_resource(ofdev->node, 0, r_irq);
-       if (rc == NO_IRQ) {
-               dev_warn(&ofdev->dev, "no IRQ found\n");
-               goto put_master;
-       }
+       master = spi_alloc_master(dev, sizeof(struct xilinx_spi));
+       if (!master)
+               return NULL;
 
        /* the spi->mode bits understood by this driver: */
        master->mode_bits = SPI_CPOL | SPI_CPHA;
@@ -330,128 +358,87 @@ static int __init xilinx_spi_of_probe(struct of_device *ofdev,
        xspi->bitbang.master->setup = xilinx_spi_setup;
        init_completion(&xspi->done);
 
-       xspi->irq = r_irq->start;
-
-       if (!request_mem_region(r_mem->start,
-                       r_mem->end - r_mem->start + 1, XILINX_SPI_NAME)) {
-               rc = -ENXIO;
-               dev_warn(&ofdev->dev, "memory request failure\n");
+       if (!request_mem_region(mem->start, resource_size(mem),
+               XILINX_SPI_NAME))
                goto put_master;
-       }
 
-       xspi->regs = ioremap(r_mem->start, r_mem->end - r_mem->start + 1);
+       xspi->regs = ioremap(mem->start, resource_size(mem));
        if (xspi->regs == NULL) {
-               rc = -ENOMEM;
-               dev_warn(&ofdev->dev, "ioremap failure\n");
-               goto release_mem;
+               dev_warn(dev, "ioremap failure\n");
+               goto map_failed;
        }
-       xspi->irq = r_irq->start;
-
-       /* dynamic bus assignment */
-       master->bus_num = -1;
 
-       /* number of slave select bits is required */
-       prop = of_get_property(ofdev->node, "xlnx,num-ss-bits", &len);
-       if (!prop || len < sizeof(*prop)) {
-               dev_warn(&ofdev->dev, "no 'xlnx,num-ss-bits' property\n");
-               goto unmap_io;
+       master->bus_num = bus_num;
+       master->num_chipselect = pdata->num_chipselect;
+
+       xspi->mem = *mem;
+       xspi->irq = irq;
+       if (pdata->little_endian) {
+               xspi->read_fn = ioread32;
+               xspi->write_fn = iowrite32;
+       } else {
+               xspi->read_fn = ioread32be;
+               xspi->write_fn = iowrite32be;
        }
-       master->num_chipselect = *prop;
+       xspi->bits_per_word = pdata->bits_per_word;
+       if (xspi->bits_per_word == 8) {
+               xspi->tx_fn = xspi_tx8;
+               xspi->rx_fn = xspi_rx8;
+       } else if (xspi->bits_per_word == 16) {
+               xspi->tx_fn = xspi_tx16;
+               xspi->rx_fn = xspi_rx16;
+       } else if (xspi->bits_per_word == 32) {
+               xspi->tx_fn = xspi_tx32;
+               xspi->rx_fn = xspi_rx32;
+       } else
+               goto unmap_io;
+
 
        /* SPI controller initializations */
-       xspi_init_hw(xspi->regs);
+       xspi_init_hw(xspi);
 
        /* Register for SPI Interrupt */
-       rc = request_irq(xspi->irq, xilinx_spi_irq, 0, XILINX_SPI_NAME, xspi);
-       if (rc != 0) {
-               dev_warn(&ofdev->dev, "irq request failure: %d\n", xspi->irq);
+       ret = request_irq(xspi->irq, xilinx_spi_irq, 0, XILINX_SPI_NAME, xspi);
+       if (ret)
                goto unmap_io;
-       }
 
-       rc = spi_bitbang_start(&xspi->bitbang);
-       if (rc != 0) {
-               dev_err(&ofdev->dev, "spi_bitbang_start FAILED\n");
+       ret = spi_bitbang_start(&xspi->bitbang);
+       if (ret) {
+               dev_err(dev, "spi_bitbang_start FAILED\n");
                goto free_irq;
        }
 
-       dev_info(&ofdev->dev, "at 0x%08X mapped to 0x%08X, irq=%d\n",
-                       (unsigned int)r_mem->start, (u32)xspi->regs, xspi->irq);
-
-       /* Add any subnodes on the SPI bus */
-       of_register_spi_devices(master, ofdev->node);
-
-       return rc;
+       dev_info(dev, "at 0x%08llX mapped to 0x%p, irq=%d\n",
+               (unsigned long long)mem->start, xspi->regs, xspi->irq);
+       return master;
 
 free_irq:
        free_irq(xspi->irq, xspi);
 unmap_io:
        iounmap(xspi->regs);
-release_mem:
-       release_mem_region(r_mem->start, resource_size(r_mem));
+map_failed:
+       release_mem_region(mem->start, resource_size(mem));
 put_master:
        spi_master_put(master);
-       return rc;
+       return NULL;
 }
+EXPORT_SYMBOL(xilinx_spi_init);
 
-static int __devexit xilinx_spi_remove(struct of_device *ofdev)
+void xilinx_spi_deinit(struct spi_master *master)
 {
        struct xilinx_spi *xspi;
-       struct spi_master *master;
-       struct resource r_mem;
 
-       master = platform_get_drvdata(ofdev);
        xspi = spi_master_get_devdata(master);
 
        spi_bitbang_stop(&xspi->bitbang);
        free_irq(xspi->irq, xspi);
        iounmap(xspi->regs);
-       if (!of_address_to_resource(ofdev->node, 0, &r_mem))
-               release_mem_region(r_mem.start, resource_size(&r_mem));
-       dev_set_drvdata(&ofdev->dev, 0);
-       spi_master_put(xspi->bitbang.master);
-
-       return 0;
-}
-
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:" XILINX_SPI_NAME);
-
-static int __exit xilinx_spi_of_remove(struct of_device *op)
-{
-       return xilinx_spi_remove(op);
-}
 
-static struct of_device_id xilinx_spi_of_match[] = {
-       { .compatible = "xlnx,xps-spi-2.00.a", },
-       { .compatible = "xlnx,xps-spi-2.00.b", },
-       {}
-};
-
-MODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
-
-static struct of_platform_driver xilinx_spi_of_driver = {
-       .owner = THIS_MODULE,
-       .name = "xilinx-xps-spi",
-       .match_table = xilinx_spi_of_match,
-       .probe = xilinx_spi_of_probe,
-       .remove = __exit_p(xilinx_spi_of_remove),
-       .driver = {
-               .name = "xilinx-xps-spi",
-               .owner = THIS_MODULE,
-       },
-};
-
-static int __init xilinx_spi_init(void)
-{
-       return of_register_platform_driver(&xilinx_spi_of_driver);
+       release_mem_region(xspi->mem.start, resource_size(&xspi->mem));
+       spi_master_put(xspi->bitbang.master);
 }
-module_init(xilinx_spi_init);
+EXPORT_SYMBOL(xilinx_spi_deinit);
 
-static void __exit xilinx_spi_exit(void)
-{
-       of_unregister_platform_driver(&xilinx_spi_of_driver);
-}
-module_exit(xilinx_spi_exit);
 MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
 MODULE_DESCRIPTION("Xilinx SPI driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/spi/xilinx_spi.h b/drivers/spi/xilinx_spi.h
new file mode 100644 (file)
index 0000000..d211acc
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Xilinx SPI device driver API and platform data header file
+ *
+ * Copyright (c) 2009 Intel Corporation
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _XILINX_SPI_H_
+#define _XILINX_SPI_H_
+
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+
+#define XILINX_SPI_NAME "xilinx_spi"
+
+struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
+       u32 irq, s16 bus_num);
+
+void xilinx_spi_deinit(struct spi_master *master);
+#endif
diff --git a/drivers/spi/xilinx_spi_of.c b/drivers/spi/xilinx_spi_of.c
new file mode 100644 (file)
index 0000000..71dc3ad
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Xilinx SPI OF device driver
+ *
+ * Copyright (c) 2009 Intel Corporation
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Supports:
+ * Xilinx SPI devices as OF devices
+ *
+ * Inspired by xilinx_spi.c, 2002-2007 (c) MontaVista Software, Inc.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#include <linux/of_platform.h>
+#include <linux/of_device.h>
+#include <linux/of_spi.h>
+
+#include <linux/spi/xilinx_spi.h>
+#include "xilinx_spi.h"
+
+
+static int __devinit xilinx_spi_of_probe(struct of_device *ofdev,
+       const struct of_device_id *match)
+{
+       struct spi_master *master;
+       struct xspi_platform_data *pdata;
+       struct resource r_mem;
+       struct resource r_irq;
+       int rc = 0;
+       const u32 *prop;
+       int len;
+
+       rc = of_address_to_resource(ofdev->node, 0, &r_mem);
+       if (rc) {
+               dev_warn(&ofdev->dev, "invalid address\n");
+               return rc;
+       }
+
+       rc = of_irq_to_resource(ofdev->node, 0, &r_irq);
+       if (rc == NO_IRQ) {
+               dev_warn(&ofdev->dev, "no IRQ found\n");
+               return -ENODEV;
+       }
+
+       ofdev->dev.platform_data =
+               kzalloc(sizeof(struct xspi_platform_data), GFP_KERNEL);
+       pdata = ofdev->dev.platform_data;
+       if (!pdata)
+               return -ENOMEM;
+
+       /* number of slave select bits is required */
+       prop = of_get_property(ofdev->node, "xlnx,num-ss-bits", &len);
+       if (!prop || len < sizeof(*prop)) {
+               dev_warn(&ofdev->dev, "no 'xlnx,num-ss-bits' property\n");
+               return -EINVAL;
+       }
+       pdata->num_chipselect = *prop;
+       pdata->bits_per_word = 8;
+       master = xilinx_spi_init(&ofdev->dev, &r_mem, r_irq.start, -1);
+       if (!master)
+               return -ENODEV;
+
+       dev_set_drvdata(&ofdev->dev, master);
+
+       /* Add any subnodes on the SPI bus */
+       of_register_spi_devices(master, ofdev->node);
+
+       return 0;
+}
+
+static int __devexit xilinx_spi_remove(struct of_device *ofdev)
+{
+       xilinx_spi_deinit(dev_get_drvdata(&ofdev->dev));
+       dev_set_drvdata(&ofdev->dev, 0);
+       kfree(ofdev->dev.platform_data);
+       ofdev->dev.platform_data = NULL;
+       return 0;
+}
+
+static int __exit xilinx_spi_of_remove(struct of_device *op)
+{
+       return xilinx_spi_remove(op);
+}
+
+static struct of_device_id xilinx_spi_of_match[] = {
+       { .compatible = "xlnx,xps-spi-2.00.a", },
+       { .compatible = "xlnx,xps-spi-2.00.b", },
+       {}
+};
+
+MODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
+
+static struct of_platform_driver xilinx_spi_of_driver = {
+       .match_table = xilinx_spi_of_match,
+       .probe = xilinx_spi_of_probe,
+       .remove = __exit_p(xilinx_spi_of_remove),
+       .driver = {
+               .name = "xilinx-xps-spi",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init xilinx_spi_of_init(void)
+{
+       return of_register_platform_driver(&xilinx_spi_of_driver);
+}
+module_init(xilinx_spi_of_init);
+
+static void __exit xilinx_spi_of_exit(void)
+{
+       of_unregister_platform_driver(&xilinx_spi_of_driver);
+}
+module_exit(xilinx_spi_of_exit);
+
+MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
+MODULE_DESCRIPTION("Xilinx SPI platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/spi/xilinx_spi_pltfm.c b/drivers/spi/xilinx_spi_pltfm.c
new file mode 100644 (file)
index 0000000..24debac
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Support for Xilinx SPI platform devices
+ * Copyright (c) 2009 Intel Corporation
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Supports:
+ * Xilinx SPI devices as platform devices
+ *
+ * Inspired by xilinx_spi.c, 2002-2007 (c) MontaVista Software, Inc.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+#include <linux/spi/xilinx_spi.h>
+
+#include "xilinx_spi.h"
+
+static int __devinit xilinx_spi_probe(struct platform_device *dev)
+{
+       struct xspi_platform_data *pdata;
+       struct resource *r;
+       int irq;
+       struct spi_master *master;
+       u8 i;
+
+       pdata = dev->dev.platform_data;
+       if (!pdata)
+               return -ENODEV;
+
+       r = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       if (!r)
+               return -ENODEV;
+
+       irq = platform_get_irq(dev, 0);
+       if (irq < 0)
+               return -ENXIO;
+
+       master = xilinx_spi_init(&dev->dev, r, irq, dev->id);
+       if (!master)
+               return -ENODEV;
+
+       for (i = 0; i < pdata->num_devices; i++)
+               spi_new_device(master, pdata->devices + i);
+
+       platform_set_drvdata(dev, master);
+       return 0;
+}
+
+static int __devexit xilinx_spi_remove(struct platform_device *dev)
+{
+       xilinx_spi_deinit(platform_get_drvdata(dev));
+       platform_set_drvdata(dev, 0);
+
+       return 0;
+}
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:" XILINX_SPI_NAME);
+
+static struct platform_driver xilinx_spi_driver = {
+       .probe  = xilinx_spi_probe,
+       .remove = __devexit_p(xilinx_spi_remove),
+       .driver = {
+               .name = XILINX_SPI_NAME,
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init xilinx_spi_pltfm_init(void)
+{
+       return platform_driver_register(&xilinx_spi_driver);
+}
+module_init(xilinx_spi_pltfm_init);
+
+static void __exit xilinx_spi_pltfm_exit(void)
+{
+       platform_driver_unregister(&xilinx_spi_driver);
+}
+module_exit(xilinx_spi_pltfm_exit);
+
+MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
+MODULE_DESCRIPTION("Xilinx SPI platform driver");
+MODULE_LICENSE("GPL v2");
index bd9883f41e63b2279940ab239edf8bb947d57c6f..2be9f2fa41f91b87d6f794b57ca0c7c39cd522f1 100644 (file)
@@ -33,7 +33,7 @@
 #include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/usb/otg.h>
-#include <linux/i2c/twl4030.h>
+#include <linux/i2c/twl.h>
 #include <linux/regulator/consumer.h>
 #include <linux/err.h>
 
@@ -276,16 +276,16 @@ static int twl4030_i2c_write_u8_verify(struct twl4030_usb *twl,
 {
        u8 check;
 
-       if ((twl4030_i2c_write_u8(module, data, address) >= 0) &&
-           (twl4030_i2c_read_u8(module, &check, address) >= 0) &&
+       if ((twl_i2c_write_u8(module, data, address) >= 0) &&
+           (twl_i2c_read_u8(module, &check, address) >= 0) &&
                                                (check == data))
                return 0;
        dev_dbg(twl->dev, "Write%d[%d,0x%x] wrote %02x but read %02x\n",
                        1, module, address, check, data);
 
        /* Failed once: Try again */
-       if ((twl4030_i2c_write_u8(module, data, address) >= 0) &&
-           (twl4030_i2c_read_u8(module, &check, address) >= 0) &&
+       if ((twl_i2c_write_u8(module, data, address) >= 0) &&
+           (twl_i2c_read_u8(module, &check, address) >= 0) &&
                                                (check == data))
                return 0;
        dev_dbg(twl->dev, "Write%d[%d,0x%x] wrote %02x but read %02x\n",
@@ -303,7 +303,7 @@ static inline int twl4030_usb_write(struct twl4030_usb *twl,
 {
        int ret = 0;
 
-       ret = twl4030_i2c_write_u8(TWL4030_MODULE_USB, data, address);
+       ret = twl_i2c_write_u8(TWL4030_MODULE_USB, data, address);
        if (ret < 0)
                dev_dbg(twl->dev,
                        "TWL4030:USB:Write[0x%x] Error %d\n", address, ret);
@@ -315,7 +315,7 @@ static inline int twl4030_readb(struct twl4030_usb *twl, u8 module, u8 address)
        u8 data;
        int ret = 0;
 
-       ret = twl4030_i2c_read_u8(module, &data, address);
+       ret = twl_i2c_read_u8(module, &data, address);
        if (ret >= 0)
                ret = data;
        else
@@ -462,7 +462,7 @@ static void twl4030_phy_power(struct twl4030_usb *twl, int on)
                 * SLEEP. We work around this by clearing the bit after usv3v1
                 * is re-activated. This ensures that VUSB3V1 is really active.
                 */
-               twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0,
+               twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0,
                                                        VUSB_DEDICATED2);
                regulator_enable(twl->usb1v5);
                pwr &= ~PHY_PWR_PHYPWD;
@@ -505,44 +505,44 @@ static void twl4030_phy_resume(struct twl4030_usb *twl)
 static int twl4030_usb_ldo_init(struct twl4030_usb *twl)
 {
        /* Enable writing to power configuration registers */
-       twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0xC0, PROTECT_KEY);
-       twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0x0C, PROTECT_KEY);
+       twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0xC0, PROTECT_KEY);
+       twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0x0C, PROTECT_KEY);
 
        /* put VUSB3V1 LDO in active state */
-       twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB_DEDICATED2);
+       twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB_DEDICATED2);
 
        /* input to VUSB3V1 LDO is from VBAT, not VBUS */
-       twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x14, VUSB_DEDICATED1);
+       twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x14, VUSB_DEDICATED1);
 
        /* Initialize 3.1V regulator */
-       twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB3V1_DEV_GRP);
+       twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB3V1_DEV_GRP);
 
        twl->usb3v1 = regulator_get(twl->dev, "usb3v1");
        if (IS_ERR(twl->usb3v1))
                return -ENODEV;
 
-       twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB3V1_TYPE);
+       twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB3V1_TYPE);
 
        /* Initialize 1.5V regulator */
-       twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V5_DEV_GRP);
+       twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V5_DEV_GRP);
 
        twl->usb1v5 = regulator_get(twl->dev, "usb1v5");
        if (IS_ERR(twl->usb1v5))
                goto fail1;
 
-       twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V5_TYPE);
+       twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V5_TYPE);
 
        /* Initialize 1.8V regulator */
-       twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V8_DEV_GRP);
+       twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V8_DEV_GRP);
 
        twl->usb1v8 = regulator_get(twl->dev, "usb1v8");
        if (IS_ERR(twl->usb1v8))
                goto fail2;
 
-       twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V8_TYPE);
+       twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V8_TYPE);
 
        /* disable access to power configuration registers */
-       twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, PROTECT_KEY);
+       twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, PROTECT_KEY);
 
        return 0;
 
index ad05da5ba3c75caf2e6862cefac5c9a32772479c..4c10edecfb6616070ce46610a5694f2fbf051080 100644 (file)
@@ -15,7 +15,7 @@
 
 struct adp5520_bl {
        struct device *master;
-       struct adp5520_backlight_platfrom_data *pdata;
+       struct adp5520_backlight_platform_data *pdata;
        struct mutex lock;
        unsigned long cached_daylight_max;
        int id;
@@ -31,29 +31,30 @@ static int adp5520_bl_set(struct backlight_device *bl, int brightness)
        if (data->pdata->en_ambl_sens) {
                if ((brightness > 0) && (brightness < ADP5020_MAX_BRIGHTNESS)) {
                        /* Disable Ambient Light auto adjust */
-                       ret |= adp5520_clr_bits(master, BL_CONTROL,
-                                       BL_AUTO_ADJ);
-                       ret |= adp5520_write(master, DAYLIGHT_MAX, brightness);
+                       ret |= adp5520_clr_bits(master, ADP5520_BL_CONTROL,
+                                       ADP5520_BL_AUTO_ADJ);
+                       ret |= adp5520_write(master, ADP5520_DAYLIGHT_MAX,
+                                       brightness);
                } else {
                        /*
                         * MAX_BRIGHTNESS -> Enable Ambient Light auto adjust
                         * restore daylight l3 sysfs brightness
                         */
-                       ret |= adp5520_write(master, DAYLIGHT_MAX,
+                       ret |= adp5520_write(master, ADP5520_DAYLIGHT_MAX,
                                         data->cached_daylight_max);
-                       ret |= adp5520_set_bits(master, BL_CONTROL,
-                                        BL_AUTO_ADJ);
+                       ret |= adp5520_set_bits(master, ADP5520_BL_CONTROL,
+                                        ADP5520_BL_AUTO_ADJ);
                }
        } else {
-               ret |= adp5520_write(master, DAYLIGHT_MAX, brightness);
+               ret |= adp5520_write(master, ADP5520_DAYLIGHT_MAX, brightness);
        }
 
        if (data->current_brightness && brightness == 0)
                ret |= adp5520_set_bits(master,
-                               MODE_STATUS, DIM_EN);
+                               ADP5520_MODE_STATUS, ADP5520_DIM_EN);
        else if (data->current_brightness == 0 && brightness)
                ret |= adp5520_clr_bits(master,
-                               MODE_STATUS, DIM_EN);
+                               ADP5520_MODE_STATUS, ADP5520_DIM_EN);
 
        if (!ret)
                data->current_brightness = brightness;
@@ -79,7 +80,7 @@ static int adp5520_bl_get_brightness(struct backlight_device *bl)
        int error;
        uint8_t reg_val;
 
-       error = adp5520_read(data->master, BL_VALUE, &reg_val);
+       error = adp5520_read(data->master, ADP5520_BL_VALUE, &reg_val);
 
        return error ? data->current_brightness : reg_val;
 }
@@ -93,33 +94,46 @@ static int adp5520_bl_setup(struct backlight_device *bl)
 {
        struct adp5520_bl *data = bl_get_data(bl);
        struct device *master = data->master;
-       struct adp5520_backlight_platfrom_data *pdata = data->pdata;
+       struct adp5520_backlight_platform_data *pdata = data->pdata;
        int ret = 0;
 
-       ret |= adp5520_write(master, DAYLIGHT_MAX, pdata->l1_daylight_max);
-       ret |= adp5520_write(master, DAYLIGHT_DIM, pdata->l1_daylight_dim);
+       ret |= adp5520_write(master, ADP5520_DAYLIGHT_MAX,
+                               pdata->l1_daylight_max);
+       ret |= adp5520_write(master, ADP5520_DAYLIGHT_DIM,
+                               pdata->l1_daylight_dim);
 
        if (pdata->en_ambl_sens) {
                data->cached_daylight_max = pdata->l1_daylight_max;
-               ret |= adp5520_write(master, OFFICE_MAX, pdata->l2_office_max);
-               ret |= adp5520_write(master, OFFICE_DIM, pdata->l2_office_dim);
-               ret |= adp5520_write(master, DARK_MAX, pdata->l3_dark_max);
-               ret |= adp5520_write(master, DARK_DIM, pdata->l3_dark_dim);
-               ret |= adp5520_write(master, L2_TRIP, pdata->l2_trip);
-               ret |= adp5520_write(master, L2_HYS, pdata->l2_hyst);
-               ret |= adp5520_write(master, L3_TRIP, pdata->l3_trip);
-               ret |= adp5520_write(master, L3_HYS, pdata->l3_hyst);
-               ret |= adp5520_write(master, ALS_CMPR_CFG,
-                       ALS_CMPR_CFG_VAL(pdata->abml_filt, L3_EN));
+               ret |= adp5520_write(master, ADP5520_OFFICE_MAX,
+                               pdata->l2_office_max);
+               ret |= adp5520_write(master, ADP5520_OFFICE_DIM,
+                               pdata->l2_office_dim);
+               ret |= adp5520_write(master, ADP5520_DARK_MAX,
+                               pdata->l3_dark_max);
+               ret |= adp5520_write(master, ADP5520_DARK_DIM,
+                               pdata->l3_dark_dim);
+               ret |= adp5520_write(master, ADP5520_L2_TRIP,
+                               pdata->l2_trip);
+               ret |= adp5520_write(master, ADP5520_L2_HYS,
+                               pdata->l2_hyst);
+               ret |= adp5520_write(master, ADP5520_L3_TRIP,
+                                pdata->l3_trip);
+               ret |= adp5520_write(master, ADP5520_L3_HYS,
+                               pdata->l3_hyst);
+               ret |= adp5520_write(master, ADP5520_ALS_CMPR_CFG,
+                               ALS_CMPR_CFG_VAL(pdata->abml_filt,
+                               ADP5520_L3_EN));
        }
 
-       ret |= adp5520_write(master, BL_CONTROL,
-                       BL_CTRL_VAL(pdata->fade_led_law, pdata->en_ambl_sens));
+       ret |= adp5520_write(master, ADP5520_BL_CONTROL,
+                       BL_CTRL_VAL(pdata->fade_led_law,
+                                       pdata->en_ambl_sens));
 
-       ret |= adp5520_write(master, BL_FADE, FADE_VAL(pdata->fade_in,
+       ret |= adp5520_write(master, ADP5520_BL_FADE, FADE_VAL(pdata->fade_in,
                        pdata->fade_out));
 
-       ret |= adp5520_set_bits(master, MODE_STATUS, BL_EN | DIM_EN);
+       ret |= adp5520_set_bits(master, ADP5520_MODE_STATUS,
+                       ADP5520_BL_EN | ADP5520_DIM_EN);
 
        return ret;
 }
@@ -156,29 +170,31 @@ static ssize_t adp5520_store(struct device *dev, const char *buf,
 }
 
 static ssize_t adp5520_bl_dark_max_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
+                       struct device_attribute *attr, char *buf)
 {
-       return adp5520_show(dev, buf, DARK_MAX);
+       return adp5520_show(dev, buf, ADP5520_DARK_MAX);
 }
 
 static ssize_t adp5520_bl_dark_max_store(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t count)
+                       struct device_attribute *attr,
+                       const char *buf, size_t count)
 {
-       return adp5520_store(dev, buf, count, DARK_MAX);
+       return adp5520_store(dev, buf, count, ADP5520_DARK_MAX);
 }
 static DEVICE_ATTR(dark_max, 0664, adp5520_bl_dark_max_show,
                        adp5520_bl_dark_max_store);
 
 static ssize_t adp5520_bl_office_max_show(struct device *dev,
-                                    struct device_attribute *attr, char *buf)
+                       struct device_attribute *attr, char *buf)
 {
-       return adp5520_show(dev, buf, OFFICE_MAX);
+       return adp5520_show(dev, buf, ADP5520_OFFICE_MAX);
 }
 
 static ssize_t adp5520_bl_office_max_store(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t count)
+                       struct device_attribute *attr,
+                       const char *buf, size_t count)
 {
-       return adp5520_store(dev, buf, count, OFFICE_MAX);
+       return adp5520_store(dev, buf, count, ADP5520_OFFICE_MAX);
 }
 static DEVICE_ATTR(office_max, 0664, adp5520_bl_office_max_show,
                        adp5520_bl_office_max_store);
@@ -186,16 +202,17 @@ static DEVICE_ATTR(office_max, 0664, adp5520_bl_office_max_show,
 static ssize_t adp5520_bl_daylight_max_show(struct device *dev,
                        struct device_attribute *attr, char *buf)
 {
-       return adp5520_show(dev, buf, DAYLIGHT_MAX);
+       return adp5520_show(dev, buf, ADP5520_DAYLIGHT_MAX);
 }
 
 static ssize_t adp5520_bl_daylight_max_store(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t count)
+                       struct device_attribute *attr,
+                       const char *buf, size_t count)
 {
        struct adp5520_bl *data = dev_get_drvdata(dev);
 
        strict_strtoul(buf, 10, &data->cached_daylight_max);
-       return adp5520_store(dev, buf, count, DAYLIGHT_MAX);
+       return adp5520_store(dev, buf, count, ADP5520_DAYLIGHT_MAX);
 }
 static DEVICE_ATTR(daylight_max, 0664, adp5520_bl_daylight_max_show,
                        adp5520_bl_daylight_max_store);
@@ -203,14 +220,14 @@ static DEVICE_ATTR(daylight_max, 0664, adp5520_bl_daylight_max_show,
 static ssize_t adp5520_bl_dark_dim_show(struct device *dev,
                        struct device_attribute *attr, char *buf)
 {
-       return adp5520_show(dev, buf, DARK_DIM);
+       return adp5520_show(dev, buf, ADP5520_DARK_DIM);
 }
 
 static ssize_t adp5520_bl_dark_dim_store(struct device *dev,
-                                    struct device_attribute *attr,
-                                    const char *buf, size_t count)
+                       struct device_attribute *attr,
+                       const char *buf, size_t count)
 {
-       return adp5520_store(dev, buf, count, DARK_DIM);
+       return adp5520_store(dev, buf, count, ADP5520_DARK_DIM);
 }
 static DEVICE_ATTR(dark_dim, 0664, adp5520_bl_dark_dim_show,
                        adp5520_bl_dark_dim_store);
@@ -218,29 +235,29 @@ static DEVICE_ATTR(dark_dim, 0664, adp5520_bl_dark_dim_show,
 static ssize_t adp5520_bl_office_dim_show(struct device *dev,
                        struct device_attribute *attr, char *buf)
 {
-       return adp5520_show(dev, buf, OFFICE_DIM);
+       return adp5520_show(dev, buf, ADP5520_OFFICE_DIM);
 }
 
 static ssize_t adp5520_bl_office_dim_store(struct device *dev,
-                                    struct device_attribute *attr,
-                                    const char *buf, size_t count)
+                       struct device_attribute *attr,
+                       const char *buf, size_t count)
 {
-       return adp5520_store(dev, buf, count, OFFICE_DIM);
+       return adp5520_store(dev, buf, count, ADP5520_OFFICE_DIM);
 }
 static DEVICE_ATTR(office_dim, 0664, adp5520_bl_office_dim_show,
                        adp5520_bl_office_dim_store);
 
 static ssize_t adp5520_bl_daylight_dim_show(struct device *dev,
-                                    struct device_attribute *attr, char *buf)
+                       struct device_attribute *attr, char *buf)
 {
-       return adp5520_show(dev, buf, DAYLIGHT_DIM);
+       return adp5520_show(dev, buf, ADP5520_DAYLIGHT_DIM);
 }
 
 static ssize_t adp5520_bl_daylight_dim_store(struct device *dev,
-                                    struct device_attribute *attr,
-                                    const char *buf, size_t count)
+                       struct device_attribute *attr,
+                       const char *buf, size_t count)
 {
-       return adp5520_store(dev, buf, count, DAYLIGHT_DIM);
+       return adp5520_store(dev, buf, count, ADP5520_DAYLIGHT_DIM);
 }
 static DEVICE_ATTR(daylight_dim, 0664, adp5520_bl_daylight_dim_show,
                        adp5520_bl_daylight_dim_store);
@@ -316,7 +333,7 @@ static int __devexit adp5520_bl_remove(struct platform_device *pdev)
        struct backlight_device *bl = platform_get_drvdata(pdev);
        struct adp5520_bl *data = bl_get_data(bl);
 
-       adp5520_clr_bits(data->master, MODE_STATUS, BL_EN);
+       adp5520_clr_bits(data->master, ADP5520_MODE_STATUS, ADP5520_BL_EN);
 
        if (data->pdata->en_ambl_sens)
                sysfs_remove_group(&bl->dev.kobj,
index 760645d9dbb6ca0a3cb0c0c83cee785be3592ed8..e3eccc9af78e3c18f8b4b2ec5c2f98bcac7ee464 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/gpio.h>
-#include <linux/i2c/twl4030.h>
+#include <linux/i2c/twl.h>
 
 #include <plat/mux.h>
 #include <asm/mach-types.h>
@@ -52,7 +52,7 @@ static unsigned enable_gpio;
 #define TWL4030_VPLL2_DEV_GRP           0x33
 #define TWL4030_VPLL2_DEDICATED         0x36
 
-#define t2_out(c, r, v) twl4030_i2c_write_u8(c, r, v)
+#define t2_out(c, r, v) twl_i2c_write_u8(c, r, v)
 
 
 static int sdp2430_panel_init(struct lcd_panel *panel,
index cb46556f2973fb43900050ad9fa97e476b68a576..8162a40d15220aed9f2b6cfe972f9221a4520166 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/platform_device.h>
 #include <linux/miscdevice.h>
 #include <linux/uaccess.h>
-#include <linux/i2c/twl4030.h>
+#include <linux/i2c/twl.h>
 
 #define TWL4030_WATCHDOG_CFG_REG_OFFS  0x3
 
@@ -48,7 +48,7 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
 
 static int twl4030_wdt_write(unsigned char val)
 {
-       return twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, val,
+       return twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, val,
                                        TWL4030_WATCHDOG_CFG_REG_OFFS);
 }
 
index 278020d2449c749a0457064e4c3e1caf4aa65f52..14cbc831422a1cb84026bfe90d7c2a68cc43d99f 100644 (file)
@@ -979,24 +979,6 @@ COMPATIBLE_IOCTL(FIGETBSZ)
 /* 'X' - originally XFS but some now in the VFS */
 COMPATIBLE_IOCTL(FIFREEZE)
 COMPATIBLE_IOCTL(FITHAW)
-/* RAID */
-COMPATIBLE_IOCTL(RAID_VERSION)
-COMPATIBLE_IOCTL(GET_ARRAY_INFO)
-COMPATIBLE_IOCTL(GET_DISK_INFO)
-COMPATIBLE_IOCTL(PRINT_RAID_DEBUG)
-COMPATIBLE_IOCTL(RAID_AUTORUN)
-COMPATIBLE_IOCTL(CLEAR_ARRAY)
-COMPATIBLE_IOCTL(ADD_NEW_DISK)
-COMPATIBLE_IOCTL(SET_ARRAY_INFO)
-COMPATIBLE_IOCTL(SET_DISK_INFO)
-COMPATIBLE_IOCTL(WRITE_RAID_INFO)
-COMPATIBLE_IOCTL(UNPROTECT_ARRAY)
-COMPATIBLE_IOCTL(PROTECT_ARRAY)
-COMPATIBLE_IOCTL(RUN_ARRAY)
-COMPATIBLE_IOCTL(STOP_ARRAY)
-COMPATIBLE_IOCTL(STOP_ARRAY_RO)
-COMPATIBLE_IOCTL(RESTART_ARRAY_RW)
-COMPATIBLE_IOCTL(GET_BITMAP_FILE)
 COMPATIBLE_IOCTL(KDGETKEYCODE)
 COMPATIBLE_IOCTL(KDSETKEYCODE)
 COMPATIBLE_IOCTL(KDGKBTYPE)
index c1e19d5b5985f2a36d39801e697b9b45f7283f50..b1fd3daadc9c50522894fd00ec62bb8e600f9fd0 100644 (file)
@@ -3955,7 +3955,7 @@ static void ext4_mb_group_or_file(struct ext4_allocation_context *ac)
         * per cpu locality group is to reduce the contention between block
         * request from multiple CPUs.
         */
-       ac->ac_lg = per_cpu_ptr(sbi->s_locality_groups, raw_smp_processor_id());
+       ac->ac_lg = __this_cpu_ptr(sbi->s_locality_groups);
 
        /* we're going to use group allocation */
        ac->ac_flags |= EXT4_MB_HINT_GROUP_ALLOC;
index 293fa0528a6e10001a66ee5e94c33fcfa95b7c65..73ab220354dfc6c2a046535ec959707779ed56ed 100644 (file)
@@ -78,11 +78,6 @@ nfs4_callback_svc(void *vrqstp)
 
        set_freezable();
 
-       /*
-        * FIXME: do we really need to run this under the BKL? If so, please
-        * add a comment about what it's intended to protect.
-        */
-       lock_kernel();
        while (!kthread_should_stop()) {
                /*
                 * Listen for a request on the socket
@@ -104,7 +99,6 @@ nfs4_callback_svc(void *vrqstp)
                preverr = err;
                svc_process(rqstp);
        }
-       unlock_kernel();
        return 0;
 }
 
@@ -160,11 +154,6 @@ nfs41_callback_svc(void *vrqstp)
 
        set_freezable();
 
-       /*
-        * FIXME: do we really need to run this under the BKL? If so, please
-        * add a comment about what it's intended to protect.
-        */
-       lock_kernel();
        while (!kthread_should_stop()) {
                prepare_to_wait(&serv->sv_cb_waitq, &wq, TASK_INTERRUPTIBLE);
                spin_lock_bh(&serv->sv_cb_lock);
@@ -183,7 +172,6 @@ nfs41_callback_svc(void *vrqstp)
                }
                finish_wait(&serv->sv_cb_waitq, &wq);
        }
-       unlock_kernel();
        return 0;
 }
 
@@ -397,6 +385,7 @@ static int nfs_callback_authenticate(struct svc_rqst *rqstp)
  */
 static struct svc_version *nfs4_callback_version[] = {
        [1] = &nfs4_callback_version1,
+       [4] = &nfs4_callback_version4,
 };
 
 static struct svc_stat nfs4_callback_stats;
index 07baa8254ca1407a6342e80bc3e545c34868161e..d4036be0b589ffd24c391b53bded40bc55a6ab5f 100644 (file)
@@ -106,6 +106,19 @@ struct cb_sequenceres {
 extern unsigned nfs4_callback_sequence(struct cb_sequenceargs *args,
                                       struct cb_sequenceres *res);
 
+extern int nfs41_validate_delegation_stateid(struct nfs_delegation *delegation,
+                                            const nfs4_stateid *stateid);
+
+#define RCA4_TYPE_MASK_RDATA_DLG       0
+#define RCA4_TYPE_MASK_WDATA_DLG       1
+
+struct cb_recallanyargs {
+       struct sockaddr *craa_addr;
+       uint32_t        craa_objs_to_keep;
+       uint32_t        craa_type_mask;
+};
+
+extern unsigned nfs4_callback_recallany(struct cb_recallanyargs *args, void *dummy);
 #endif /* CONFIG_NFS_V4_1 */
 
 extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res);
@@ -114,8 +127,9 @@ extern __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy);
 #ifdef CONFIG_NFS_V4
 extern int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt);
 extern void nfs_callback_down(int minorversion);
+extern int nfs4_validate_delegation_stateid(struct nfs_delegation *delegation,
+                                           const nfs4_stateid *stateid);
 #endif /* CONFIG_NFS_V4 */
-
 /*
  * nfs41: Callbacks are expected to not cause substantial latency,
  * so we limit their concurrency to 1 by setting up the maximum number
index b7da1f54da68e3334aded5549ef3811ff5253f7a..defa9b4c470ebf0515d3b7da58585c0ec551e3db 100644 (file)
@@ -61,6 +61,16 @@ out:
        return res->status;
 }
 
+static int (*nfs_validate_delegation_stateid(struct nfs_client *clp))(struct nfs_delegation *, const nfs4_stateid *)
+{
+#if defined(CONFIG_NFS_V4_1)
+       if (clp->cl_minorversion > 0)
+               return nfs41_validate_delegation_stateid;
+#endif
+       return nfs4_validate_delegation_stateid;
+}
+
+
 __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy)
 {
        struct nfs_client *clp;
@@ -81,7 +91,8 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy)
                inode = nfs_delegation_find_inode(clp, &args->fh);
                if (inode != NULL) {
                        /* Set up a helper thread to actually return the delegation */
-                       switch(nfs_async_inode_return_delegation(inode, &args->stateid)) {
+                       switch (nfs_async_inode_return_delegation(inode, &args->stateid,
+                                                                 nfs_validate_delegation_stateid(clp))) {
                                case 0:
                                        res = 0;
                                        break;
@@ -102,8 +113,31 @@ out:
        return res;
 }
 
+int nfs4_validate_delegation_stateid(struct nfs_delegation *delegation, const nfs4_stateid *stateid)
+{
+       if (delegation == NULL || memcmp(delegation->stateid.data, stateid->data,
+                                        sizeof(delegation->stateid.data)) != 0)
+               return 0;
+       return 1;
+}
+
 #if defined(CONFIG_NFS_V4_1)
 
+int nfs41_validate_delegation_stateid(struct nfs_delegation *delegation, const nfs4_stateid *stateid)
+{
+       if (delegation == NULL)
+               return 0;
+
+       /* seqid is 4-bytes long */
+       if (((u32 *) &stateid->data)[0] != 0)
+               return 0;
+       if (memcmp(&delegation->stateid.data[4], &stateid->data[4],
+                  sizeof(stateid->data)-4))
+               return 0;
+
+       return 1;
+}
+
 /*
  * Validate the sequenceID sent by the server.
  * Return success if the sequenceID is one more than what we last saw on
@@ -227,4 +261,32 @@ out:
        return res->csr_status;
 }
 
+unsigned nfs4_callback_recallany(struct cb_recallanyargs *args, void *dummy)
+{
+       struct nfs_client *clp;
+       int status;
+       fmode_t flags = 0;
+
+       status = htonl(NFS4ERR_OP_NOT_IN_SESSION);
+       clp = nfs_find_client(args->craa_addr, 4);
+       if (clp == NULL)
+               goto out;
+
+       dprintk("NFS: RECALL_ANY callback request from %s\n",
+               rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR));
+
+       if (test_bit(RCA4_TYPE_MASK_RDATA_DLG, (const unsigned long *)
+                    &args->craa_type_mask))
+               flags = FMODE_READ;
+       if (test_bit(RCA4_TYPE_MASK_WDATA_DLG, (const unsigned long *)
+                    &args->craa_type_mask))
+               flags |= FMODE_WRITE;
+
+       if (flags)
+               nfs_expire_all_delegation_types(clp, flags);
+       status = htonl(NFS4_OK);
+out:
+       dprintk("%s: exit with status = %d\n", __func__, ntohl(status));
+       return status;
+}
 #endif /* CONFIG_NFS_V4_1 */
index 76b0aa0f73bfca33ac620c6569cbe926f099f901..8e1a2511c8be5b00e35fae972ee62cc921ce2d15 100644 (file)
@@ -23,6 +23,7 @@
 #if defined(CONFIG_NFS_V4_1)
 #define CB_OP_SEQUENCE_RES_MAXSZ       (CB_OP_HDR_RES_MAXSZ + \
                                        4 + 1 + 3)
+#define CB_OP_RECALLANY_RES_MAXSZ      (CB_OP_HDR_RES_MAXSZ)
 #endif /* CONFIG_NFS_V4_1 */
 
 #define NFSDBG_FACILITY NFSDBG_CALLBACK
@@ -326,6 +327,25 @@ out_free:
        goto out;
 }
 
+static unsigned decode_recallany_args(struct svc_rqst *rqstp,
+                                     struct xdr_stream *xdr,
+                                     struct cb_recallanyargs *args)
+{
+       uint32_t *p;
+
+       args->craa_addr = svc_addr(rqstp);
+       p = read_buf(xdr, 4);
+       if (unlikely(p == NULL))
+               return htonl(NFS4ERR_BADXDR);
+       args->craa_objs_to_keep = ntohl(*p++);
+       p = read_buf(xdr, 4);
+       if (unlikely(p == NULL))
+               return htonl(NFS4ERR_BADXDR);
+       args->craa_type_mask = ntohl(*p);
+
+       return 0;
+}
+
 #endif /* CONFIG_NFS_V4_1 */
 
 static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
@@ -533,6 +553,7 @@ preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op)
        case OP_CB_GETATTR:
        case OP_CB_RECALL:
        case OP_CB_SEQUENCE:
+       case OP_CB_RECALL_ANY:
                *op = &callback_ops[op_nr];
                break;
 
@@ -540,7 +561,6 @@ preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op)
        case OP_CB_NOTIFY_DEVICEID:
        case OP_CB_NOTIFY:
        case OP_CB_PUSH_DELEG:
-       case OP_CB_RECALL_ANY:
        case OP_CB_RECALLABLE_OBJ_AVAIL:
        case OP_CB_RECALL_SLOT:
        case OP_CB_WANTS_CANCELLED:
@@ -688,6 +708,11 @@ static struct callback_op callback_ops[] = {
                .encode_res = (callback_encode_res_t)encode_cb_sequence_res,
                .res_maxsize = CB_OP_SEQUENCE_RES_MAXSZ,
        },
+       [OP_CB_RECALL_ANY] = {
+               .process_op = (callback_process_op_t)nfs4_callback_recallany,
+               .decode_args = (callback_decode_arg_t)decode_recallany_args,
+               .res_maxsize = CB_OP_RECALLANY_RES_MAXSZ,
+       },
 #endif /* CONFIG_NFS_V4_1 */
 };
 
@@ -718,3 +743,10 @@ struct svc_version nfs4_callback_version1 = {
        .vs_dispatch = NULL,
 };
 
+struct svc_version nfs4_callback_version4 = {
+       .vs_vers = 4,
+       .vs_nproc = ARRAY_SIZE(nfs4_callback_procedures1),
+       .vs_proc = nfs4_callback_procedures1,
+       .vs_xdrsize = NFS4_CALLBACK_XDRSIZE,
+       .vs_dispatch = NULL,
+};
index 99ea196f071f04d81c82fbc42bdcb000b9f0694d..ee77713ce68b10e020b0589920560f87c6fffe11 100644 (file)
@@ -1260,10 +1260,20 @@ error:
 static void nfs4_session_set_rwsize(struct nfs_server *server)
 {
 #ifdef CONFIG_NFS_V4_1
+       struct nfs4_session *sess;
+       u32 server_resp_sz;
+       u32 server_rqst_sz;
+
        if (!nfs4_has_session(server->nfs_client))
                return;
-       server->rsize = server->nfs_client->cl_session->fc_attrs.max_resp_sz;
-       server->wsize = server->nfs_client->cl_session->fc_attrs.max_rqst_sz;
+       sess = server->nfs_client->cl_session;
+       server_resp_sz = sess->fc_attrs.max_resp_sz - nfs41_maxread_overhead;
+       server_rqst_sz = sess->fc_attrs.max_rqst_sz - nfs41_maxwrite_overhead;
+
+       if (server->rsize > server_resp_sz)
+               server->rsize = server_resp_sz;
+       if (server->wsize > server_rqst_sz)
+               server->wsize = server_rqst_sz;
 #endif /* CONFIG_NFS_V4_1 */
 }
 
index 6dd48a4405b46d409af629d4195b27b17e83dab1..2563bebc4c670915f73de93625411062a52f3582 100644 (file)
@@ -92,7 +92,7 @@ out:
        return status;
 }
 
-static void nfs_delegation_claim_opens(struct inode *inode, const nfs4_stateid *stateid)
+static int nfs_delegation_claim_opens(struct inode *inode, const nfs4_stateid *stateid)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
        struct nfs_open_context *ctx;
@@ -116,10 +116,11 @@ again:
                        err = nfs_delegation_claim_locks(ctx, state);
                put_nfs_open_context(ctx);
                if (err != 0)
-                       return;
+                       return err;
                goto again;
        }
        spin_unlock(&inode->i_lock);
+       return 0;
 }
 
 /*
@@ -261,30 +262,34 @@ static void nfs_msync_inode(struct inode *inode)
 /*
  * Basic procedure for returning a delegation to the server
  */
-static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegation *delegation)
+static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegation *delegation, int issync)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
+       int err;
 
-       nfs_msync_inode(inode);
        /*
         * Guard against new delegated open/lock/unlock calls and against
         * state recovery
         */
        down_write(&nfsi->rwsem);
-       nfs_delegation_claim_opens(inode, &delegation->stateid);
+       err = nfs_delegation_claim_opens(inode, &delegation->stateid);
        up_write(&nfsi->rwsem);
-       nfs_msync_inode(inode);
+       if (err)
+               goto out;
 
-       return nfs_do_return_delegation(inode, delegation, 1);
+       err = nfs_do_return_delegation(inode, delegation, issync);
+out:
+       return err;
 }
 
 /*
  * Return all delegations that have been marked for return
  */
-void nfs_client_return_marked_delegations(struct nfs_client *clp)
+int nfs_client_return_marked_delegations(struct nfs_client *clp)
 {
        struct nfs_delegation *delegation;
        struct inode *inode;
+       int err = 0;
 
 restart:
        rcu_read_lock();
@@ -298,12 +303,18 @@ restart:
                delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL);
                spin_unlock(&clp->cl_lock);
                rcu_read_unlock();
-               if (delegation != NULL)
-                       __nfs_inode_return_delegation(inode, delegation);
+               if (delegation != NULL) {
+                       filemap_flush(inode->i_mapping);
+                       err = __nfs_inode_return_delegation(inode, delegation, 0);
+               }
                iput(inode);
-               goto restart;
+               if (!err)
+                       goto restart;
+               set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
+               return err;
        }
        rcu_read_unlock();
+       return 0;
 }
 
 /*
@@ -338,8 +349,10 @@ int nfs_inode_return_delegation(struct inode *inode)
                spin_lock(&clp->cl_lock);
                delegation = nfs_detach_delegation_locked(nfsi, NULL);
                spin_unlock(&clp->cl_lock);
-               if (delegation != NULL)
-                       err = __nfs_inode_return_delegation(inode, delegation);
+               if (delegation != NULL) {
+                       nfs_msync_inode(inode);
+                       err = __nfs_inode_return_delegation(inode, delegation, 1);
+               }
        }
        return err;
 }
@@ -368,33 +381,47 @@ void nfs_super_return_all_delegations(struct super_block *sb)
                spin_unlock(&delegation->lock);
        }
        rcu_read_unlock();
-       nfs_client_return_marked_delegations(clp);
+       if (nfs_client_return_marked_delegations(clp) != 0)
+               nfs4_schedule_state_manager(clp);
 }
 
-static void nfs_client_mark_return_all_delegations(struct nfs_client *clp)
+static
+void nfs_client_mark_return_all_delegation_types(struct nfs_client *clp, fmode_t flags)
 {
        struct nfs_delegation *delegation;
 
        rcu_read_lock();
        list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
-               set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
-               set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
+               if ((delegation->type == (FMODE_READ|FMODE_WRITE)) && !(flags & FMODE_WRITE))
+                       continue;
+               if (delegation->type & flags)
+                       nfs_mark_return_delegation(clp, delegation);
        }
        rcu_read_unlock();
 }
 
+static void nfs_client_mark_return_all_delegations(struct nfs_client *clp)
+{
+       nfs_client_mark_return_all_delegation_types(clp, FMODE_READ|FMODE_WRITE);
+}
+
 static void nfs_delegation_run_state_manager(struct nfs_client *clp)
 {
        if (test_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state))
                nfs4_schedule_state_manager(clp);
 }
 
-void nfs_expire_all_delegations(struct nfs_client *clp)
+void nfs_expire_all_delegation_types(struct nfs_client *clp, fmode_t flags)
 {
-       nfs_client_mark_return_all_delegations(clp);
+       nfs_client_mark_return_all_delegation_types(clp, flags);
        nfs_delegation_run_state_manager(clp);
 }
 
+void nfs_expire_all_delegations(struct nfs_client *clp)
+{
+       nfs_expire_all_delegation_types(clp, FMODE_READ|FMODE_WRITE);
+}
+
 /*
  * Return all delegations following an NFS4ERR_CB_PATH_DOWN error.
  */
@@ -413,8 +440,7 @@ static void nfs_client_mark_return_unreferenced_delegations(struct nfs_client *c
        list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
                if (test_and_clear_bit(NFS_DELEGATION_REFERENCED, &delegation->flags))
                        continue;
-               set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
-               set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
+               nfs_mark_return_delegation(clp, delegation);
        }
        rcu_read_unlock();
 }
@@ -428,18 +454,21 @@ void nfs_expire_unreferenced_delegations(struct nfs_client *clp)
 /*
  * Asynchronous delegation recall!
  */
-int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid)
+int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid,
+                                     int (*validate_stateid)(struct nfs_delegation *delegation,
+                                                             const nfs4_stateid *stateid))
 {
        struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
        struct nfs_delegation *delegation;
 
        rcu_read_lock();
        delegation = rcu_dereference(NFS_I(inode)->delegation);
-       if (delegation == NULL || memcmp(delegation->stateid.data, stateid->data,
-                               sizeof(delegation->stateid.data)) != 0) {
+
+       if (!validate_stateid(delegation, stateid)) {
                rcu_read_unlock();
                return -ENOENT;
        }
+
        nfs_mark_return_delegation(clp, delegation);
        rcu_read_unlock();
        nfs_delegation_run_state_manager(clp);
index 09f383795174d065f36a413a6f698b467a93c57c..944b627ec6e1a956340ee8c0464b5510b185b336 100644 (file)
@@ -34,15 +34,18 @@ enum {
 int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res);
 void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res);
 int nfs_inode_return_delegation(struct inode *inode);
-int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid);
+int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid,
+                                     int (*validate_stateid)(struct nfs_delegation *delegation,
+                                                             const nfs4_stateid *stateid));
 void nfs_inode_return_delegation_noreclaim(struct inode *inode);
 
 struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle);
 void nfs_super_return_all_delegations(struct super_block *sb);
 void nfs_expire_all_delegations(struct nfs_client *clp);
+void nfs_expire_all_delegation_types(struct nfs_client *clp, fmode_t flags);
 void nfs_expire_unreferenced_delegations(struct nfs_client *clp);
 void nfs_handle_cb_pathdown(struct nfs_client *clp);
-void nfs_client_return_marked_delegations(struct nfs_client *clp);
+int nfs_client_return_marked_delegations(struct nfs_client *clp);
 
 void nfs_delegation_mark_reclaim(struct nfs_client *clp);
 void nfs_delegation_reap_unclaimed(struct nfs_client *clp);
index 7cb298525eefd1a5ebcac1870ce08679447a3f2e..2c5ace4f00a7ffecfcf41c21e512833ef70d426b 100644 (file)
@@ -1579,55 +1579,46 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        struct dentry *dentry = NULL, *rehash = NULL;
        int error = -EBUSY;
 
-       /*
-        * To prevent any new references to the target during the rename,
-        * we unhash the dentry and free the inode in advance.
-        */
-       if (!d_unhashed(new_dentry)) {
-               d_drop(new_dentry);
-               rehash = new_dentry;
-       }
-
        dfprintk(VFS, "NFS: rename(%s/%s -> %s/%s, ct=%d)\n",
                 old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
                 new_dentry->d_parent->d_name.name, new_dentry->d_name.name,
                 atomic_read(&new_dentry->d_count));
 
        /*
-        * First check whether the target is busy ... we can't
-        * safely do _any_ rename if the target is in use.
-        *
-        * For files, make a copy of the dentry and then do a 
-        * silly-rename. If the silly-rename succeeds, the
-        * copied dentry is hashed and becomes the new target.
+        * For non-directories, check whether the target is busy and if so,
+        * make a copy of the dentry and then do a silly-rename. If the
+        * silly-rename succeeds, the copied dentry is hashed and becomes
+        * the new target.
         */
-       if (!new_inode)
-               goto go_ahead;
-       if (S_ISDIR(new_inode->i_mode)) {
-               error = -EISDIR;
-               if (!S_ISDIR(old_inode->i_mode))
-                       goto out;
-       } else if (atomic_read(&new_dentry->d_count) > 2) {
-               int err;
-               /* copy the target dentry's name */
-               dentry = d_alloc(new_dentry->d_parent,
-                                &new_dentry->d_name);
-               if (!dentry)
-                       goto out;
+       if (new_inode && !S_ISDIR(new_inode->i_mode)) {
+               /*
+                * To prevent any new references to the target during the
+                * rename, we unhash the dentry in advance.
+                */
+               if (!d_unhashed(new_dentry)) {
+                       d_drop(new_dentry);
+                       rehash = new_dentry;
+               }
+
+               if (atomic_read(&new_dentry->d_count) > 2) {
+                       int err;
+
+                       /* copy the target dentry's name */
+                       dentry = d_alloc(new_dentry->d_parent,
+                                        &new_dentry->d_name);
+                       if (!dentry)
+                               goto out;
 
-               /* silly-rename the existing target ... */
-               err = nfs_sillyrename(new_dir, new_dentry);
-               if (!err) {
-                       new_dentry = rehash = dentry;
+                       /* silly-rename the existing target ... */
+                       err = nfs_sillyrename(new_dir, new_dentry);
+                       if (err)
+                               goto out;
+
+                       new_dentry = dentry;
                        new_inode = NULL;
-                       /* instantiate the replacement target */
-                       d_instantiate(new_dentry, NULL);
-               } else if (atomic_read(&new_dentry->d_count) > 1)
-                       /* dentry still busy? */
-                       goto out;
+               }
        }
 
-go_ahead:
        /*
         * ... prune child dentries and writebacks if needed.
         */
index f4d54ba97cc62653ffceedf568f4d4c987840682..95e1ca765d4757085117e8c401fbcb09046ecea5 100644 (file)
@@ -146,7 +146,7 @@ static int nfs_dns_show(struct seq_file *m, struct cache_detail *cd,
        return 0;
 }
 
-struct nfs_dns_ent *nfs_dns_lookup(struct cache_detail *cd,
+static struct nfs_dns_ent *nfs_dns_lookup(struct cache_detail *cd,
                struct nfs_dns_ent *key)
 {
        struct cache_head *ch;
@@ -159,7 +159,7 @@ struct nfs_dns_ent *nfs_dns_lookup(struct cache_detail *cd,
        return container_of(ch, struct nfs_dns_ent, h);
 }
 
-struct nfs_dns_ent *nfs_dns_update(struct cache_detail *cd,
+static struct nfs_dns_ent *nfs_dns_update(struct cache_detail *cd,
                struct nfs_dns_ent *new,
                struct nfs_dns_ent *key)
 {
index e21b1bb9972f893270c9090c31ffd110cc31ae43..29e464d23b32fe4107aea88394d0c734e02c10df 100644 (file)
@@ -30,6 +30,15 @@ static inline int nfs4_has_session(const struct nfs_client *clp)
        return 0;
 }
 
+static inline int nfs4_has_persistent_session(const struct nfs_client *clp)
+{
+#ifdef CONFIG_NFS_V4_1
+       if (nfs4_has_session(clp))
+               return (clp->cl_session->flags & SESSION4_PERSIST);
+#endif /* CONFIG_NFS_V4_1 */
+       return 0;
+}
+
 struct nfs_clone_mount {
        const struct super_block *sb;
        const struct dentry *dentry;
@@ -156,6 +165,7 @@ struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentr
 
 /* callback_xdr.c */
 extern struct svc_version nfs4_callback_version1;
+extern struct svc_version nfs4_callback_version4;
 
 /* pagelist.c */
 extern int __init nfs_init_nfspagecache(void);
@@ -177,24 +187,14 @@ extern __be32 * nfs_decode_dirent(__be32 *, struct nfs_entry *, int);
 extern struct rpc_procinfo nfs3_procedures[];
 extern __be32 *nfs3_decode_dirent(__be32 *, struct nfs_entry *, int);
 
-/* nfs4proc.c */
-static inline void nfs4_restart_rpc(struct rpc_task *task,
-                                   const struct nfs_client *clp)
-{
-#ifdef CONFIG_NFS_V4_1
-       if (nfs4_has_session(clp) &&
-           test_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) {
-               rpc_restart_call_prepare(task);
-               return;
-       }
-#endif /* CONFIG_NFS_V4_1 */
-       rpc_restart_call(task);
-}
-
 /* nfs4xdr.c */
 #ifdef CONFIG_NFS_V4
 extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus);
 #endif
+#ifdef CONFIG_NFS_V4_1
+extern const u32 nfs41_maxread_overhead;
+extern const u32 nfs41_maxwrite_overhead;
+#endif
 
 /* nfs4proc.c */
 #ifdef CONFIG_NFS_V4
@@ -273,20 +273,6 @@ extern int _nfs4_call_sync_session(struct nfs_server *server,
                                   struct nfs4_sequence_res *res,
                                   int cache_reply);
 
-#ifdef CONFIG_NFS_V4_1
-extern void nfs41_sequence_free_slot(const struct nfs_client *,
-                                    struct nfs4_sequence_res *res);
-#endif /* CONFIG_NFS_V4_1 */
-
-static inline void nfs4_sequence_free_slot(const struct nfs_client *clp,
-                                          struct nfs4_sequence_res *res)
-{
-#ifdef CONFIG_NFS_V4_1
-       if (nfs4_has_session(clp))
-               nfs41_sequence_free_slot(clp, res);
-#endif /* CONFIG_NFS_V4_1 */
-}
-
 /*
  * Determine the device name as a string
  */
@@ -380,3 +366,15 @@ unsigned int nfs_page_array_len(unsigned int base, size_t len)
        return ((unsigned long)len + (unsigned long)base +
                PAGE_SIZE - 1) >> PAGE_SHIFT;
 }
+
+/*
+ * Helper for restarting RPC calls in the possible presence of NFSv4.1
+ * sessions.
+ */
+static inline void nfs_restart_rpc(struct rpc_task *task, const struct nfs_client *clp)
+{
+       if (nfs4_has_session(clp))
+               rpc_restart_call_prepare(task);
+       else
+               rpc_restart_call(task);
+}
index ceda50aad73cc5a3bc93baeaaa7771ebd7a0f00f..46d779abafd356e3344ef79c151466dfc863fed5 100644 (file)
@@ -25,13 +25,7 @@ struct nfs_iostats {
 static inline void nfs_inc_server_stats(const struct nfs_server *server,
                                        enum nfs_stat_eventcounters stat)
 {
-       struct nfs_iostats *iostats;
-       int cpu;
-
-       cpu = get_cpu();
-       iostats = per_cpu_ptr(server->io_stats, cpu);
-       iostats->events[stat]++;
-       put_cpu();
+       this_cpu_inc(server->io_stats->events[stat]);
 }
 
 static inline void nfs_inc_stats(const struct inode *inode,
@@ -44,13 +38,7 @@ static inline void nfs_add_server_stats(const struct nfs_server *server,
                                        enum nfs_stat_bytecounters stat,
                                        unsigned long addend)
 {
-       struct nfs_iostats *iostats;
-       int cpu;
-
-       cpu = get_cpu();
-       iostats = per_cpu_ptr(server->io_stats, cpu);
-       iostats->bytes[stat] += addend;
-       put_cpu();
+       this_cpu_add(server->io_stats->bytes[stat], addend);
 }
 
 static inline void nfs_add_stats(const struct inode *inode,
@@ -65,13 +53,7 @@ static inline void nfs_add_fscache_stats(struct inode *inode,
                                         enum nfs_stat_fscachecounters stat,
                                         unsigned long addend)
 {
-       struct nfs_iostats *iostats;
-       int cpu;
-
-       cpu = get_cpu();
-       iostats = per_cpu_ptr(NFS_SERVER(inode)->io_stats, cpu);
-       iostats->fscache[stat] += addend;
-       put_cpu();
+       this_cpu_add(NFS_SERVER(inode)->io_stats->fscache[stat], addend);
 }
 #endif
 
index 6ea07a3c75d4942f6197e54791b7504502d3f54c..7e57b04e40141f5971dfabd63f848d07cc7ceeb2 100644 (file)
@@ -44,7 +44,8 @@ enum nfs4_client_state {
        NFS4CLNT_RECLAIM_REBOOT,
        NFS4CLNT_RECLAIM_NOGRACE,
        NFS4CLNT_DELEGRETURN,
-       NFS4CLNT_SESSION_SETUP,
+       NFS4CLNT_SESSION_RESET,
+       NFS4CLNT_SESSION_DRAINING,
 };
 
 /*
@@ -180,6 +181,7 @@ struct nfs4_state_recovery_ops {
        int (*recover_lock)(struct nfs4_state *, struct file_lock *);
        int (*establish_clid)(struct nfs_client *, struct rpc_cred *);
        struct rpc_cred * (*get_clid_cred)(struct nfs_client *);
+       int (*reclaim_complete)(struct nfs_client *);
 };
 
 struct nfs4_state_maintenance_ops {
@@ -200,9 +202,11 @@ extern ssize_t nfs4_listxattr(struct dentry *, char *, size_t);
 /* nfs4proc.c */
 extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struct rpc_cred *);
 extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct rpc_cred *);
+extern int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred);
 extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *);
 extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *);
 extern int nfs4_init_clientid(struct nfs_client *, struct rpc_cred *);
+extern int nfs41_init_clientid(struct nfs_client *, struct rpc_cred *);
 extern int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait);
 extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *);
 extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *);
@@ -218,9 +222,11 @@ extern int nfs4_setup_sequence(struct nfs_client *clp,
                int cache_reply, struct rpc_task *task);
 extern void nfs4_destroy_session(struct nfs4_session *session);
 extern struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp);
-extern int nfs4_proc_create_session(struct nfs_client *, int reset);
+extern int nfs4_proc_create_session(struct nfs_client *);
 extern int nfs4_proc_destroy_session(struct nfs4_session *);
 extern int nfs4_init_session(struct nfs_server *server);
+extern int nfs4_proc_get_lease_time(struct nfs_client *clp,
+               struct nfs_fsinfo *fsinfo);
 #else /* CONFIG_NFS_v4_1 */
 static inline int nfs4_setup_sequence(struct nfs_client *clp,
                struct nfs4_sequence_args *args, struct nfs4_sequence_res *res,
@@ -267,6 +273,7 @@ extern void nfs4_state_set_mode_locked(struct nfs4_state *, fmode_t);
 extern void nfs4_schedule_state_recovery(struct nfs_client *);
 extern void nfs4_schedule_state_manager(struct nfs_client *);
 extern int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state);
+extern void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags);
 extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp);
 extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl);
 extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t);
@@ -287,6 +294,7 @@ struct nfs4_mount_data;
 
 /* callback_xdr.c */
 extern struct svc_version nfs4_callback_version1;
+extern struct svc_version nfs4_callback_version4;
 
 #else
 
index 741a562177fc3f587dcd1e1019f3cfe53c367de8..9f5f11ecfd93853ac3e18fe5b19a95f4b24d8645 100644 (file)
@@ -270,11 +270,18 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode,
                case -NFS4ERR_SEQ_MISORDERED:
                        dprintk("%s ERROR: %d Reset session\n", __func__,
                                errorcode);
-                       set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state);
+                       nfs4_schedule_state_recovery(clp);
                        exception->retry = 1;
-                       /* FALLTHROUGH */
+                       break;
 #endif /* !defined(CONFIG_NFS_V4_1) */
                case -NFS4ERR_FILE_OPEN:
+                       if (exception->timeout > HZ) {
+                               /* We have retried a decent amount, time to
+                                * fail
+                                */
+                               ret = -EBUSY;
+                               break;
+                       }
                case -NFS4ERR_GRACE:
                case -NFS4ERR_DELAY:
                        ret = nfs4_delay(server->client, &exception->timeout);
@@ -311,48 +318,54 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp
  * so we need to scan down from highest_used_slotid to 0 looking for the now
  * highest slotid in use.
  * If none found, highest_used_slotid is set to -1.
+ *
+ * Must be called while holding tbl->slot_tbl_lock
  */
 static void
 nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid)
 {
        int slotid = free_slotid;
 
-       spin_lock(&tbl->slot_tbl_lock);
        /* clear used bit in bitmap */
        __clear_bit(slotid, tbl->used_slots);
 
        /* update highest_used_slotid when it is freed */
        if (slotid == tbl->highest_used_slotid) {
                slotid = find_last_bit(tbl->used_slots, tbl->max_slots);
-               if (slotid >= 0 && slotid < tbl->max_slots)
+               if (slotid < tbl->max_slots)
                        tbl->highest_used_slotid = slotid;
                else
                        tbl->highest_used_slotid = -1;
        }
-       rpc_wake_up_next(&tbl->slot_tbl_waitq);
-       spin_unlock(&tbl->slot_tbl_lock);
        dprintk("%s: free_slotid %u highest_used_slotid %d\n", __func__,
                free_slotid, tbl->highest_used_slotid);
 }
 
-void nfs41_sequence_free_slot(const struct nfs_client *clp,
+static void nfs41_sequence_free_slot(const struct nfs_client *clp,
                              struct nfs4_sequence_res *res)
 {
        struct nfs4_slot_table *tbl;
 
-       if (!nfs4_has_session(clp)) {
-               dprintk("%s: No session\n", __func__);
-               return;
-       }
        tbl = &clp->cl_session->fc_slot_table;
        if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) {
-               dprintk("%s: No slot\n", __func__);
                /* just wake up the next guy waiting since
                 * we may have not consumed a slot after all */
-               rpc_wake_up_next(&tbl->slot_tbl_waitq);
+               dprintk("%s: No slot\n", __func__);
                return;
        }
+
+       spin_lock(&tbl->slot_tbl_lock);
        nfs4_free_slot(tbl, res->sr_slotid);
+
+       /* Signal state manager thread if session is drained */
+       if (test_bit(NFS4CLNT_SESSION_DRAINING, &clp->cl_state)) {
+               if (tbl->highest_used_slotid == -1) {
+                       dprintk("%s COMPLETE: Session Drained\n", __func__);
+                       complete(&clp->cl_session->complete);
+               }
+       } else
+               rpc_wake_up_next(&tbl->slot_tbl_waitq);
+       spin_unlock(&tbl->slot_tbl_lock);
        res->sr_slotid = NFS4_MAX_SLOT_TABLE;
 }
 
@@ -377,10 +390,10 @@ static void nfs41_sequence_done(struct nfs_client *clp,
        if (res->sr_slotid == NFS4_MAX_SLOT_TABLE)
                goto out;
 
-       tbl = &clp->cl_session->fc_slot_table;
-       slot = tbl->slots + res->sr_slotid;
-
+       /* Check the SEQUENCE operation status */
        if (res->sr_status == 0) {
+               tbl = &clp->cl_session->fc_slot_table;
+               slot = tbl->slots + res->sr_slotid;
                /* Update the slot's sequence and clientid lease timer */
                ++slot->seq_nr;
                timestamp = res->sr_renewal_time;
@@ -388,7 +401,8 @@ static void nfs41_sequence_done(struct nfs_client *clp,
                if (time_before(clp->cl_last_renewal, timestamp))
                        clp->cl_last_renewal = timestamp;
                spin_unlock(&clp->cl_lock);
-               return;
+               /* Check sequence flags */
+               nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags);
        }
 out:
        /* The session may be reset by one of the error handlers. */
@@ -429,24 +443,6 @@ out:
        return ret_id;
 }
 
-static int nfs4_recover_session(struct nfs4_session *session)
-{
-       struct nfs_client *clp = session->clp;
-       unsigned int loop;
-       int ret;
-
-       for (loop = NFS4_MAX_LOOP_ON_RECOVER; loop != 0; loop--) {
-               ret = nfs4_wait_clnt_recover(clp);
-               if (ret != 0)
-                       break;
-               if (!test_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state))
-                       break;
-               nfs4_schedule_state_manager(clp);
-               ret = -EIO;
-       }
-       return ret;
-}
-
 static int nfs41_setup_sequence(struct nfs4_session *session,
                                struct nfs4_sequence_args *args,
                                struct nfs4_sequence_res *res,
@@ -455,7 +451,6 @@ static int nfs41_setup_sequence(struct nfs4_session *session,
 {
        struct nfs4_slot *slot;
        struct nfs4_slot_table *tbl;
-       int status = 0;
        u8 slotid;
 
        dprintk("--> %s\n", __func__);
@@ -468,21 +463,15 @@ static int nfs41_setup_sequence(struct nfs4_session *session,
        tbl = &session->fc_slot_table;
 
        spin_lock(&tbl->slot_tbl_lock);
-       if (test_bit(NFS4CLNT_SESSION_SETUP, &session->clp->cl_state)) {
-               if (tbl->highest_used_slotid != -1) {
-                       rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL);
-                       spin_unlock(&tbl->slot_tbl_lock);
-                       dprintk("<-- %s: Session reset: draining\n", __func__);
-                       return -EAGAIN;
-               }
-
-               /* The slot table is empty; start the reset thread */
-               dprintk("%s Session Reset\n", __func__);
+       if (test_bit(NFS4CLNT_SESSION_DRAINING, &session->clp->cl_state)) {
+               /*
+                * The state manager will wait until the slot table is empty.
+                * Schedule the reset thread
+                */
+               rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL);
                spin_unlock(&tbl->slot_tbl_lock);
-               status = nfs4_recover_session(session);
-               if (status)
-                       return status;
-               spin_lock(&tbl->slot_tbl_lock);
+               dprintk("%s Schedule Session Reset\n", __func__);
+               return -EAGAIN;
        }
 
        slotid = nfs4_find_slot(tbl, task);
@@ -527,7 +516,7 @@ int nfs4_setup_sequence(struct nfs_client *clp,
                goto out;
        ret = nfs41_setup_sequence(clp->cl_session, args, res, cache_reply,
                                   task);
-       if (ret != -EAGAIN) {
+       if (ret && ret != -EAGAIN) {
                /* terminate rpc task */
                task->tk_status = ret;
                task->tk_action = NULL;
@@ -561,7 +550,6 @@ static void nfs41_call_sync_done(struct rpc_task *task, void *calldata)
        struct nfs41_call_sync_data *data = calldata;
 
        nfs41_sequence_done(data->clp, data->seq_res, task->tk_status);
-       nfs41_sequence_free_slot(data->clp, data->seq_res);
 }
 
 struct rpc_call_ops nfs41_call_sync_ops = {
@@ -637,15 +625,6 @@ static void nfs4_sequence_done(const struct nfs_server *server,
 #endif /* CONFIG_NFS_V4_1 */
 }
 
-/* no restart, therefore free slot here */
-static void nfs4_sequence_done_free_slot(const struct nfs_server *server,
-                                        struct nfs4_sequence_res *res,
-                                        int rpc_status)
-{
-       nfs4_sequence_done(server, res, rpc_status);
-       nfs4_sequence_free_slot(server->nfs_client, res);
-}
-
 static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo)
 {
        struct nfs_inode *nfsi = NFS_I(dir);
@@ -720,9 +699,15 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path,
        p->o_arg.bitmask = server->attr_bitmask;
        p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;
        if (flags & O_EXCL) {
-               u32 *s = (u32 *) p->o_arg.u.verifier.data;
-               s[0] = jiffies;
-               s[1] = current->pid;
+               if (nfs4_has_persistent_session(server->nfs_client)) {
+                       /* GUARDED */
+                       p->o_arg.u.attrs = &p->attrs;
+                       memcpy(&p->attrs, attrs, sizeof(p->attrs));
+               } else { /* EXCLUSIVE4_1 */
+                       u32 *s = (u32 *) p->o_arg.u.verifier.data;
+                       s[0] = jiffies;
+                       s[1] = current->pid;
+               }
        } else if (flags & O_CREAT) {
                p->o_arg.u.attrs = &p->attrs;
                memcpy(&p->attrs, attrs, sizeof(p->attrs));
@@ -776,13 +761,16 @@ static int can_open_cached(struct nfs4_state *state, fmode_t mode, int open_mode
                goto out;
        switch (mode & (FMODE_READ|FMODE_WRITE)) {
                case FMODE_READ:
-                       ret |= test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0;
+                       ret |= test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0
+                               && state->n_rdonly != 0;
                        break;
                case FMODE_WRITE:
-                       ret |= test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0;
+                       ret |= test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0
+                               && state->n_wronly != 0;
                        break;
                case FMODE_READ|FMODE_WRITE:
-                       ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0;
+                       ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0
+                               && state->n_rdwr != 0;
        }
 out:
        return ret;
@@ -1183,6 +1171,14 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state
                        case -ENOENT:
                        case -ESTALE:
                                goto out;
+                       case -NFS4ERR_BADSESSION:
+                       case -NFS4ERR_BADSLOT:
+                       case -NFS4ERR_BAD_HIGH_SLOT:
+                       case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
+                       case -NFS4ERR_DEADSESSION:
+                               nfs4_schedule_state_recovery(
+                                       server->nfs_client);
+                               goto out;
                        case -NFS4ERR_STALE_CLIENTID:
                        case -NFS4ERR_STALE_STATEID:
                        case -NFS4ERR_EXPIRED:
@@ -1336,8 +1332,8 @@ static void nfs4_open_done(struct rpc_task *task, void *calldata)
 
        data->rpc_status = task->tk_status;
 
-       nfs4_sequence_done_free_slot(data->o_arg.server, &data->o_res.seq_res,
-                                    task->tk_status);
+       nfs4_sequence_done(data->o_arg.server, &data->o_res.seq_res,
+                       task->tk_status);
 
        if (RPC_ASSASSINATED(task))
                return;
@@ -1488,7 +1484,7 @@ static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *s
        return ret;
 }
 
-static inline int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4_state *state)
+static int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4_state *state)
 {
        struct nfs_server *server = NFS_SERVER(state->inode);
        struct nfs4_exception exception = { };
@@ -1496,10 +1492,16 @@ static inline int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4
 
        do {
                err = _nfs4_open_expired(ctx, state);
-               if (err != -NFS4ERR_DELAY)
-                       break;
-               nfs4_handle_exception(server, err, &exception);
+               switch (err) {
+               default:
+                       goto out;
+               case -NFS4ERR_GRACE:
+               case -NFS4ERR_DELAY:
+                       nfs4_handle_exception(server, err, &exception);
+                       err = 0;
+               }
        } while (exception.retry);
+out:
        return err;
 }
 
@@ -1712,6 +1714,18 @@ static void nfs4_free_closedata(void *data)
        kfree(calldata);
 }
 
+static void nfs4_close_clear_stateid_flags(struct nfs4_state *state,
+               fmode_t fmode)
+{
+       spin_lock(&state->owner->so_lock);
+       if (!(fmode & FMODE_READ))
+               clear_bit(NFS_O_RDONLY_STATE, &state->flags);
+       if (!(fmode & FMODE_WRITE))
+               clear_bit(NFS_O_WRONLY_STATE, &state->flags);
+       clear_bit(NFS_O_RDWR_STATE, &state->flags);
+       spin_unlock(&state->owner->so_lock);
+}
+
 static void nfs4_close_done(struct rpc_task *task, void *data)
 {
        struct nfs4_closedata *calldata = data;
@@ -1728,6 +1742,8 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
                case 0:
                        nfs_set_open_stateid(state, &calldata->res.stateid, 0);
                        renew_lease(server, calldata->timestamp);
+                       nfs4_close_clear_stateid_flags(state,
+                                       calldata->arg.fmode);
                        break;
                case -NFS4ERR_STALE_STATEID:
                case -NFS4ERR_OLD_STATEID:
@@ -1737,11 +1753,10 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
                                break;
                default:
                        if (nfs4_async_handle_error(task, server, state) == -EAGAIN) {
-                               nfs4_restart_rpc(task, server->nfs_client);
+                               nfs_restart_rpc(task, server->nfs_client);
                                return;
                        }
        }
-       nfs4_sequence_free_slot(server->nfs_client, &calldata->res.seq_res);
        nfs_refresh_inode(calldata->inode, calldata->res.fattr);
 }
 
@@ -1749,38 +1764,39 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
 {
        struct nfs4_closedata *calldata = data;
        struct nfs4_state *state = calldata->state;
-       int clear_rd, clear_wr, clear_rdwr;
+       int call_close = 0;
 
        if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0)
                return;
 
-       clear_rd = clear_wr = clear_rdwr = 0;
+       task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE];
+       calldata->arg.fmode = FMODE_READ|FMODE_WRITE;
        spin_lock(&state->owner->so_lock);
        /* Calculate the change in open mode */
        if (state->n_rdwr == 0) {
                if (state->n_rdonly == 0) {
-                       clear_rd |= test_and_clear_bit(NFS_O_RDONLY_STATE, &state->flags);
-                       clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags);
+                       call_close |= test_bit(NFS_O_RDONLY_STATE, &state->flags);
+                       call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags);
+                       calldata->arg.fmode &= ~FMODE_READ;
                }
                if (state->n_wronly == 0) {
-                       clear_wr |= test_and_clear_bit(NFS_O_WRONLY_STATE, &state->flags);
-                       clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags);
+                       call_close |= test_bit(NFS_O_WRONLY_STATE, &state->flags);
+                       call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags);
+                       calldata->arg.fmode &= ~FMODE_WRITE;
                }
        }
        spin_unlock(&state->owner->so_lock);
-       if (!clear_rd && !clear_wr && !clear_rdwr) {
+
+       if (!call_close) {
                /* Note: exit _without_ calling nfs4_close_done */
                task->tk_action = NULL;
                return;
        }
+
+       if (calldata->arg.fmode == 0)
+               task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE];
+
        nfs_fattr_init(calldata->res.fattr);
-       if (test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0) {
-               task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE];
-               calldata->arg.fmode = FMODE_READ;
-       } else if (test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0) {
-               task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE];
-               calldata->arg.fmode = FMODE_WRITE;
-       }
        calldata->timestamp = jiffies;
        if (nfs4_setup_sequence((NFS_SERVER(calldata->inode))->nfs_client,
                                &calldata->arg.seq_args, &calldata->res.seq_res,
@@ -1981,7 +1997,7 @@ out_drop:
        return 0;
 }
 
-void nfs4_close_context(struct nfs_open_context *ctx, int is_sync)
+static void nfs4_close_context(struct nfs_open_context *ctx, int is_sync)
 {
        if (ctx->state == NULL)
                return;
@@ -2532,7 +2548,6 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
        nfs4_sequence_done(res->server, &res->seq_res, task->tk_status);
        if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN)
                return 0;
-       nfs4_sequence_free_slot(res->server->nfs_client, &res->seq_res);
        update_changeattr(dir, &res->cinfo);
        nfs_post_op_update_inode(dir, &res->dir_attr);
        return 1;
@@ -2971,11 +2986,10 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data)
 
        dprintk("--> %s\n", __func__);
 
-       /* nfs4_sequence_free_slot called in the read rpc_call_done */
        nfs4_sequence_done(server, &data->res.seq_res, task->tk_status);
 
        if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) {
-               nfs4_restart_rpc(task, server->nfs_client);
+               nfs_restart_rpc(task, server->nfs_client);
                return -EAGAIN;
        }
 
@@ -2995,12 +3009,11 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data)
 {
        struct inode *inode = data->inode;
        
-       /* slot is freed in nfs_writeback_done */
        nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res,
                           task->tk_status);
 
        if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) {
-               nfs4_restart_rpc(task, NFS_SERVER(inode)->nfs_client);
+               nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client);
                return -EAGAIN;
        }
        if (task->tk_status >= 0) {
@@ -3028,11 +3041,9 @@ static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data)
        nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res,
                           task->tk_status);
        if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) {
-               nfs4_restart_rpc(task, NFS_SERVER(inode)->nfs_client);
+               nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client);
                return -EAGAIN;
        }
-       nfs4_sequence_free_slot(NFS_SERVER(inode)->nfs_client,
-                               &data->res.seq_res);
        nfs_refresh_inode(inode, data->res.fattr);
        return 0;
 }
@@ -3350,7 +3361,7 @@ _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
                case -NFS4ERR_SEQ_MISORDERED:
                        dprintk("%s ERROR %d, Reset session\n", __func__,
                                task->tk_status);
-                       set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state);
+                       nfs4_schedule_state_recovery(clp);
                        task->tk_status = 0;
                        return -EAGAIN;
 #endif /* CONFIG_NFS_V4_1 */
@@ -3483,12 +3494,23 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
 {
        struct nfs4_delegreturndata *data = calldata;
 
-       nfs4_sequence_done_free_slot(data->res.server, &data->res.seq_res,
-                                    task->tk_status);
+       nfs4_sequence_done(data->res.server, &data->res.seq_res,
+                       task->tk_status);
 
-       data->rpc_status = task->tk_status;
-       if (data->rpc_status == 0)
+       switch (task->tk_status) {
+       case -NFS4ERR_STALE_STATEID:
+       case -NFS4ERR_EXPIRED:
+       case 0:
                renew_lease(data->res.server, data->timestamp);
+               break;
+       default:
+               if (nfs4_async_handle_error(task, data->res.server, NULL) ==
+                               -EAGAIN) {
+                       nfs_restart_rpc(task, data->res.server->nfs_client);
+                       return;
+               }
+       }
+       data->rpc_status = task->tk_status;
 }
 
 static void nfs4_delegreturn_release(void *calldata)
@@ -3741,11 +3763,9 @@ static void nfs4_locku_done(struct rpc_task *task, void *data)
                        break;
                default:
                        if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN)
-                               nfs4_restart_rpc(task,
-                                               calldata->server->nfs_client);
+                               nfs_restart_rpc(task,
+                                                calldata->server->nfs_client);
        }
-       nfs4_sequence_free_slot(calldata->server->nfs_client,
-                               &calldata->res.seq_res);
 }
 
 static void nfs4_locku_prepare(struct rpc_task *task, void *data)
@@ -3927,8 +3947,8 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata)
 
        dprintk("%s: begin!\n", __func__);
 
-       nfs4_sequence_done_free_slot(data->server, &data->res.seq_res,
-                                    task->tk_status);
+       nfs4_sequence_done(data->server, &data->res.seq_res,
+                       task->tk_status);
 
        data->rpc_status = task->tk_status;
        if (RPC_ASSASSINATED(task))
@@ -4049,10 +4069,16 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request
                if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
                        return 0;
                err = _nfs4_do_setlk(state, F_SETLK, request, 0);
-               if (err != -NFS4ERR_DELAY)
-                       break;
-               nfs4_handle_exception(server, err, &exception);
+               switch (err) {
+               default:
+                       goto out;
+               case -NFS4ERR_GRACE:
+               case -NFS4ERR_DELAY:
+                       nfs4_handle_exception(server, err, &exception);
+                       err = 0;
+               }
        } while (exception.retry);
+out:
        return err;
 }
 
@@ -4172,6 +4198,11 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl)
                        case -NFS4ERR_EXPIRED:
                        case -NFS4ERR_STALE_CLIENTID:
                        case -NFS4ERR_STALE_STATEID:
+                       case -NFS4ERR_BADSESSION:
+                       case -NFS4ERR_BADSLOT:
+                       case -NFS4ERR_BAD_HIGH_SLOT:
+                       case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
+                       case -NFS4ERR_DEADSESSION:
                                nfs4_schedule_state_recovery(server->nfs_client);
                                goto out;
                        case -ERESTARTSYS:
@@ -4296,7 +4327,7 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
  * NFS4ERR_BADSESSION in the sequence operation, and will therefore
  * be in some phase of session reset.
  */
-static int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
+int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
 {
        nfs4_verifier verifier;
        struct nfs41_exchange_id_args args = {
@@ -4318,6 +4349,9 @@ static int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
        dprintk("--> %s\n", __func__);
        BUG_ON(clp == NULL);
 
+       /* Remove server-only flags */
+       args.flags &= ~EXCHGID4_FLAG_CONFIRMED_R;
+
        p = (u32 *)verifier.data;
        *p++ = htonl((u32)clp->cl_boot_time.tv_sec);
        *p = htonl((u32)clp->cl_boot_time.tv_nsec);
@@ -4389,10 +4423,9 @@ static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata)
                dprintk("%s Retry: tk_status %d\n", __func__, task->tk_status);
                rpc_delay(task, NFS4_POLL_RETRY_MIN);
                task->tk_status = 0;
-               nfs4_restart_rpc(task, data->clp);
+               nfs_restart_rpc(task, data->clp);
                return;
        }
-       nfs41_sequence_free_slot(data->clp, &data->res->lr_seq_res);
        dprintk("<-- %s\n", __func__);
 }
 
@@ -4465,7 +4498,6 @@ static int nfs4_reset_slot_table(struct nfs4_slot_table *tbl, int max_slots,
        spin_lock(&tbl->slot_tbl_lock);
        for (i = 0; i < max_slots; ++i)
                tbl->slots[i].seq_nr = ivalue;
-       tbl->highest_used_slotid = -1;
        spin_unlock(&tbl->slot_tbl_lock);
        dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__,
                tbl, tbl->slots, tbl->max_slots);
@@ -4515,7 +4547,6 @@ static void nfs4_destroy_slot_tables(struct nfs4_session *session)
 static int nfs4_init_slot_table(struct nfs4_slot_table *tbl,
                int max_slots, int ivalue)
 {
-       int i;
        struct nfs4_slot *slot;
        int ret = -ENOMEM;
 
@@ -4526,18 +4557,9 @@ static int nfs4_init_slot_table(struct nfs4_slot_table *tbl,
        slot = kcalloc(max_slots, sizeof(struct nfs4_slot), GFP_KERNEL);
        if (!slot)
                goto out;
-       for (i = 0; i < max_slots; ++i)
-               slot[i].seq_nr = ivalue;
        ret = 0;
 
        spin_lock(&tbl->slot_tbl_lock);
-       if (tbl->slots != NULL) {
-               spin_unlock(&tbl->slot_tbl_lock);
-               dprintk("%s: slot table already initialized. tbl=%p slots=%p\n",
-                       __func__, tbl, tbl->slots);
-               WARN_ON(1);
-               goto out_free;
-       }
        tbl->max_slots = max_slots;
        tbl->slots = slot;
        tbl->highest_used_slotid = -1;  /* no slot is currently used */
@@ -4547,10 +4569,6 @@ static int nfs4_init_slot_table(struct nfs4_slot_table *tbl,
 out:
        dprintk("<-- %s: return %d\n", __func__, ret);
        return ret;
-
-out_free:
-       kfree(slot);
-       goto out;
 }
 
 /*
@@ -4558,17 +4576,24 @@ out_free:
  */
 static int nfs4_init_slot_tables(struct nfs4_session *session)
 {
-       int status;
+       struct nfs4_slot_table *tbl;
+       int status = 0;
 
-       status = nfs4_init_slot_table(&session->fc_slot_table,
-                       session->fc_attrs.max_reqs, 1);
-       if (status)
-               return status;
+       tbl = &session->fc_slot_table;
+       if (tbl->slots == NULL) {
+               status = nfs4_init_slot_table(tbl,
+                               session->fc_attrs.max_reqs, 1);
+               if (status)
+                       return status;
+       }
 
-       status = nfs4_init_slot_table(&session->bc_slot_table,
-                       session->bc_attrs.max_reqs, 0);
-       if (status)
-               nfs4_destroy_slot_tables(session);
+       tbl = &session->bc_slot_table;
+       if (tbl->slots == NULL) {
+               status = nfs4_init_slot_table(tbl,
+                               session->bc_attrs.max_reqs, 0);
+               if (status)
+                       nfs4_destroy_slot_tables(session);
+       }
 
        return status;
 }
@@ -4582,7 +4607,6 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp)
        if (!session)
                return NULL;
 
-       set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state);
        /*
         * The create session reply races with the server back
         * channel probe. Mark the client NFS_CS_SESSION_INITING
@@ -4590,12 +4614,15 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp)
         * nfs_client struct
         */
        clp->cl_cons_state = NFS_CS_SESSION_INITING;
+       init_completion(&session->complete);
 
        tbl = &session->fc_slot_table;
+       tbl->highest_used_slotid = -1;
        spin_lock_init(&tbl->slot_tbl_lock);
        rpc_init_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table");
 
        tbl = &session->bc_slot_table;
+       tbl->highest_used_slotid = -1;
        spin_lock_init(&tbl->slot_tbl_lock);
        rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table");
 
@@ -4747,11 +4774,10 @@ static int _nfs4_proc_create_session(struct nfs_client *clp)
  * It is the responsibility of the caller to verify the session is
  * expired before calling this routine.
  */
-int nfs4_proc_create_session(struct nfs_client *clp, int reset)
+int nfs4_proc_create_session(struct nfs_client *clp)
 {
        int status;
        unsigned *ptr;
-       struct nfs_fsinfo fsinfo;
        struct nfs4_session *session = clp->cl_session;
 
        dprintk("--> %s clp=%p session=%p\n", __func__, clp, session);
@@ -4760,35 +4786,19 @@ int nfs4_proc_create_session(struct nfs_client *clp, int reset)
        if (status)
                goto out;
 
-       /* Init or reset the fore channel */
-       if (reset)
-               status = nfs4_reset_slot_tables(session);
-       else
-               status = nfs4_init_slot_tables(session);
-       dprintk("fore channel slot table initialization returned %d\n", status);
+       /* Init and reset the fore channel */
+       status = nfs4_init_slot_tables(session);
+       dprintk("slot table initialization returned %d\n", status);
+       if (status)
+               goto out;
+       status = nfs4_reset_slot_tables(session);
+       dprintk("slot table reset returned %d\n", status);
        if (status)
                goto out;
 
        ptr = (unsigned *)&session->sess_id.data[0];
        dprintk("%s client>seqid %d sessionid %u:%u:%u:%u\n", __func__,
                clp->cl_seqid, ptr[0], ptr[1], ptr[2], ptr[3]);
-
-       if (reset)
-               /* Lease time is aleady set */
-               goto out;
-
-       /* Get the lease time */
-       status = nfs4_proc_get_lease_time(clp, &fsinfo);
-       if (status == 0) {
-               /* Update lease time and schedule renewal */
-               spin_lock(&clp->cl_lock);
-               clp->cl_lease_time = fsinfo.lease_time * HZ;
-               clp->cl_last_renewal = jiffies;
-               clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
-               spin_unlock(&clp->cl_lock);
-
-               nfs4_schedule_state_renewal(clp);
-       }
 out:
        dprintk("<-- %s\n", __func__);
        return status;
@@ -4827,13 +4837,16 @@ int nfs4_proc_destroy_session(struct nfs4_session *session)
 int nfs4_init_session(struct nfs_server *server)
 {
        struct nfs_client *clp = server->nfs_client;
+       struct nfs4_session *session;
        int ret;
 
        if (!nfs4_has_session(clp))
                return 0;
 
-       clp->cl_session->fc_attrs.max_rqst_sz = server->wsize;
-       clp->cl_session->fc_attrs.max_resp_sz = server->rsize;
+       session = clp->cl_session;
+       session->fc_attrs.max_rqst_sz = server->wsize + nfs41_maxwrite_overhead;
+       session->fc_attrs.max_resp_sz = server->rsize + nfs41_maxread_overhead;
+
        ret = nfs4_recover_expired_lease(server);
        if (!ret)
                ret = nfs4_check_client_ready(clp);
@@ -4872,11 +4885,10 @@ void nfs41_sequence_call_done(struct rpc_task *task, void *data)
 
                if (_nfs4_async_handle_error(task, NULL, clp, NULL)
                                                                == -EAGAIN) {
-                       nfs4_restart_rpc(task, clp);
+                       nfs_restart_rpc(task, clp);
                        return;
                }
        }
-       nfs41_sequence_free_slot(clp, task->tk_msg.rpc_resp);
        dprintk("%s rpc_cred %p\n", __func__, task->tk_msg.rpc_cred);
 
        kfree(task->tk_msg.rpc_argp);
@@ -4931,6 +4943,109 @@ static int nfs41_proc_async_sequence(struct nfs_client *clp,
                              &nfs41_sequence_ops, (void *)clp);
 }
 
+struct nfs4_reclaim_complete_data {
+       struct nfs_client *clp;
+       struct nfs41_reclaim_complete_args arg;
+       struct nfs41_reclaim_complete_res res;
+};
+
+static void nfs4_reclaim_complete_prepare(struct rpc_task *task, void *data)
+{
+       struct nfs4_reclaim_complete_data *calldata = data;
+
+       if (nfs4_setup_sequence(calldata->clp, &calldata->arg.seq_args,
+                               &calldata->res.seq_res, 0, task))
+               return;
+
+       rpc_call_start(task);
+}
+
+static void nfs4_reclaim_complete_done(struct rpc_task *task, void *data)
+{
+       struct nfs4_reclaim_complete_data *calldata = data;
+       struct nfs_client *clp = calldata->clp;
+       struct nfs4_sequence_res *res = &calldata->res.seq_res;
+
+       dprintk("--> %s\n", __func__);
+       nfs41_sequence_done(clp, res, task->tk_status);
+       switch (task->tk_status) {
+       case 0:
+       case -NFS4ERR_COMPLETE_ALREADY:
+               break;
+       case -NFS4ERR_BADSESSION:
+       case -NFS4ERR_DEADSESSION:
+               /*
+                * Handle the session error, but do not retry the operation, as
+                * we have no way of telling whether the clientid had to be
+                * reset before we got our reply.  If reset, a new wave of
+                * reclaim operations will follow, containing their own reclaim
+                * complete.  We don't want our retry to get on the way of
+                * recovery by incorrectly indicating to the server that we're
+                * done reclaiming state since the process had to be restarted.
+                */
+               _nfs4_async_handle_error(task, NULL, clp, NULL);
+               break;
+       default:
+               if (_nfs4_async_handle_error(
+                               task, NULL, clp, NULL) == -EAGAIN) {
+                       rpc_restart_call_prepare(task);
+                       return;
+               }
+       }
+
+       dprintk("<-- %s\n", __func__);
+}
+
+static void nfs4_free_reclaim_complete_data(void *data)
+{
+       struct nfs4_reclaim_complete_data *calldata = data;
+
+       kfree(calldata);
+}
+
+static const struct rpc_call_ops nfs4_reclaim_complete_call_ops = {
+       .rpc_call_prepare = nfs4_reclaim_complete_prepare,
+       .rpc_call_done = nfs4_reclaim_complete_done,
+       .rpc_release = nfs4_free_reclaim_complete_data,
+};
+
+/*
+ * Issue a global reclaim complete.
+ */
+static int nfs41_proc_reclaim_complete(struct nfs_client *clp)
+{
+       struct nfs4_reclaim_complete_data *calldata;
+       struct rpc_task *task;
+       struct rpc_message msg = {
+               .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RECLAIM_COMPLETE],
+       };
+       struct rpc_task_setup task_setup_data = {
+               .rpc_client = clp->cl_rpcclient,
+               .rpc_message = &msg,
+               .callback_ops = &nfs4_reclaim_complete_call_ops,
+               .flags = RPC_TASK_ASYNC,
+       };
+       int status = -ENOMEM;
+
+       dprintk("--> %s\n", __func__);
+       calldata = kzalloc(sizeof(*calldata), GFP_KERNEL);
+       if (calldata == NULL)
+               goto out;
+       calldata->clp = clp;
+       calldata->arg.one_fs = 0;
+       calldata->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE;
+
+       msg.rpc_argp = &calldata->arg;
+       msg.rpc_resp = &calldata->res;
+       task_setup_data.callback_data = calldata;
+       task = rpc_run_task(&task_setup_data);
+       if (IS_ERR(task))
+               status = PTR_ERR(task);
+       rpc_put_task(task);
+out:
+       dprintk("<-- %s status=%d\n", __func__, status);
+       return status;
+}
 #endif /* CONFIG_NFS_V4_1 */
 
 struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = {
@@ -4948,8 +5063,9 @@ struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = {
        .state_flag_bit = NFS_STATE_RECLAIM_REBOOT,
        .recover_open   = nfs4_open_reclaim,
        .recover_lock   = nfs4_lock_reclaim,
-       .establish_clid = nfs4_proc_exchange_id,
+       .establish_clid = nfs41_init_clientid,
        .get_clid_cred  = nfs4_get_exchange_id_cred,
+       .reclaim_complete = nfs41_proc_reclaim_complete,
 };
 #endif /* CONFIG_NFS_V4_1 */
 
@@ -4968,7 +5084,7 @@ struct nfs4_state_recovery_ops nfs41_nograce_recovery_ops = {
        .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE,
        .recover_open   = nfs4_open_expired,
        .recover_lock   = nfs4_lock_expired,
-       .establish_clid = nfs4_proc_exchange_id,
+       .establish_clid = nfs41_init_clientid,
        .get_clid_cred  = nfs4_get_exchange_id_cred,
 };
 #endif /* CONFIG_NFS_V4_1 */
index 2ef4fecf39847049cce4a5af771760255dca29c5..e76427e6346fc136a413b324a83d6c9994a14830 100644 (file)
@@ -116,6 +116,68 @@ struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp)
 
 #if defined(CONFIG_NFS_V4_1)
 
+static int nfs41_setup_state_renewal(struct nfs_client *clp)
+{
+       int status;
+       struct nfs_fsinfo fsinfo;
+
+       status = nfs4_proc_get_lease_time(clp, &fsinfo);
+       if (status == 0) {
+               /* Update lease time and schedule renewal */
+               spin_lock(&clp->cl_lock);
+               clp->cl_lease_time = fsinfo.lease_time * HZ;
+               clp->cl_last_renewal = jiffies;
+               spin_unlock(&clp->cl_lock);
+
+               nfs4_schedule_state_renewal(clp);
+       }
+
+       return status;
+}
+
+static void nfs41_end_drain_session(struct nfs_client *clp,
+               struct nfs4_session *ses)
+{
+       if (test_and_clear_bit(NFS4CLNT_SESSION_DRAINING, &clp->cl_state))
+               rpc_wake_up(&ses->fc_slot_table.slot_tbl_waitq);
+}
+
+static int nfs41_begin_drain_session(struct nfs_client *clp,
+               struct nfs4_session *ses)
+{
+       struct nfs4_slot_table *tbl = &ses->fc_slot_table;
+
+       spin_lock(&tbl->slot_tbl_lock);
+       set_bit(NFS4CLNT_SESSION_DRAINING, &clp->cl_state);
+       if (tbl->highest_used_slotid != -1) {
+               INIT_COMPLETION(ses->complete);
+               spin_unlock(&tbl->slot_tbl_lock);
+               return wait_for_completion_interruptible(&ses->complete);
+       }
+       spin_unlock(&tbl->slot_tbl_lock);
+       return 0;
+}
+
+int nfs41_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)
+{
+       int status;
+
+       status = nfs41_begin_drain_session(clp, clp->cl_session);
+       if (status != 0)
+               goto out;
+       status = nfs4_proc_exchange_id(clp, cred);
+       if (status != 0)
+               goto out;
+       status = nfs4_proc_create_session(clp);
+       if (status != 0)
+               goto out;
+       nfs41_end_drain_session(clp, clp->cl_session);
+       nfs41_setup_state_renewal(clp);
+       nfs_mark_client_ready(clp, NFS_CS_READY);
+out:
+       return status;
+}
+
 struct rpc_cred *nfs4_get_exchange_id_cred(struct nfs_client *clp)
 {
        struct rpc_cred *cred;
@@ -877,6 +939,10 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_
                        case -NFS4ERR_EXPIRED:
                        case -NFS4ERR_NO_GRACE:
                        case -NFS4ERR_STALE_CLIENTID:
+                       case -NFS4ERR_BADSESSION:
+                       case -NFS4ERR_BADSLOT:
+                       case -NFS4ERR_BAD_HIGH_SLOT:
+                       case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
                                goto out;
                        default:
                                printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n",
@@ -959,6 +1025,10 @@ restart:
                        case -NFS4ERR_NO_GRACE:
                                nfs4_state_mark_reclaim_nograce(sp->so_client, state);
                        case -NFS4ERR_STALE_CLIENTID:
+                       case -NFS4ERR_BADSESSION:
+                       case -NFS4ERR_BADSLOT:
+                       case -NFS4ERR_BAD_HIGH_SLOT:
+                       case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
                                goto out_err;
                }
                nfs4_put_open_state(state);
@@ -1011,6 +1081,14 @@ static void nfs4_state_start_reclaim_reboot(struct nfs_client *clp)
        nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_reboot);
 }
 
+static void nfs4_reclaim_complete(struct nfs_client *clp,
+                                const struct nfs4_state_recovery_ops *ops)
+{
+       /* Notify the server we're done reclaiming our state */
+       if (ops->reclaim_complete)
+               (void)ops->reclaim_complete(clp);
+}
+
 static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp)
 {
        struct nfs4_state_owner *sp;
@@ -1020,6 +1098,9 @@ static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp)
        if (!test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state))
                return;
 
+       nfs4_reclaim_complete(clp,
+               nfs4_reboot_recovery_ops[clp->cl_minorversion]);
+
        for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) {
                sp = rb_entry(pos, struct nfs4_state_owner, so_client_node);
                spin_lock(&sp->so_lock);
@@ -1046,25 +1127,25 @@ static void nfs4_state_start_reclaim_nograce(struct nfs_client *clp)
        nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_nograce);
 }
 
-static void nfs4_state_end_reclaim_nograce(struct nfs_client *clp)
-{
-       clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state);
-}
-
-static void nfs4_recovery_handle_error(struct nfs_client *clp, int error)
+static int nfs4_recovery_handle_error(struct nfs_client *clp, int error)
 {
        switch (error) {
                case -NFS4ERR_CB_PATH_DOWN:
                        nfs_handle_cb_pathdown(clp);
-                       break;
+                       return 0;
+               case -NFS4ERR_NO_GRACE:
+                       nfs4_state_end_reclaim_reboot(clp);
+                       return 0;
                case -NFS4ERR_STALE_CLIENTID:
                case -NFS4ERR_LEASE_MOVED:
                        set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
+                       nfs4_state_end_reclaim_reboot(clp);
                        nfs4_state_start_reclaim_reboot(clp);
                        break;
                case -NFS4ERR_EXPIRED:
                        set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
                        nfs4_state_start_reclaim_nograce(clp);
+                       break;
                case -NFS4ERR_BADSESSION:
                case -NFS4ERR_BADSLOT:
                case -NFS4ERR_BAD_HIGH_SLOT:
@@ -1072,8 +1153,11 @@ static void nfs4_recovery_handle_error(struct nfs_client *clp, int error)
                case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
                case -NFS4ERR_SEQ_FALSE_RETRY:
                case -NFS4ERR_SEQ_MISORDERED:
-                       set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state);
+                       set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
+                       /* Zero session reset errors */
+                       return 0;
        }
+       return error;
 }
 
 static int nfs4_do_reclaim(struct nfs_client *clp, const struct nfs4_state_recovery_ops *ops)
@@ -1093,8 +1177,7 @@ restart:
                if (status < 0) {
                        set_bit(ops->owner_flag_bit, &sp->so_flags);
                        nfs4_put_state_owner(sp);
-                       nfs4_recovery_handle_error(clp, status);
-                       return status;
+                       return nfs4_recovery_handle_error(clp, status);
                }
                nfs4_put_state_owner(sp);
                goto restart;
@@ -1124,8 +1207,7 @@ static int nfs4_check_lease(struct nfs_client *clp)
        status = ops->renew_lease(clp, cred);
        put_rpccred(cred);
 out:
-       nfs4_recovery_handle_error(clp, status);
-       return status;
+       return nfs4_recovery_handle_error(clp, status);
 }
 
 static int nfs4_reclaim_lease(struct nfs_client *clp)
@@ -1151,55 +1233,65 @@ static int nfs4_reclaim_lease(struct nfs_client *clp)
 }
 
 #ifdef CONFIG_NFS_V4_1
-static void nfs4_session_recovery_handle_error(struct nfs_client *clp, int err)
+void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags)
 {
-       switch (err) {
-       case -NFS4ERR_STALE_CLIENTID:
+       if (!flags)
+               return;
+       else if (flags & SEQ4_STATUS_RESTART_RECLAIM_NEEDED) {
                set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
-               set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state);
-       }
+               nfs4_state_start_reclaim_reboot(clp);
+               nfs4_schedule_state_recovery(clp);
+       } else if (flags & (SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED |
+                           SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED |
+                           SEQ4_STATUS_ADMIN_STATE_REVOKED |
+                           SEQ4_STATUS_RECALLABLE_STATE_REVOKED |
+                           SEQ4_STATUS_LEASE_MOVED)) {
+               set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
+               nfs4_state_start_reclaim_nograce(clp);
+               nfs4_schedule_state_recovery(clp);
+       } else if (flags & (SEQ4_STATUS_CB_PATH_DOWN |
+                           SEQ4_STATUS_BACKCHANNEL_FAULT |
+                           SEQ4_STATUS_CB_PATH_DOWN_SESSION))
+               nfs_expire_all_delegations(clp);
 }
 
 static int nfs4_reset_session(struct nfs_client *clp)
 {
+       struct nfs4_session *ses = clp->cl_session;
        int status;
 
+       status = nfs41_begin_drain_session(clp, ses);
+       if (status != 0)
+               return status;
+
        status = nfs4_proc_destroy_session(clp->cl_session);
        if (status && status != -NFS4ERR_BADSESSION &&
            status != -NFS4ERR_DEADSESSION) {
-               nfs4_session_recovery_handle_error(clp, status);
+               status = nfs4_recovery_handle_error(clp, status);
                goto out;
        }
 
        memset(clp->cl_session->sess_id.data, 0, NFS4_MAX_SESSIONID_LEN);
-       status = nfs4_proc_create_session(clp, 1);
+       status = nfs4_proc_create_session(clp);
        if (status)
-               nfs4_session_recovery_handle_error(clp, status);
-               /* fall through*/
-out:
-       /* Wake up the next rpc task even on error */
-       rpc_wake_up_next(&clp->cl_session->fc_slot_table.slot_tbl_waitq);
-       return status;
-}
-
-static int nfs4_initialize_session(struct nfs_client *clp)
-{
-       int status;
+               status = nfs4_recovery_handle_error(clp, status);
 
-       status = nfs4_proc_create_session(clp, 0);
-       if (!status) {
-               nfs_mark_client_ready(clp, NFS_CS_READY);
-       } else if (status == -NFS4ERR_STALE_CLIENTID) {
-               set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
-               set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state);
-       } else {
-               nfs_mark_client_ready(clp, status);
+out:
+       /*
+        * Let the state manager reestablish state
+        * without waking other tasks yet.
+        */
+       if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) {
+               /* Wake up the next rpc task */
+               nfs41_end_drain_session(clp, ses);
+               if (status == 0)
+                       nfs41_setup_state_renewal(clp);
        }
        return status;
 }
+
 #else /* CONFIG_NFS_V4_1 */
 static int nfs4_reset_session(struct nfs_client *clp) { return 0; }
-static int nfs4_initialize_session(struct nfs_client *clp) { return 0; }
 #endif /* CONFIG_NFS_V4_1 */
 
 /* Set NFS4CLNT_LEASE_EXPIRED for all v4.0 errors and for recoverable errors
@@ -1234,7 +1326,8 @@ static void nfs4_state_manager(struct nfs_client *clp)
                        status = nfs4_reclaim_lease(clp);
                        if (status) {
                                nfs4_set_lease_expired(clp, status);
-                               if (status == -EAGAIN)
+                               if (test_bit(NFS4CLNT_LEASE_EXPIRED,
+                                                       &clp->cl_state))
                                        continue;
                                if (clp->cl_cons_state ==
                                                        NFS_CS_SESSION_INITING)
@@ -1242,55 +1335,51 @@ static void nfs4_state_manager(struct nfs_client *clp)
                                goto out_error;
                        }
                        clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
+                       set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state);
                }
 
                if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) {
                        status = nfs4_check_lease(clp);
-                       if (status != 0)
+                       if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
                                continue;
+                       if (status < 0 && status != -NFS4ERR_CB_PATH_DOWN)
+                               goto out_error;
                }
+
                /* Initialize or reset the session */
-               if (test_and_clear_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)
+               if (test_and_clear_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state)
                   && nfs4_has_session(clp)) {
-                       if (clp->cl_cons_state == NFS_CS_SESSION_INITING)
-                               status = nfs4_initialize_session(clp);
-                       else
-                               status = nfs4_reset_session(clp);
-                       if (status) {
-                               if (status == -NFS4ERR_STALE_CLIENTID)
-                                       continue;
+                       status = nfs4_reset_session(clp);
+                       if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
+                               continue;
+                       if (status < 0)
                                goto out_error;
-                       }
                }
+
                /* First recover reboot state... */
-               if (test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) {
+               if (test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) {
                        status = nfs4_do_reclaim(clp,
                                nfs4_reboot_recovery_ops[clp->cl_minorversion]);
-                       if (status == -NFS4ERR_STALE_CLIENTID)
-                               continue;
-                       if (test_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state))
+                       if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) ||
+                           test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state))
                                continue;
                        nfs4_state_end_reclaim_reboot(clp);
-                       continue;
+                       if (test_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state))
+                               continue;
+                       if (status < 0)
+                               goto out_error;
                }
 
                /* Now recover expired state... */
                if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) {
                        status = nfs4_do_reclaim(clp,
                                nfs4_nograce_recovery_ops[clp->cl_minorversion]);
-                       if (status < 0) {
-                               set_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state);
-                               if (status == -NFS4ERR_STALE_CLIENTID)
-                                       continue;
-                               if (status == -NFS4ERR_EXPIRED)
-                                       continue;
-                               if (test_bit(NFS4CLNT_SESSION_SETUP,
-                                                               &clp->cl_state))
-                                       continue;
+                       if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) ||
+                           test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state) ||
+                           test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state))
+                               continue;
+                       if (status < 0)
                                goto out_error;
-                       } else
-                               nfs4_state_end_reclaim_nograce(clp);
-                       continue;
                }
 
                if (test_and_clear_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) {
@@ -1309,8 +1398,6 @@ static void nfs4_state_manager(struct nfs_client *clp)
 out_error:
        printk(KERN_WARNING "Error: state manager failed on NFSv4 server %s"
                        " with error %d\n", clp->cl_hostname, -status);
-       if (test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state))
-               nfs4_state_end_reclaim_reboot(clp);
        nfs4_clear_state_manager_bit(clp);
 }
 
index 20b4e30e6c828e5e0aed77ea01c445a52caab0ee..e437fd6a819f6f5a3ea5bd7c303a3c3e6b260638 100644 (file)
 #include <linux/proc_fs.h>
 #include <linux/kdev_t.h>
 #include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/msg_prot.h>
 #include <linux/nfs.h>
 #include <linux/nfs4.h>
 #include <linux/nfs_fs.h>
 #include <linux/nfs_idmap.h>
 #include "nfs4_fs.h"
+#include "internal.h"
 
 #define NFSDBG_FACILITY                NFSDBG_XDR
 
@@ -134,7 +136,7 @@ static int nfs4_stat_to_errno(int);
 #define decode_lookup_maxsz    (op_decode_hdr_maxsz)
 #define encode_share_access_maxsz \
                                (2)
-#define encode_createmode_maxsz        (1 + encode_attrs_maxsz)
+#define encode_createmode_maxsz        (1 + encode_attrs_maxsz + encode_verifier_maxsz)
 #define encode_opentype_maxsz  (1 + encode_createmode_maxsz)
 #define encode_claim_null_maxsz        (1 + nfs4_name_maxsz)
 #define encode_open_maxsz      (op_encode_hdr_maxsz + \
@@ -299,6 +301,8 @@ static int nfs4_stat_to_errno(int);
                                XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 4)
 #define decode_sequence_maxsz  (op_decode_hdr_maxsz + \
                                XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 5)
+#define encode_reclaim_complete_maxsz  (op_encode_hdr_maxsz + 4)
+#define decode_reclaim_complete_maxsz  (op_decode_hdr_maxsz + 4)
 #else /* CONFIG_NFS_V4_1 */
 #define encode_sequence_maxsz  0
 #define decode_sequence_maxsz  0
@@ -676,6 +680,25 @@ static int nfs4_stat_to_errno(int);
                                         decode_sequence_maxsz + \
                                         decode_putrootfh_maxsz + \
                                         decode_fsinfo_maxsz)
+#define NFS4_enc_reclaim_complete_sz   (compound_encode_hdr_maxsz + \
+                                        encode_sequence_maxsz + \
+                                        encode_reclaim_complete_maxsz)
+#define NFS4_dec_reclaim_complete_sz   (compound_decode_hdr_maxsz + \
+                                        decode_sequence_maxsz + \
+                                        decode_reclaim_complete_maxsz)
+
+const u32 nfs41_maxwrite_overhead = ((RPC_MAX_HEADER_WITH_AUTH +
+                                     compound_encode_hdr_maxsz +
+                                     encode_sequence_maxsz +
+                                     encode_putfh_maxsz +
+                                     encode_getattr_maxsz) *
+                                    XDR_UNIT);
+
+const u32 nfs41_maxread_overhead = ((RPC_MAX_HEADER_WITH_AUTH +
+                                    compound_decode_hdr_maxsz +
+                                    decode_sequence_maxsz +
+                                    decode_putfh_maxsz) *
+                                   XDR_UNIT);
 #endif /* CONFIG_NFS_V4_1 */
 
 static const umode_t nfs_type2fmt[] = {
@@ -1140,6 +1163,7 @@ static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_opena
 static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_openargs *arg)
 {
        __be32 *p;
+       struct nfs_client *clp;
 
        p = reserve_space(xdr, 4);
        switch(arg->open_flags & O_EXCL) {
@@ -1148,8 +1172,23 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op
                encode_attrs(xdr, arg->u.attrs, arg->server);
                break;
        default:
-               *p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE);
-               encode_nfs4_verifier(xdr, &arg->u.verifier);
+               clp = arg->server->nfs_client;
+               if (clp->cl_minorversion > 0) {
+                       if (nfs4_has_persistent_session(clp)) {
+                               *p = cpu_to_be32(NFS4_CREATE_GUARDED);
+                               encode_attrs(xdr, arg->u.attrs, arg->server);
+                       } else {
+                               struct iattr dummy;
+
+                               *p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE4_1);
+                               encode_nfs4_verifier(xdr, &arg->u.verifier);
+                               dummy.ia_valid = 0;
+                               encode_attrs(xdr, &dummy, arg->server);
+                       }
+               } else {
+                       *p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE);
+                       encode_nfs4_verifier(xdr, &arg->u.verifier);
+               }
        }
 }
 
@@ -1592,6 +1631,19 @@ static void encode_destroy_session(struct xdr_stream *xdr,
        hdr->nops++;
        hdr->replen += decode_destroy_session_maxsz;
 }
+
+static void encode_reclaim_complete(struct xdr_stream *xdr,
+                                   struct nfs41_reclaim_complete_args *args,
+                                   struct compound_hdr *hdr)
+{
+       __be32 *p;
+
+       p = reserve_space(xdr, 8);
+       *p++ = cpu_to_be32(OP_RECLAIM_COMPLETE);
+       *p++ = cpu_to_be32(args->one_fs);
+       hdr->nops++;
+       hdr->replen += decode_reclaim_complete_maxsz;
+}
 #endif /* CONFIG_NFS_V4_1 */
 
 static void encode_sequence(struct xdr_stream *xdr,
@@ -2096,7 +2148,7 @@ nfs4_xdr_enc_getacl(struct rpc_rqst *req, __be32 *p,
        encode_compound_hdr(&xdr, req, &hdr);
        encode_sequence(&xdr, &args->seq_args, &hdr);
        encode_putfh(&xdr, args->fh, &hdr);
-       replen = hdr.replen + nfs4_fattr_bitmap_maxsz + 1;
+       replen = hdr.replen + op_decode_hdr_maxsz + nfs4_fattr_bitmap_maxsz + 1;
        encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0, &hdr);
 
        xdr_inline_pages(&req->rq_rcv_buf, replen << 2,
@@ -2420,6 +2472,26 @@ static int nfs4_xdr_enc_get_lease_time(struct rpc_rqst *req, uint32_t *p,
        encode_nops(&hdr);
        return 0;
 }
+
+/*
+ * a RECLAIM_COMPLETE request
+ */
+static int nfs4_xdr_enc_reclaim_complete(struct rpc_rqst *req, uint32_t *p,
+                                    struct nfs41_reclaim_complete_args *args)
+{
+       struct xdr_stream xdr;
+       struct compound_hdr hdr = {
+               .minorversion = nfs4_xdr_minorversion(&args->seq_args)
+       };
+
+       xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+       encode_compound_hdr(&xdr, req, &hdr);
+       encode_sequence(&xdr, &args->seq_args, &hdr);
+       encode_reclaim_complete(&xdr, args, &hdr);
+       encode_nops(&hdr);
+       return 0;
+}
+
 #endif /* CONFIG_NFS_V4_1 */
 
 static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
@@ -4528,6 +4600,11 @@ static int decode_destroy_session(struct xdr_stream *xdr, void *dummy)
 {
        return decode_op_hdr(xdr, OP_DESTROY_SESSION);
 }
+
+static int decode_reclaim_complete(struct xdr_stream *xdr, void *dummy)
+{
+       return decode_op_hdr(xdr, OP_RECLAIM_COMPLETE);
+}
 #endif /* CONFIG_NFS_V4_1 */
 
 static int decode_sequence(struct xdr_stream *xdr,
@@ -4583,8 +4660,8 @@ static int decode_sequence(struct xdr_stream *xdr,
        dummy = be32_to_cpup(p++);
        /* target highest slot id - currently not processed */
        dummy = be32_to_cpup(p++);
-       /* result flags - currently not processed */
-       dummy = be32_to_cpup(p);
+       /* result flags */
+       res->sr_status_flags = be32_to_cpup(p);
        status = 0;
 out_err:
        res->sr_status = status;
@@ -5309,7 +5386,7 @@ out:
 }
 
 /*
- * FSINFO request
+ * Decode FSINFO response
  */
 static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p,
                               struct nfs4_fsinfo_res *res)
@@ -5330,7 +5407,7 @@ static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p,
 }
 
 /*
- * PATHCONF request
+ * Decode PATHCONF response
  */
 static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p,
                                 struct nfs4_pathconf_res *res)
@@ -5351,7 +5428,7 @@ static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p,
 }
 
 /*
- * STATFS request
+ * Decode STATFS response
  */
 static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p,
                               struct nfs4_statfs_res *res)
@@ -5372,7 +5449,7 @@ static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p,
 }
 
 /*
- * GETATTR_BITMAP request
+ * Decode GETATTR_BITMAP response
  */
 static int nfs4_xdr_dec_server_caps(struct rpc_rqst *req, __be32 *p, struct nfs4_server_caps_res *res)
 {
@@ -5411,7 +5488,7 @@ static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, __be32 *p, void *dummy)
 }
 
 /*
- * a SETCLIENTID request
+ * Decode SETCLIENTID response
  */
 static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, __be32 *p,
                struct nfs_client *clp)
@@ -5428,7 +5505,7 @@ static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, __be32 *p,
 }
 
 /*
- * a SETCLIENTID_CONFIRM request
+ * Decode SETCLIENTID_CONFIRM response
  */
 static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *fsinfo)
 {
@@ -5448,7 +5525,7 @@ static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, __be32 *p, str
 }
 
 /*
- * DELEGRETURN request
+ * Decode DELEGRETURN response
  */
 static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_delegreturnres *res)
 {
@@ -5474,7 +5551,7 @@ out:
 }
 
 /*
- * FS_LOCATIONS request
+ * Decode FS_LOCATIONS response
  */
 static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p,
                                     struct nfs4_fs_locations_res *res)
@@ -5504,7 +5581,7 @@ out:
 
 #if defined(CONFIG_NFS_V4_1)
 /*
- * EXCHANGE_ID request
+ * Decode EXCHANGE_ID response
  */
 static int nfs4_xdr_dec_exchange_id(struct rpc_rqst *rqstp, uint32_t *p,
                                    void *res)
@@ -5521,7 +5598,7 @@ static int nfs4_xdr_dec_exchange_id(struct rpc_rqst *rqstp, uint32_t *p,
 }
 
 /*
- * a CREATE_SESSION request
+ * Decode CREATE_SESSION response
  */
 static int nfs4_xdr_dec_create_session(struct rpc_rqst *rqstp, uint32_t *p,
                                       struct nfs41_create_session_res *res)
@@ -5538,7 +5615,7 @@ static int nfs4_xdr_dec_create_session(struct rpc_rqst *rqstp, uint32_t *p,
 }
 
 /*
- * a DESTROY_SESSION request
+ * Decode DESTROY_SESSION response
  */
 static int nfs4_xdr_dec_destroy_session(struct rpc_rqst *rqstp, uint32_t *p,
                                        void *dummy)
@@ -5555,7 +5632,7 @@ static int nfs4_xdr_dec_destroy_session(struct rpc_rqst *rqstp, uint32_t *p,
 }
 
 /*
- * a SEQUENCE request
+ * Decode SEQUENCE response
  */
 static int nfs4_xdr_dec_sequence(struct rpc_rqst *rqstp, uint32_t *p,
                                 struct nfs4_sequence_res *res)
@@ -5572,7 +5649,7 @@ static int nfs4_xdr_dec_sequence(struct rpc_rqst *rqstp, uint32_t *p,
 }
 
 /*
- * a GET_LEASE_TIME request
+ * Decode GET_LEASE_TIME response
  */
 static int nfs4_xdr_dec_get_lease_time(struct rpc_rqst *rqstp, uint32_t *p,
                                       struct nfs4_get_lease_time_res *res)
@@ -5591,6 +5668,25 @@ static int nfs4_xdr_dec_get_lease_time(struct rpc_rqst *rqstp, uint32_t *p,
                status = decode_fsinfo(&xdr, res->lr_fsinfo);
        return status;
 }
+
+/*
+ * Decode RECLAIM_COMPLETE response
+ */
+static int nfs4_xdr_dec_reclaim_complete(struct rpc_rqst *rqstp, uint32_t *p,
+                                        struct nfs41_reclaim_complete_res *res)
+{
+       struct xdr_stream xdr;
+       struct compound_hdr hdr;
+       int status;
+
+       xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+       status = decode_compound_hdr(&xdr, &hdr);
+       if (!status)
+               status = decode_sequence(&xdr, &res->seq_res, rqstp);
+       if (!status)
+               status = decode_reclaim_complete(&xdr, (void *)NULL);
+       return status;
+}
 #endif /* CONFIG_NFS_V4_1 */
 
 __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
@@ -5767,6 +5863,7 @@ struct rpc_procinfo       nfs4_procedures[] = {
   PROC(DESTROY_SESSION,        enc_destroy_session,    dec_destroy_session),
   PROC(SEQUENCE,       enc_sequence,   dec_sequence),
   PROC(GET_LEASE_TIME, enc_get_lease_time,     dec_get_lease_time),
+  PROC(RECLAIM_COMPLETE, enc_reclaim_complete,  dec_reclaim_complete),
 #endif /* CONFIG_NFS_V4_1 */
 };
 
index 12c9e66d3f1d9739147573ecd00cbc703f9f70a8..db9b360ae19da9e61b13152318c6fc59013074ec 100644 (file)
@@ -356,25 +356,19 @@ static void nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data
        struct nfs_readres *resp = &data->res;
 
        if (resp->eof || resp->count == argp->count)
-               goto out;
+               return;
 
        /* This is a short read! */
        nfs_inc_stats(data->inode, NFSIOS_SHORTREAD);
        /* Has the server at least made some progress? */
        if (resp->count == 0)
-               goto out;
+               return;
 
        /* Yes, so retry the read at the end of the data */
        argp->offset += resp->count;
        argp->pgbase += resp->count;
        argp->count -= resp->count;
-       nfs4_restart_rpc(task, NFS_SERVER(data->inode)->nfs_client);
-       return;
-out:
-       nfs4_sequence_free_slot(NFS_SERVER(data->inode)->nfs_client,
-                               &data->res.seq_res);
-       return;
-
+       nfs_restart_rpc(task, NFS_SERVER(data->inode)->nfs_client);
 }
 
 /*
index 90be551b80c19fa2733349cbecfdfe231f2a5573..ce907efc5508f049a9ff000a28f8d082159704ce 100644 (file)
@@ -175,14 +175,16 @@ static const match_table_t nfs_mount_option_tokens = {
 };
 
 enum {
-       Opt_xprt_udp, Opt_xprt_tcp, Opt_xprt_rdma,
+       Opt_xprt_udp, Opt_xprt_udp6, Opt_xprt_tcp, Opt_xprt_tcp6, Opt_xprt_rdma,
 
        Opt_xprt_err
 };
 
 static const match_table_t nfs_xprt_protocol_tokens = {
        { Opt_xprt_udp, "udp" },
+       { Opt_xprt_udp6, "udp6" },
        { Opt_xprt_tcp, "tcp" },
+       { Opt_xprt_tcp6, "tcp6" },
        { Opt_xprt_rdma, "rdma" },
 
        { Opt_xprt_err, NULL }
@@ -492,6 +494,45 @@ static const char *nfs_pseudoflavour_to_name(rpc_authflavor_t flavour)
        return sec_flavours[i].str;
 }
 
+static void nfs_show_mountd_netid(struct seq_file *m, struct nfs_server *nfss,
+                                 int showdefaults)
+{
+       struct sockaddr *sap = (struct sockaddr *) &nfss->mountd_address;
+
+       seq_printf(m, ",mountproto=");
+       switch (sap->sa_family) {
+       case AF_INET:
+               switch (nfss->mountd_protocol) {
+               case IPPROTO_UDP:
+                       seq_printf(m, RPCBIND_NETID_UDP);
+                       break;
+               case IPPROTO_TCP:
+                       seq_printf(m, RPCBIND_NETID_TCP);
+                       break;
+               default:
+                       if (showdefaults)
+                               seq_printf(m, "auto");
+               }
+               break;
+       case AF_INET6:
+               switch (nfss->mountd_protocol) {
+               case IPPROTO_UDP:
+                       seq_printf(m, RPCBIND_NETID_UDP6);
+                       break;
+               case IPPROTO_TCP:
+                       seq_printf(m, RPCBIND_NETID_TCP6);
+                       break;
+               default:
+                       if (showdefaults)
+                               seq_printf(m, "auto");
+               }
+               break;
+       default:
+               if (showdefaults)
+                       seq_printf(m, "auto");
+       }
+}
+
 static void nfs_show_mountd_options(struct seq_file *m, struct nfs_server *nfss,
                                    int showdefaults)
 {
@@ -505,7 +546,7 @@ static void nfs_show_mountd_options(struct seq_file *m, struct nfs_server *nfss,
        }
        case AF_INET6: {
                struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
-               seq_printf(m, ",mountaddr=%pI6", &sin6->sin6_addr);
+               seq_printf(m, ",mountaddr=%pI6c", &sin6->sin6_addr);
                break;
        }
        default:
@@ -518,17 +559,7 @@ static void nfs_show_mountd_options(struct seq_file *m, struct nfs_server *nfss,
        if (nfss->mountd_port || showdefaults)
                seq_printf(m, ",mountport=%u", nfss->mountd_port);
 
-       switch (nfss->mountd_protocol) {
-       case IPPROTO_UDP:
-               seq_printf(m, ",mountproto=udp");
-               break;
-       case IPPROTO_TCP:
-               seq_printf(m, ",mountproto=tcp");
-               break;
-       default:
-               if (showdefaults)
-                       seq_printf(m, ",mountproto=auto");
-       }
+       nfs_show_mountd_netid(m, nfss, showdefaults);
 }
 
 /*
@@ -578,7 +609,7 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
                        seq_puts(m, nfs_infop->nostr);
        }
        seq_printf(m, ",proto=%s",
-                  rpc_peeraddr2str(nfss->client, RPC_DISPLAY_PROTO));
+                  rpc_peeraddr2str(nfss->client, RPC_DISPLAY_NETID));
        if (version == 4) {
                if (nfss->port != NFS_PORT)
                        seq_printf(m, ",port=%u", nfss->port);
@@ -714,8 +745,6 @@ static void nfs_umount_begin(struct super_block *sb)
        struct nfs_server *server;
        struct rpc_clnt *rpc;
 
-       lock_kernel();
-
        server = NFS_SB(sb);
        /* -EIO all pending I/O */
        rpc = server->client_acl;
@@ -724,8 +753,6 @@ static void nfs_umount_begin(struct super_block *sb)
        rpc = server->client;
        if (!IS_ERR(rpc))
                rpc_killall_tasks(rpc);
-
-       unlock_kernel();
 }
 
 static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(unsigned int version)
@@ -734,8 +761,6 @@ static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(unsigned int ve
 
        data = kzalloc(sizeof(*data), GFP_KERNEL);
        if (data) {
-               data->rsize             = NFS_MAX_FILE_IO_SIZE;
-               data->wsize             = NFS_MAX_FILE_IO_SIZE;
                data->acregmin          = NFS_DEF_ACREGMIN;
                data->acregmax          = NFS_DEF_ACREGMAX;
                data->acdirmin          = NFS_DEF_ACDIRMIN;
@@ -887,6 +912,8 @@ static int nfs_parse_mount_options(char *raw,
 {
        char *p, *string, *secdata;
        int rc, sloppy = 0, invalid_option = 0;
+       unsigned short protofamily = AF_UNSPEC;
+       unsigned short mountfamily = AF_UNSPEC;
 
        if (!raw) {
                dfprintk(MOUNT, "NFS: mount options string was NULL.\n");
@@ -1232,12 +1259,17 @@ static int nfs_parse_mount_options(char *raw,
                        token = match_token(string,
                                            nfs_xprt_protocol_tokens, args);
 
+                       protofamily = AF_INET;
                        switch (token) {
+                       case Opt_xprt_udp6:
+                               protofamily = AF_INET6;
                        case Opt_xprt_udp:
                                mnt->flags &= ~NFS_MOUNT_TCP;
                                mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
                                kfree(string);
                                break;
+                       case Opt_xprt_tcp6:
+                               protofamily = AF_INET6;
                        case Opt_xprt_tcp:
                                mnt->flags |= NFS_MOUNT_TCP;
                                mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
@@ -1265,10 +1297,15 @@ static int nfs_parse_mount_options(char *raw,
                                            nfs_xprt_protocol_tokens, args);
                        kfree(string);
 
+                       mountfamily = AF_INET;
                        switch (token) {
+                       case Opt_xprt_udp6:
+                               mountfamily = AF_INET6;
                        case Opt_xprt_udp:
                                mnt->mount_server.protocol = XPRT_TRANSPORT_UDP;
                                break;
+                       case Opt_xprt_tcp6:
+                               mountfamily = AF_INET6;
                        case Opt_xprt_tcp:
                                mnt->mount_server.protocol = XPRT_TRANSPORT_TCP;
                                break;
@@ -1367,8 +1404,33 @@ static int nfs_parse_mount_options(char *raw,
        if (!sloppy && invalid_option)
                return 0;
 
+       /*
+        * verify that any proto=/mountproto= options match the address
+        * familiies in the addr=/mountaddr= options.
+        */
+       if (protofamily != AF_UNSPEC &&
+           protofamily != mnt->nfs_server.address.ss_family)
+               goto out_proto_mismatch;
+
+       if (mountfamily != AF_UNSPEC) {
+               if (mnt->mount_server.addrlen) {
+                       if (mountfamily != mnt->mount_server.address.ss_family)
+                               goto out_mountproto_mismatch;
+               } else {
+                       if (mountfamily != mnt->nfs_server.address.ss_family)
+                               goto out_mountproto_mismatch;
+               }
+       }
+
        return 1;
 
+out_mountproto_mismatch:
+       printk(KERN_INFO "NFS: mount server address does not match mountproto= "
+                        "option\n");
+       return 0;
+out_proto_mismatch:
+       printk(KERN_INFO "NFS: server address does not match proto= option\n");
+       return 0;
 out_invalid_address:
        printk(KERN_INFO "NFS: bad IP address specified: %s\n", p);
        return 0;
@@ -1881,7 +1943,6 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data)
        if (data == NULL)
                return -ENOMEM;
 
-       lock_kernel();
        /* fill out struct with values from existing mount */
        data->flags = nfss->flags;
        data->rsize = nfss->rsize;
@@ -1907,7 +1968,6 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data)
        error = nfs_compare_remount_data(nfss, data);
 out:
        kfree(data);
-       unlock_kernel();
        return error;
 }
 
index 1064c91ae810c3496f621729cbc754653be69a8e..6da3d3ff6edd652fdcaf5934ea5056acdd062135 100644 (file)
@@ -83,7 +83,7 @@ static void nfs_async_unlink_done(struct rpc_task *task, void *calldata)
        struct inode *dir = data->dir;
 
        if (!NFS_PROTO(dir)->unlink_done(task, dir))
-               nfs4_restart_rpc(task, NFS_SERVER(dir)->nfs_client);
+               nfs_restart_rpc(task, NFS_SERVER(dir)->nfs_client);
 }
 
 /**
index b1ce2ea9b93bf4a3e1bdae9b110bcb1793a7d82d..d171696017f4befe44f85ffd79b138f88db7c214 100644 (file)
@@ -1216,7 +1216,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
                                 */
                                argp->stable = NFS_FILE_SYNC;
                        }
-                       nfs4_restart_rpc(task, server->nfs_client);
+                       nfs_restart_rpc(task, server->nfs_client);
                        return -EAGAIN;
                }
                if (time_before(complain, jiffies)) {
@@ -1228,7 +1228,6 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
                /* Can't do anything about it except throw an error. */
                task->tk_status = -EIO;
        }
-       nfs4_sequence_free_slot(server->nfs_client, &data->res.seq_res);
        return 0;
 }
 
@@ -1612,15 +1611,16 @@ int nfs_migrate_page(struct address_space *mapping, struct page *newpage,
        if (ret)
                goto out_unlock;
        page_cache_get(newpage);
+       spin_lock(&mapping->host->i_lock);
        req->wb_page = newpage;
        SetPagePrivate(newpage);
-       set_page_private(newpage, page_private(page));
+       set_page_private(newpage, (unsigned long)req);
        ClearPagePrivate(page);
        set_page_private(page, 0);
+       spin_unlock(&mapping->host->i_lock);
        page_cache_release(page);
 out_unlock:
        nfs_clear_page_tag_locked(req);
-       nfs_release_request(req);
 out:
        return ret;
 }
index 66a888a9ad6f87a0f913bc6b1508d0f8897927fb..bfffd6334abbfae37d804174241bc1a1c17760d3 100644 (file)
@@ -2389,12 +2389,12 @@ xfs_icsb_modify_counters(
 {
        xfs_icsb_cnts_t *icsbp;
        long long       lcounter;       /* long counter for 64 bit fields */
-       int             cpu, ret = 0;
+       int             ret = 0;
 
        might_sleep();
 again:
-       cpu = get_cpu();
-       icsbp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, cpu);
+       preempt_disable();
+       icsbp = this_cpu_ptr(mp->m_sb_cnts);
 
        /*
         * if the counter is disabled, go to slow path
@@ -2438,11 +2438,11 @@ again:
                break;
        }
        xfs_icsb_unlock_cntr(icsbp);
-       put_cpu();
+       preempt_enable();
        return 0;
 
 slow_path:
-       put_cpu();
+       preempt_enable();
 
        /*
         * serialise with a mutex so we don't burn lots of cpu on
@@ -2490,7 +2490,7 @@ slow_path:
 
 balance_counter:
        xfs_icsb_unlock_cntr(icsbp);
-       put_cpu();
+       preempt_enable();
 
        /*
         * We may have multiple threads here if multiple per-cpu
index 90079c373f1c462d2957b98b64f5f15b8ea7ac19..8087b90d4673d52cdd2f2d8ccf888009b7d0e115 100644 (file)
@@ -56,6 +56,9 @@ extern unsigned long __per_cpu_offset[NR_CPUS];
 #define __raw_get_cpu_var(var) \
        (*SHIFT_PERCPU_PTR(&per_cpu_var(var), __my_cpu_offset))
 
+#define this_cpu_ptr(ptr) SHIFT_PERCPU_PTR(ptr, my_cpu_offset)
+#define __this_cpu_ptr(ptr) SHIFT_PERCPU_PTR(ptr, __my_cpu_offset)
+
 
 #ifdef CONFIG_HAVE_SETUP_PER_CPU_AREA
 extern void setup_per_cpu_areas(void);
@@ -66,6 +69,8 @@ extern void setup_per_cpu_areas(void);
 #define per_cpu(var, cpu)                      (*((void)(cpu), &per_cpu_var(var)))
 #define __get_cpu_var(var)                     per_cpu_var(var)
 #define __raw_get_cpu_var(var)                 per_cpu_var(var)
+#define this_cpu_ptr(ptr) per_cpu_ptr(ptr, 0)
+#define __this_cpu_ptr(ptr) this_cpu_ptr(ptr)
 
 #endif /* SMP */
 
index 69f07a9f1277bceb76fddc3b4ff2d223b6787368..41235c93e4e95400bf0db52bf2f7b84399d22a39 100644 (file)
@@ -93,7 +93,7 @@ register_user_hw_breakpoint(struct perf_event_attr *attr,
                            struct task_struct *tsk)    { return NULL; }
 static inline int
 modify_user_hw_breakpoint(struct perf_event *bp,
-                         struct perf_event_attr *attr) { return NULL; }
+                         struct perf_event_attr *attr) { return -ENOSYS; }
 static inline struct perf_event *
 register_wide_hw_breakpoint_cpu(struct perf_event_attr *attr,
                                perf_overflow_handler_t  triggered,
index 918c5354d9b8967825c12882852803b0e6470785..08aa92278d71cdd6b388c24d8fdb083c719e291b 100644 (file)
 #define        TPS_VDCDC1              0x0c
 #      define  TPS_ENABLE_LP           (1 << 3)
 #define        TPS_VDCDC2              0x0d
+#      define  TPS_LP_COREOFF  (1 << 7)
+#      define  TPS_VCORE_1_8V  (7<<4)
+#      define  TPS_VCORE_1_5V  (6 << 4)
+#      define  TPS_VCORE_1_4V  (5 << 4)
+#      define  TPS_VCORE_1_3V  (4 << 4)
+#      define  TPS_VCORE_1_2V  (3 << 4)
+#      define  TPS_VCORE_1_1V  (2 << 4)
+#      define  TPS_VCORE_1_0V  (1 << 4)
+#      define  TPS_VCORE_0_85V (0 << 4)
+#      define  TPS_VCORE_LP_1_2V (3 << 2)
+#      define  TPS_VCORE_LP_1_1V (2 << 2)
+#      define  TPS_VCORE_LP_1_0V (1 << 2)
+#      define  TPS_VCORE_LP_0_85V (0 << 2)
+#      define  TPS_VIB         (1 << 1)
+#      define  TPS_VCORE_DISCH (1 << 0)
 #define        TPS_VREGS1              0x0e
 #      define  TPS_LDO2_ENABLE (1 << 7)
 #      define  TPS_LDO2_OFF    (1 << 6)
@@ -152,6 +167,10 @@ extern int tps65010_config_vregs1(unsigned value);
  */
 extern int tps65013_set_low_pwr(unsigned mode);
 
+/* tps65010_set_vdcdc2
+ *  value to be written to VDCDC2
+ */
+extern int tps65010_config_vdcdc2(unsigned value);
 
 struct i2c_client;
 
diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h
new file mode 100644 (file)
index 0000000..bf1c5be
--- /dev/null
@@ -0,0 +1,673 @@
+/*
+ * twl4030.h - header for TWL4030 PM and audio CODEC device
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * Based on tlv320aic23.c:
+ * Copyright (c) by Kai Svahn <kai.svahn@nokia.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
+ *
+ */
+
+#ifndef __TWL_H_
+#define __TWL_H_
+
+#include <linux/types.h>
+#include <linux/input/matrix_keypad.h>
+
+/*
+ * Using the twl4030 core we address registers using a pair
+ *     { module id, relative register offset }
+ * which that core then maps to the relevant
+ *     { i2c slave, absolute register address }
+ *
+ * The module IDs are meaningful only to the twl4030 core code,
+ * which uses them as array indices to look up the first register
+ * address each module uses within a given i2c slave.
+ */
+
+/* Slave 0 (i2c address 0x48) */
+#define TWL4030_MODULE_USB             0x00
+
+/* Slave 1 (i2c address 0x49) */
+#define TWL4030_MODULE_AUDIO_VOICE     0x01
+#define TWL4030_MODULE_GPIO            0x02
+#define TWL4030_MODULE_INTBR           0x03
+#define TWL4030_MODULE_PIH             0x04
+#define TWL4030_MODULE_TEST            0x05
+
+/* Slave 2 (i2c address 0x4a) */
+#define TWL4030_MODULE_KEYPAD          0x06
+#define TWL4030_MODULE_MADC            0x07
+#define TWL4030_MODULE_INTERRUPTS      0x08
+#define TWL4030_MODULE_LED             0x09
+#define TWL4030_MODULE_MAIN_CHARGE     0x0A
+#define TWL4030_MODULE_PRECHARGE       0x0B
+#define TWL4030_MODULE_PWM0            0x0C
+#define TWL4030_MODULE_PWM1            0x0D
+#define TWL4030_MODULE_PWMA            0x0E
+#define TWL4030_MODULE_PWMB            0x0F
+
+#define TWL5031_MODULE_ACCESSORY       0x10
+#define TWL5031_MODULE_INTERRUPTS      0x11
+
+/* Slave 3 (i2c address 0x4b) */
+#define TWL4030_MODULE_BACKUP          0x12
+#define TWL4030_MODULE_INT             0x13
+#define TWL4030_MODULE_PM_MASTER       0x14
+#define TWL4030_MODULE_PM_RECEIVER     0x15
+#define TWL4030_MODULE_RTC             0x16
+#define TWL4030_MODULE_SECURED_REG     0x17
+
+#define TWL_MODULE_USB         TWL4030_MODULE_USB
+#define TWL_MODULE_AUDIO_VOICE TWL4030_MODULE_AUDIO_VOICE
+#define TWL_MODULE_PIH         TWL4030_MODULE_PIH
+#define TWL_MODULE_MADC                TWL4030_MODULE_MADC
+#define TWL_MODULE_MAIN_CHARGE TWL4030_MODULE_MAIN_CHARGE
+#define TWL_MODULE_PM_MASTER   TWL4030_MODULE_PM_MASTER
+#define TWL_MODULE_PM_RECEIVER TWL4030_MODULE_PM_RECEIVER
+#define TWL_MODULE_RTC         TWL4030_MODULE_RTC
+
+#define GPIO_INTR_OFFSET       0
+#define KEYPAD_INTR_OFFSET     1
+#define BCI_INTR_OFFSET                2
+#define MADC_INTR_OFFSET       3
+#define USB_INTR_OFFSET                4
+#define BCI_PRES_INTR_OFFSET   9
+#define USB_PRES_INTR_OFFSET   10
+#define RTC_INTR_OFFSET                11
+
+/*
+ * Offset from TWL6030_IRQ_BASE / pdata->irq_base
+ */
+#define PWR_INTR_OFFSET                0
+#define HOTDIE_INTR_OFFSET     12
+#define SMPSLDO_INTR_OFFSET    13
+#define BATDETECT_INTR_OFFSET  14
+#define SIMDETECT_INTR_OFFSET  15
+#define MMCDETECT_INTR_OFFSET  16
+#define GASGAUGE_INTR_OFFSET   17
+#define USBOTG_INTR_OFFSET     4
+#define CHARGER_INTR_OFFSET    2
+#define RSV_INTR_OFFSET                0
+
+/* INT register offsets */
+#define REG_INT_STS_A                  0x00
+#define REG_INT_STS_B                  0x01
+#define REG_INT_STS_C                  0x02
+
+#define REG_INT_MSK_LINE_A             0x03
+#define REG_INT_MSK_LINE_B             0x04
+#define REG_INT_MSK_LINE_C             0x05
+
+#define REG_INT_MSK_STS_A              0x06
+#define REG_INT_MSK_STS_B              0x07
+#define REG_INT_MSK_STS_C              0x08
+
+/* MASK INT REG GROUP A */
+#define TWL6030_PWR_INT_MASK           0x07
+#define TWL6030_RTC_INT_MASK           0x18
+#define TWL6030_HOTDIE_INT_MASK        0x20
+#define TWL6030_SMPSLDOA_INT_MASK      0xC0
+
+/* MASK INT REG GROUP B */
+#define TWL6030_SMPSLDOB_INT_MASK      0x01
+#define TWL6030_BATDETECT_INT_MASK     0x02
+#define TWL6030_SIMDETECT_INT_MASK     0x04
+#define TWL6030_MMCDETECT_INT_MASK     0x08
+#define TWL6030_GPADC_INT_MASK                 0x60
+#define TWL6030_GASGAUGE_INT_MASK      0x80
+
+/* MASK INT REG GROUP C */
+#define TWL6030_USBOTG_INT_MASK        0x0F
+#define TWL6030_CHARGER_CTRL_INT_MASK  0x10
+#define TWL6030_CHARGER_FAULT_INT_MASK         0x60
+
+
+#define TWL4030_CLASS_ID               0x4030
+#define TWL6030_CLASS_ID               0x6030
+unsigned int twl_rev(void);
+#define GET_TWL_REV (twl_rev())
+#define TWL_CLASS_IS(class, id)                        \
+static inline int twl_class_is_ ##class(void)  \
+{                                              \
+       return ((id) == (GET_TWL_REV)) ? 1 : 0; \
+}
+
+TWL_CLASS_IS(4030, TWL4030_CLASS_ID)
+TWL_CLASS_IS(6030, TWL6030_CLASS_ID)
+
+/*
+ * Read and write single 8-bit registers
+ */
+int twl_i2c_write_u8(u8 mod_no, u8 val, u8 reg);
+int twl_i2c_read_u8(u8 mod_no, u8 *val, u8 reg);
+
+/*
+ * Read and write several 8-bit registers at once.
+ *
+ * IMPORTANT:  For twl_i2c_write(), allocate num_bytes + 1
+ * for the value, and populate your data starting at offset 1.
+ */
+int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes);
+int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes);
+
+int twl6030_interrupt_unmask(u8 bit_mask, u8 offset);
+int twl6030_interrupt_mask(u8 bit_mask, u8 offset);
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * NOTE:  at up to 1024 registers, this is a big chip.
+ *
+ * Avoid putting register declarations in this file, instead of into
+ * a driver-private file, unless some of the registers in a block
+ * need to be shared with other drivers.  One example is blocks that
+ * have Secondary IRQ Handler (SIH) registers.
+ */
+
+#define TWL4030_SIH_CTRL_EXCLEN_MASK   BIT(0)
+#define TWL4030_SIH_CTRL_PENDDIS_MASK  BIT(1)
+#define TWL4030_SIH_CTRL_COR_MASK      BIT(2)
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * GPIO Block Register offsets (use TWL4030_MODULE_GPIO)
+ */
+
+#define REG_GPIODATAIN1                        0x0
+#define REG_GPIODATAIN2                        0x1
+#define REG_GPIODATAIN3                        0x2
+#define REG_GPIODATADIR1               0x3
+#define REG_GPIODATADIR2               0x4
+#define REG_GPIODATADIR3               0x5
+#define REG_GPIODATAOUT1               0x6
+#define REG_GPIODATAOUT2               0x7
+#define REG_GPIODATAOUT3               0x8
+#define REG_CLEARGPIODATAOUT1          0x9
+#define REG_CLEARGPIODATAOUT2          0xA
+#define REG_CLEARGPIODATAOUT3          0xB
+#define REG_SETGPIODATAOUT1            0xC
+#define REG_SETGPIODATAOUT2            0xD
+#define REG_SETGPIODATAOUT3            0xE
+#define REG_GPIO_DEBEN1                        0xF
+#define REG_GPIO_DEBEN2                        0x10
+#define REG_GPIO_DEBEN3                        0x11
+#define REG_GPIO_CTRL                  0x12
+#define REG_GPIOPUPDCTR1               0x13
+#define REG_GPIOPUPDCTR2               0x14
+#define REG_GPIOPUPDCTR3               0x15
+#define REG_GPIOPUPDCTR4               0x16
+#define REG_GPIOPUPDCTR5               0x17
+#define REG_GPIO_ISR1A                 0x19
+#define REG_GPIO_ISR2A                 0x1A
+#define REG_GPIO_ISR3A                 0x1B
+#define REG_GPIO_IMR1A                 0x1C
+#define REG_GPIO_IMR2A                 0x1D
+#define REG_GPIO_IMR3A                 0x1E
+#define REG_GPIO_ISR1B                 0x1F
+#define REG_GPIO_ISR2B                 0x20
+#define REG_GPIO_ISR3B                 0x21
+#define REG_GPIO_IMR1B                 0x22
+#define REG_GPIO_IMR2B                 0x23
+#define REG_GPIO_IMR3B                 0x24
+#define REG_GPIO_EDR1                  0x28
+#define REG_GPIO_EDR2                  0x29
+#define REG_GPIO_EDR3                  0x2A
+#define REG_GPIO_EDR4                  0x2B
+#define REG_GPIO_EDR5                  0x2C
+#define REG_GPIO_SIH_CTRL              0x2D
+
+/* Up to 18 signals are available as GPIOs, when their
+ * pins are not assigned to another use (such as ULPI/USB).
+ */
+#define TWL4030_GPIO_MAX               18
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * Keypad register offsets (use TWL4030_MODULE_KEYPAD)
+ * ... SIH/interrupt only
+ */
+
+#define TWL4030_KEYPAD_KEYP_ISR1       0x11
+#define TWL4030_KEYPAD_KEYP_IMR1       0x12
+#define TWL4030_KEYPAD_KEYP_ISR2       0x13
+#define TWL4030_KEYPAD_KEYP_IMR2       0x14
+#define TWL4030_KEYPAD_KEYP_SIR                0x15    /* test register */
+#define TWL4030_KEYPAD_KEYP_EDR                0x16
+#define TWL4030_KEYPAD_KEYP_SIH_CTRL   0x17
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * Multichannel ADC register offsets (use TWL4030_MODULE_MADC)
+ * ... SIH/interrupt only
+ */
+
+#define TWL4030_MADC_ISR1              0x61
+#define TWL4030_MADC_IMR1              0x62
+#define TWL4030_MADC_ISR2              0x63
+#define TWL4030_MADC_IMR2              0x64
+#define TWL4030_MADC_SIR               0x65    /* test register */
+#define TWL4030_MADC_EDR               0x66
+#define TWL4030_MADC_SIH_CTRL          0x67
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * Battery charger register offsets (use TWL4030_MODULE_INTERRUPTS)
+ */
+
+#define TWL4030_INTERRUPTS_BCIISR1A    0x0
+#define TWL4030_INTERRUPTS_BCIISR2A    0x1
+#define TWL4030_INTERRUPTS_BCIIMR1A    0x2
+#define TWL4030_INTERRUPTS_BCIIMR2A    0x3
+#define TWL4030_INTERRUPTS_BCIISR1B    0x4
+#define TWL4030_INTERRUPTS_BCIISR2B    0x5
+#define TWL4030_INTERRUPTS_BCIIMR1B    0x6
+#define TWL4030_INTERRUPTS_BCIIMR2B    0x7
+#define TWL4030_INTERRUPTS_BCISIR1     0x8     /* test register */
+#define TWL4030_INTERRUPTS_BCISIR2     0x9     /* test register */
+#define TWL4030_INTERRUPTS_BCIEDR1     0xa
+#define TWL4030_INTERRUPTS_BCIEDR2     0xb
+#define TWL4030_INTERRUPTS_BCIEDR3     0xc
+#define TWL4030_INTERRUPTS_BCISIHCTRL  0xd
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * Power Interrupt block register offsets (use TWL4030_MODULE_INT)
+ */
+
+#define TWL4030_INT_PWR_ISR1           0x0
+#define TWL4030_INT_PWR_IMR1           0x1
+#define TWL4030_INT_PWR_ISR2           0x2
+#define TWL4030_INT_PWR_IMR2           0x3
+#define TWL4030_INT_PWR_SIR            0x4     /* test register */
+#define TWL4030_INT_PWR_EDR1           0x5
+#define TWL4030_INT_PWR_EDR2           0x6
+#define TWL4030_INT_PWR_SIH_CTRL       0x7
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * Accessory Interrupts
+ */
+#define TWL5031_ACIIMR_LSB             0x05
+#define TWL5031_ACIIMR_MSB             0x06
+#define TWL5031_ACIIDR_LSB             0x07
+#define TWL5031_ACIIDR_MSB             0x08
+#define TWL5031_ACCISR1                        0x0F
+#define TWL5031_ACCIMR1                        0x10
+#define TWL5031_ACCISR2                        0x11
+#define TWL5031_ACCIMR2                        0x12
+#define TWL5031_ACCSIR                 0x13
+#define TWL5031_ACCEDR1                        0x14
+#define TWL5031_ACCSIHCTRL             0x15
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * Battery Charger Controller
+ */
+
+#define TWL5031_INTERRUPTS_BCIISR1     0x0
+#define TWL5031_INTERRUPTS_BCIIMR1     0x1
+#define TWL5031_INTERRUPTS_BCIISR2     0x2
+#define TWL5031_INTERRUPTS_BCIIMR2     0x3
+#define TWL5031_INTERRUPTS_BCISIR      0x4
+#define TWL5031_INTERRUPTS_BCIEDR1     0x5
+#define TWL5031_INTERRUPTS_BCIEDR2     0x6
+#define TWL5031_INTERRUPTS_BCISIHCTRL  0x7
+
+/*----------------------------------------------------------------------*/
+
+/* Power bus message definitions */
+
+/* The TWL4030/5030 splits its power-management resources (the various
+ * regulators, clock and reset lines) into 3 processor groups - P1, P2 and
+ * P3. These groups can then be configured to transition between sleep, wait-on
+ * and active states by sending messages to the power bus.  See Section 5.4.2
+ * Power Resources of TWL4030 TRM
+ */
+
+/* Processor groups */
+#define DEV_GRP_NULL           0x0
+#define DEV_GRP_P1             0x1     /* P1: all OMAP devices */
+#define DEV_GRP_P2             0x2     /* P2: all Modem devices */
+#define DEV_GRP_P3             0x4     /* P3: all peripheral devices */
+
+/* Resource groups */
+#define RES_GRP_RES            0x0     /* Reserved */
+#define RES_GRP_PP             0x1     /* Power providers */
+#define RES_GRP_RC             0x2     /* Reset and control */
+#define RES_GRP_PP_RC          0x3
+#define RES_GRP_PR             0x4     /* Power references */
+#define RES_GRP_PP_PR          0x5
+#define RES_GRP_RC_PR          0x6
+#define RES_GRP_ALL            0x7     /* All resource groups */
+
+#define RES_TYPE2_R0           0x0
+
+#define RES_TYPE_ALL           0x7
+
+/* Resource states */
+#define RES_STATE_WRST         0xF
+#define RES_STATE_ACTIVE       0xE
+#define RES_STATE_SLEEP                0x8
+#define RES_STATE_OFF          0x0
+
+/* Power resources */
+
+/* Power providers */
+#define RES_VAUX1               1
+#define RES_VAUX2               2
+#define RES_VAUX3               3
+#define RES_VAUX4               4
+#define RES_VMMC1               5
+#define RES_VMMC2               6
+#define RES_VPLL1               7
+#define RES_VPLL2               8
+#define RES_VSIM                9
+#define RES_VDAC                10
+#define RES_VINTANA1            11
+#define RES_VINTANA2            12
+#define RES_VINTDIG             13
+#define RES_VIO                 14
+#define RES_VDD1                15
+#define RES_VDD2                16
+#define RES_VUSB_1V5            17
+#define RES_VUSB_1V8            18
+#define RES_VUSB_3V1            19
+#define RES_VUSBCP              20
+#define RES_REGEN               21
+/* Reset and control */
+#define RES_NRES_PWRON          22
+#define RES_CLKEN               23
+#define RES_SYSEN               24
+#define RES_HFCLKOUT            25
+#define RES_32KCLKOUT           26
+#define RES_RESET               27
+/* Power Reference */
+#define RES_Main_Ref            28
+
+#define TOTAL_RESOURCES                28
+/*
+ * Power Bus Message Format ... these can be sent individually by Linux,
+ * but are usually part of downloaded scripts that are run when various
+ * power events are triggered.
+ *
+ *  Broadcast Message (16 Bits):
+ *    DEV_GRP[15:13] MT[12]  RES_GRP[11:9]  RES_TYPE2[8:7] RES_TYPE[6:4]
+ *    RES_STATE[3:0]
+ *
+ *  Singular Message (16 Bits):
+ *    DEV_GRP[15:13] MT[12]  RES_ID[11:4]  RES_STATE[3:0]
+ */
+
+#define MSG_BROADCAST(devgrp, grp, type, type2, state) \
+       ( (devgrp) << 13 | 1 << 12 | (grp) << 9 | (type2) << 7 \
+       | (type) << 4 | (state))
+
+#define MSG_SINGULAR(devgrp, id, state) \
+       ((devgrp) << 13 | 0 << 12 | (id) << 4 | (state))
+
+#define MSG_BROADCAST_ALL(devgrp, state) \
+       ((devgrp) << 5 | (state))
+
+#define MSG_BROADCAST_REF MSG_BROADCAST_ALL
+#define MSG_BROADCAST_PROV MSG_BROADCAST_ALL
+#define MSG_BROADCAST__CLK_RST MSG_BROADCAST_ALL
+/*----------------------------------------------------------------------*/
+
+struct twl4030_clock_init_data {
+       bool ck32k_lowpwr_enable;
+};
+
+struct twl4030_bci_platform_data {
+       int *battery_tmp_tbl;
+       unsigned int tblsize;
+};
+
+/* TWL4030_GPIO_MAX (18) GPIOs, with interrupts */
+struct twl4030_gpio_platform_data {
+       int             gpio_base;
+       unsigned        irq_base, irq_end;
+
+       /* package the two LED signals as output-only GPIOs? */
+       bool            use_leds;
+
+       /* gpio-n should control VMMC(n+1) if BIT(n) in mmc_cd is set */
+       u8              mmc_cd;
+
+       /* if BIT(N) is set, or VMMC(n+1) is linked, debounce GPIO-N */
+       u32             debounce;
+
+       /* For gpio-N, bit (1 << N) in "pullups" is set if that pullup
+        * should be enabled.  Else, if that bit is set in "pulldowns",
+        * that pulldown is enabled.  Don't waste power by letting any
+        * digital inputs float...
+        */
+       u32             pullups;
+       u32             pulldowns;
+
+       int             (*setup)(struct device *dev,
+                               unsigned gpio, unsigned ngpio);
+       int             (*teardown)(struct device *dev,
+                               unsigned gpio, unsigned ngpio);
+};
+
+struct twl4030_madc_platform_data {
+       int             irq_line;
+};
+
+/* Boards have uniqe mappings of {row, col} --> keycode.
+ * Column and row are 8 bits each, but range only from 0..7.
+ * a PERSISTENT_KEY is "always on" and never reported.
+ */
+#define PERSISTENT_KEY(r, c)   KEY((r), (c), KEY_RESERVED)
+
+struct twl4030_keypad_data {
+       const struct matrix_keymap_data *keymap_data;
+       unsigned rows;
+       unsigned cols;
+       bool rep;
+};
+
+enum twl4030_usb_mode {
+       T2_USB_MODE_ULPI = 1,
+       T2_USB_MODE_CEA2011_3PIN = 2,
+};
+
+struct twl4030_usb_data {
+       enum twl4030_usb_mode   usb_mode;
+};
+
+struct twl4030_ins {
+       u16 pmb_message;
+       u8 delay;
+};
+
+struct twl4030_script {
+       struct twl4030_ins *script;
+       unsigned size;
+       u8 flags;
+#define TWL4030_WRST_SCRIPT    (1<<0)
+#define TWL4030_WAKEUP12_SCRIPT        (1<<1)
+#define TWL4030_WAKEUP3_SCRIPT (1<<2)
+#define TWL4030_SLEEP_SCRIPT   (1<<3)
+};
+
+struct twl4030_resconfig {
+       u8 resource;
+       u8 devgroup;    /* Processor group that Power resource belongs to */
+       u8 type;        /* Power resource addressed, 6 / broadcast message */
+       u8 type2;       /* Power resource addressed, 3 / broadcast message */
+       u8 remap_off;   /* off state remapping */
+       u8 remap_sleep; /* sleep state remapping */
+};
+
+struct twl4030_power_data {
+       struct twl4030_script **scripts;
+       unsigned num;
+       struct twl4030_resconfig *resource_config;
+#define TWL4030_RESCONFIG_UNDEF        ((u8)-1)
+};
+
+extern void twl4030_power_init(struct twl4030_power_data *triton2_scripts);
+
+struct twl4030_codec_audio_data {
+       unsigned int    audio_mclk;
+       unsigned int ramp_delay_value;
+       unsigned int hs_extmute:1;
+       void (*set_hs_extmute)(int mute);
+};
+
+struct twl4030_codec_vibra_data {
+       unsigned int    audio_mclk;
+       unsigned int    coexist;
+};
+
+struct twl4030_codec_data {
+       unsigned int    audio_mclk;
+       struct twl4030_codec_audio_data         *audio;
+       struct twl4030_codec_vibra_data         *vibra;
+};
+
+struct twl4030_platform_data {
+       unsigned                                irq_base, irq_end;
+       struct twl4030_clock_init_data          *clock;
+       struct twl4030_bci_platform_data        *bci;
+       struct twl4030_gpio_platform_data       *gpio;
+       struct twl4030_madc_platform_data       *madc;
+       struct twl4030_keypad_data              *keypad;
+       struct twl4030_usb_data                 *usb;
+       struct twl4030_power_data               *power;
+       struct twl4030_codec_data               *codec;
+
+       /* Common LDO regulators for TWL4030/TWL6030 */
+       struct regulator_init_data              *vdac;
+       struct regulator_init_data              *vaux1;
+       struct regulator_init_data              *vaux2;
+       struct regulator_init_data              *vaux3;
+       /* TWL4030 LDO regulators */
+       struct regulator_init_data              *vpll1;
+       struct regulator_init_data              *vpll2;
+       struct regulator_init_data              *vmmc1;
+       struct regulator_init_data              *vmmc2;
+       struct regulator_init_data              *vsim;
+       struct regulator_init_data              *vaux4;
+       struct regulator_init_data              *vio;
+       struct regulator_init_data              *vdd1;
+       struct regulator_init_data              *vdd2;
+       struct regulator_init_data              *vintana1;
+       struct regulator_init_data              *vintana2;
+       struct regulator_init_data              *vintdig;
+       /* TWL6030 LDO regulators */
+       struct regulator_init_data              *vmmc;
+       struct regulator_init_data              *vpp;
+       struct regulator_init_data              *vusim;
+       struct regulator_init_data              *vana;
+       struct regulator_init_data              *vcxio;
+       struct regulator_init_data              *vusb;
+};
+
+/*----------------------------------------------------------------------*/
+
+int twl4030_sih_setup(int module);
+
+/* Offsets to Power Registers */
+#define TWL4030_VDAC_DEV_GRP           0x3B
+#define TWL4030_VDAC_DEDICATED         0x3E
+#define TWL4030_VAUX1_DEV_GRP          0x17
+#define TWL4030_VAUX1_DEDICATED                0x1A
+#define TWL4030_VAUX2_DEV_GRP          0x1B
+#define TWL4030_VAUX2_DEDICATED                0x1E
+#define TWL4030_VAUX3_DEV_GRP          0x1F
+#define TWL4030_VAUX3_DEDICATED                0x22
+
+#if defined(CONFIG_TWL4030_BCI_BATTERY) || \
+       defined(CONFIG_TWL4030_BCI_BATTERY_MODULE)
+       extern int twl4030charger_usb_en(int enable);
+#else
+       static inline int twl4030charger_usb_en(int enable) { return 0; }
+#endif
+
+/*----------------------------------------------------------------------*/
+
+/* Linux-specific regulator identifiers ... for now, we only support
+ * the LDOs, and leave the three buck converters alone.  VDD1 and VDD2
+ * need to tie into hardware based voltage scaling (cpufreq etc), while
+ * VIO is generally fixed.
+ */
+
+/* TWL4030 SMPS/LDO's */
+/* EXTERNAL dc-to-dc buck converters */
+#define TWL4030_REG_VDD1       0
+#define TWL4030_REG_VDD2       1
+#define TWL4030_REG_VIO                2
+
+/* EXTERNAL LDOs */
+#define TWL4030_REG_VDAC       3
+#define TWL4030_REG_VPLL1      4
+#define TWL4030_REG_VPLL2      5       /* not on all chips */
+#define TWL4030_REG_VMMC1      6
+#define TWL4030_REG_VMMC2      7       /* not on all chips */
+#define TWL4030_REG_VSIM       8       /* not on all chips */
+#define TWL4030_REG_VAUX1      9       /* not on all chips */
+#define TWL4030_REG_VAUX2_4030 10      /* (twl4030-specific) */
+#define TWL4030_REG_VAUX2      11      /* (twl5030 and newer) */
+#define TWL4030_REG_VAUX3      12      /* not on all chips */
+#define TWL4030_REG_VAUX4      13      /* not on all chips */
+
+/* INTERNAL LDOs */
+#define TWL4030_REG_VINTANA1   14
+#define TWL4030_REG_VINTANA2   15
+#define TWL4030_REG_VINTDIG    16
+#define TWL4030_REG_VUSB1V5    17
+#define TWL4030_REG_VUSB1V8    18
+#define TWL4030_REG_VUSB3V1    19
+
+/* TWL6030 SMPS/LDO's */
+/* EXTERNAL dc-to-dc buck convertor contollable via SR */
+#define TWL6030_REG_VDD1       30
+#define TWL6030_REG_VDD2       31
+#define TWL6030_REG_VDD3       32
+
+/* Non SR compliant dc-to-dc buck convertors */
+#define        TWL6030_REG_VMEM        33
+#define TWL6030_REG_V2V1       34
+#define        TWL6030_REG_V1V29       35
+#define TWL6030_REG_V1V8       36
+
+/* EXTERNAL LDOs */
+#define TWL6030_REG_VAUX1_6030 37
+#define TWL6030_REG_VAUX2_6030 38
+#define TWL6030_REG_VAUX3_6030 39
+#define TWL6030_REG_VMMC       40
+#define TWL6030_REG_VPP                41
+#define TWL6030_REG_VUSIM      42
+#define TWL6030_REG_VANA       43
+#define TWL6030_REG_VCXIO      44
+#define TWL6030_REG_VDAC       45
+#define TWL6030_REG_VUSB       46
+
+/* INTERNAL LDOs */
+#define TWL6030_REG_VRTC       47
+
+#endif /* End of __TWL4030_H */
diff --git a/include/linux/i2c/twl4030.h b/include/linux/i2c/twl4030.h
deleted file mode 100644 (file)
index 5306a75..0000000
+++ /dev/null
@@ -1,502 +0,0 @@
-/*
- * twl4030.h - header for TWL4030 PM and audio CODEC device
- *
- * Copyright (C) 2005-2006 Texas Instruments, Inc.
- *
- * Based on tlv320aic23.c:
- * Copyright (c) by Kai Svahn <kai.svahn@nokia.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
- *
- */
-
-#ifndef __TWL4030_H_
-#define __TWL4030_H_
-
-#include <linux/types.h>
-#include <linux/input/matrix_keypad.h>
-
-/*
- * Using the twl4030 core we address registers using a pair
- *     { module id, relative register offset }
- * which that core then maps to the relevant
- *     { i2c slave, absolute register address }
- *
- * The module IDs are meaningful only to the twl4030 core code,
- * which uses them as array indices to look up the first register
- * address each module uses within a given i2c slave.
- */
-
-/* Slave 0 (i2c address 0x48) */
-#define TWL4030_MODULE_USB             0x00
-
-/* Slave 1 (i2c address 0x49) */
-#define TWL4030_MODULE_AUDIO_VOICE     0x01
-#define TWL4030_MODULE_GPIO            0x02
-#define TWL4030_MODULE_INTBR           0x03
-#define TWL4030_MODULE_PIH             0x04
-#define TWL4030_MODULE_TEST            0x05
-
-/* Slave 2 (i2c address 0x4a) */
-#define TWL4030_MODULE_KEYPAD          0x06
-#define TWL4030_MODULE_MADC            0x07
-#define TWL4030_MODULE_INTERRUPTS      0x08
-#define TWL4030_MODULE_LED             0x09
-#define TWL4030_MODULE_MAIN_CHARGE     0x0A
-#define TWL4030_MODULE_PRECHARGE       0x0B
-#define TWL4030_MODULE_PWM0            0x0C
-#define TWL4030_MODULE_PWM1            0x0D
-#define TWL4030_MODULE_PWMA            0x0E
-#define TWL4030_MODULE_PWMB            0x0F
-
-/* Slave 3 (i2c address 0x4b) */
-#define TWL4030_MODULE_BACKUP          0x10
-#define TWL4030_MODULE_INT             0x11
-#define TWL4030_MODULE_PM_MASTER       0x12
-#define TWL4030_MODULE_PM_RECEIVER     0x13
-#define TWL4030_MODULE_RTC             0x14
-#define TWL4030_MODULE_SECURED_REG     0x15
-
-/*
- * Read and write single 8-bit registers
- */
-int twl4030_i2c_write_u8(u8 mod_no, u8 val, u8 reg);
-int twl4030_i2c_read_u8(u8 mod_no, u8 *val, u8 reg);
-
-/*
- * Read and write several 8-bit registers at once.
- *
- * IMPORTANT:  For twl4030_i2c_write(), allocate num_bytes + 1
- * for the value, and populate your data starting at offset 1.
- */
-int twl4030_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes);
-int twl4030_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes);
-
-/*----------------------------------------------------------------------*/
-
-/*
- * NOTE:  at up to 1024 registers, this is a big chip.
- *
- * Avoid putting register declarations in this file, instead of into
- * a driver-private file, unless some of the registers in a block
- * need to be shared with other drivers.  One example is blocks that
- * have Secondary IRQ Handler (SIH) registers.
- */
-
-#define TWL4030_SIH_CTRL_EXCLEN_MASK   BIT(0)
-#define TWL4030_SIH_CTRL_PENDDIS_MASK  BIT(1)
-#define TWL4030_SIH_CTRL_COR_MASK      BIT(2)
-
-/*----------------------------------------------------------------------*/
-
-/*
- * GPIO Block Register offsets (use TWL4030_MODULE_GPIO)
- */
-
-#define REG_GPIODATAIN1                        0x0
-#define REG_GPIODATAIN2                        0x1
-#define REG_GPIODATAIN3                        0x2
-#define REG_GPIODATADIR1               0x3
-#define REG_GPIODATADIR2               0x4
-#define REG_GPIODATADIR3               0x5
-#define REG_GPIODATAOUT1               0x6
-#define REG_GPIODATAOUT2               0x7
-#define REG_GPIODATAOUT3               0x8
-#define REG_CLEARGPIODATAOUT1          0x9
-#define REG_CLEARGPIODATAOUT2          0xA
-#define REG_CLEARGPIODATAOUT3          0xB
-#define REG_SETGPIODATAOUT1            0xC
-#define REG_SETGPIODATAOUT2            0xD
-#define REG_SETGPIODATAOUT3            0xE
-#define REG_GPIO_DEBEN1                        0xF
-#define REG_GPIO_DEBEN2                        0x10
-#define REG_GPIO_DEBEN3                        0x11
-#define REG_GPIO_CTRL                  0x12
-#define REG_GPIOPUPDCTR1               0x13
-#define REG_GPIOPUPDCTR2               0x14
-#define REG_GPIOPUPDCTR3               0x15
-#define REG_GPIOPUPDCTR4               0x16
-#define REG_GPIOPUPDCTR5               0x17
-#define REG_GPIO_ISR1A                 0x19
-#define REG_GPIO_ISR2A                 0x1A
-#define REG_GPIO_ISR3A                 0x1B
-#define REG_GPIO_IMR1A                 0x1C
-#define REG_GPIO_IMR2A                 0x1D
-#define REG_GPIO_IMR3A                 0x1E
-#define REG_GPIO_ISR1B                 0x1F
-#define REG_GPIO_ISR2B                 0x20
-#define REG_GPIO_ISR3B                 0x21
-#define REG_GPIO_IMR1B                 0x22
-#define REG_GPIO_IMR2B                 0x23
-#define REG_GPIO_IMR3B                 0x24
-#define REG_GPIO_EDR1                  0x28
-#define REG_GPIO_EDR2                  0x29
-#define REG_GPIO_EDR3                  0x2A
-#define REG_GPIO_EDR4                  0x2B
-#define REG_GPIO_EDR5                  0x2C
-#define REG_GPIO_SIH_CTRL              0x2D
-
-/* Up to 18 signals are available as GPIOs, when their
- * pins are not assigned to another use (such as ULPI/USB).
- */
-#define TWL4030_GPIO_MAX               18
-
-/*----------------------------------------------------------------------*/
-
-/*
- * Keypad register offsets (use TWL4030_MODULE_KEYPAD)
- * ... SIH/interrupt only
- */
-
-#define TWL4030_KEYPAD_KEYP_ISR1       0x11
-#define TWL4030_KEYPAD_KEYP_IMR1       0x12
-#define TWL4030_KEYPAD_KEYP_ISR2       0x13
-#define TWL4030_KEYPAD_KEYP_IMR2       0x14
-#define TWL4030_KEYPAD_KEYP_SIR                0x15    /* test register */
-#define TWL4030_KEYPAD_KEYP_EDR                0x16
-#define TWL4030_KEYPAD_KEYP_SIH_CTRL   0x17
-
-/*----------------------------------------------------------------------*/
-
-/*
- * Multichannel ADC register offsets (use TWL4030_MODULE_MADC)
- * ... SIH/interrupt only
- */
-
-#define TWL4030_MADC_ISR1              0x61
-#define TWL4030_MADC_IMR1              0x62
-#define TWL4030_MADC_ISR2              0x63
-#define TWL4030_MADC_IMR2              0x64
-#define TWL4030_MADC_SIR               0x65    /* test register */
-#define TWL4030_MADC_EDR               0x66
-#define TWL4030_MADC_SIH_CTRL          0x67
-
-/*----------------------------------------------------------------------*/
-
-/*
- * Battery charger register offsets (use TWL4030_MODULE_INTERRUPTS)
- */
-
-#define TWL4030_INTERRUPTS_BCIISR1A    0x0
-#define TWL4030_INTERRUPTS_BCIISR2A    0x1
-#define TWL4030_INTERRUPTS_BCIIMR1A    0x2
-#define TWL4030_INTERRUPTS_BCIIMR2A    0x3
-#define TWL4030_INTERRUPTS_BCIISR1B    0x4
-#define TWL4030_INTERRUPTS_BCIISR2B    0x5
-#define TWL4030_INTERRUPTS_BCIIMR1B    0x6
-#define TWL4030_INTERRUPTS_BCIIMR2B    0x7
-#define TWL4030_INTERRUPTS_BCISIR1     0x8     /* test register */
-#define TWL4030_INTERRUPTS_BCISIR2     0x9     /* test register */
-#define TWL4030_INTERRUPTS_BCIEDR1     0xa
-#define TWL4030_INTERRUPTS_BCIEDR2     0xb
-#define TWL4030_INTERRUPTS_BCIEDR3     0xc
-#define TWL4030_INTERRUPTS_BCISIHCTRL  0xd
-
-/*----------------------------------------------------------------------*/
-
-/*
- * Power Interrupt block register offsets (use TWL4030_MODULE_INT)
- */
-
-#define TWL4030_INT_PWR_ISR1           0x0
-#define TWL4030_INT_PWR_IMR1           0x1
-#define TWL4030_INT_PWR_ISR2           0x2
-#define TWL4030_INT_PWR_IMR2           0x3
-#define TWL4030_INT_PWR_SIR            0x4     /* test register */
-#define TWL4030_INT_PWR_EDR1           0x5
-#define TWL4030_INT_PWR_EDR2           0x6
-#define TWL4030_INT_PWR_SIH_CTRL       0x7
-
-/*----------------------------------------------------------------------*/
-
-/* Power bus message definitions */
-
-/* The TWL4030/5030 splits its power-management resources (the various
- * regulators, clock and reset lines) into 3 processor groups - P1, P2 and
- * P3. These groups can then be configured to transition between sleep, wait-on
- * and active states by sending messages to the power bus.  See Section 5.4.2
- * Power Resources of TWL4030 TRM
- */
-
-/* Processor groups */
-#define DEV_GRP_NULL           0x0
-#define DEV_GRP_P1             0x1     /* P1: all OMAP devices */
-#define DEV_GRP_P2             0x2     /* P2: all Modem devices */
-#define DEV_GRP_P3             0x4     /* P3: all peripheral devices */
-
-/* Resource groups */
-#define RES_GRP_RES            0x0     /* Reserved */
-#define RES_GRP_PP             0x1     /* Power providers */
-#define RES_GRP_RC             0x2     /* Reset and control */
-#define RES_GRP_PP_RC          0x3
-#define RES_GRP_PR             0x4     /* Power references */
-#define RES_GRP_PP_PR          0x5
-#define RES_GRP_RC_PR          0x6
-#define RES_GRP_ALL            0x7     /* All resource groups */
-
-#define RES_TYPE2_R0           0x0
-
-#define RES_TYPE_ALL           0x7
-
-#define RES_STATE_WRST         0xF
-#define RES_STATE_ACTIVE       0xE
-#define RES_STATE_SLEEP                0x8
-#define RES_STATE_OFF          0x0
-
-/* Power resources */
-
-/* Power providers */
-#define RES_VAUX1               1
-#define RES_VAUX2               2
-#define RES_VAUX3               3
-#define RES_VAUX4               4
-#define RES_VMMC1               5
-#define RES_VMMC2               6
-#define RES_VPLL1               7
-#define RES_VPLL2               8
-#define RES_VSIM                9
-#define RES_VDAC                10
-#define RES_VINTANA1            11
-#define RES_VINTANA2            12
-#define RES_VINTDIG             13
-#define RES_VIO                 14
-#define RES_VDD1                15
-#define RES_VDD2                16
-#define RES_VUSB_1V5            17
-#define RES_VUSB_1V8            18
-#define RES_VUSB_3V1            19
-#define RES_VUSBCP              20
-#define RES_REGEN               21
-/* Reset and control */
-#define RES_NRES_PWRON          22
-#define RES_CLKEN               23
-#define RES_SYSEN               24
-#define RES_HFCLKOUT            25
-#define RES_32KCLKOUT           26
-#define RES_RESET               27
-/* Power Reference */
-#define RES_Main_Ref            28
-
-#define TOTAL_RESOURCES                28
-/*
- * Power Bus Message Format ... these can be sent individually by Linux,
- * but are usually part of downloaded scripts that are run when various
- * power events are triggered.
- *
- *  Broadcast Message (16 Bits):
- *    DEV_GRP[15:13] MT[12]  RES_GRP[11:9]  RES_TYPE2[8:7] RES_TYPE[6:4]
- *    RES_STATE[3:0]
- *
- *  Singular Message (16 Bits):
- *    DEV_GRP[15:13] MT[12]  RES_ID[11:4]  RES_STATE[3:0]
- */
-
-#define MSG_BROADCAST(devgrp, grp, type, type2, state) \
-       ( (devgrp) << 13 | 1 << 12 | (grp) << 9 | (type2) << 7 \
-       | (type) << 4 | (state))
-
-#define MSG_SINGULAR(devgrp, id, state) \
-       ((devgrp) << 13 | 0 << 12 | (id) << 4 | (state))
-
-/*----------------------------------------------------------------------*/
-
-struct twl4030_bci_platform_data {
-       int *battery_tmp_tbl;
-       unsigned int tblsize;
-};
-
-/* TWL4030_GPIO_MAX (18) GPIOs, with interrupts */
-struct twl4030_gpio_platform_data {
-       int             gpio_base;
-       unsigned        irq_base, irq_end;
-
-       /* package the two LED signals as output-only GPIOs? */
-       bool            use_leds;
-
-       /* gpio-n should control VMMC(n+1) if BIT(n) in mmc_cd is set */
-       u8              mmc_cd;
-
-       /* if BIT(N) is set, or VMMC(n+1) is linked, debounce GPIO-N */
-       u32             debounce;
-
-       /* For gpio-N, bit (1 << N) in "pullups" is set if that pullup
-        * should be enabled.  Else, if that bit is set in "pulldowns",
-        * that pulldown is enabled.  Don't waste power by letting any
-        * digital inputs float...
-        */
-       u32             pullups;
-       u32             pulldowns;
-
-       int             (*setup)(struct device *dev,
-                               unsigned gpio, unsigned ngpio);
-       int             (*teardown)(struct device *dev,
-                               unsigned gpio, unsigned ngpio);
-};
-
-struct twl4030_madc_platform_data {
-       int             irq_line;
-};
-
-/* Boards have uniqe mappings of {row, col} --> keycode.
- * Column and row are 8 bits each, but range only from 0..7.
- * a PERSISTENT_KEY is "always on" and never reported.
- */
-#define PERSISTENT_KEY(r, c)   KEY((r), (c), KEY_RESERVED)
-
-struct twl4030_keypad_data {
-       const struct matrix_keymap_data *keymap_data;
-       unsigned rows;
-       unsigned cols;
-       bool rep;
-};
-
-enum twl4030_usb_mode {
-       T2_USB_MODE_ULPI = 1,
-       T2_USB_MODE_CEA2011_3PIN = 2,
-};
-
-struct twl4030_usb_data {
-       enum twl4030_usb_mode   usb_mode;
-};
-
-struct twl4030_ins {
-       u16 pmb_message;
-       u8 delay;
-};
-
-struct twl4030_script {
-       struct twl4030_ins *script;
-       unsigned size;
-       u8 flags;
-#define TWL4030_WRST_SCRIPT    (1<<0)
-#define TWL4030_WAKEUP12_SCRIPT        (1<<1)
-#define TWL4030_WAKEUP3_SCRIPT (1<<2)
-#define TWL4030_SLEEP_SCRIPT   (1<<3)
-};
-
-struct twl4030_resconfig {
-       u8 resource;
-       u8 devgroup;    /* Processor group that Power resource belongs to */
-       u8 type;        /* Power resource addressed, 6 / broadcast message */
-       u8 type2;       /* Power resource addressed, 3 / broadcast message */
-};
-
-struct twl4030_power_data {
-       struct twl4030_script **scripts;
-       unsigned num;
-       struct twl4030_resconfig *resource_config;
-};
-
-extern void twl4030_power_init(struct twl4030_power_data *triton2_scripts);
-
-struct twl4030_codec_audio_data {
-       unsigned int    audio_mclk;
-       unsigned int ramp_delay_value;
-       unsigned int hs_extmute:1;
-       void (*set_hs_extmute)(int mute);
-};
-
-struct twl4030_codec_vibra_data {
-       unsigned int    audio_mclk;
-       unsigned int    coexist;
-};
-
-struct twl4030_codec_data {
-       unsigned int    audio_mclk;
-       struct twl4030_codec_audio_data         *audio;
-       struct twl4030_codec_vibra_data         *vibra;
-};
-
-struct twl4030_platform_data {
-       unsigned                                irq_base, irq_end;
-       struct twl4030_bci_platform_data        *bci;
-       struct twl4030_gpio_platform_data       *gpio;
-       struct twl4030_madc_platform_data       *madc;
-       struct twl4030_keypad_data              *keypad;
-       struct twl4030_usb_data                 *usb;
-       struct twl4030_power_data               *power;
-       struct twl4030_codec_data               *codec;
-
-       /* LDO regulators */
-       struct regulator_init_data              *vdac;
-       struct regulator_init_data              *vpll1;
-       struct regulator_init_data              *vpll2;
-       struct regulator_init_data              *vmmc1;
-       struct regulator_init_data              *vmmc2;
-       struct regulator_init_data              *vsim;
-       struct regulator_init_data              *vaux1;
-       struct regulator_init_data              *vaux2;
-       struct regulator_init_data              *vaux3;
-       struct regulator_init_data              *vaux4;
-
-       /* REVISIT more to come ... _nothing_ should be hard-wired */
-};
-
-/*----------------------------------------------------------------------*/
-
-int twl4030_sih_setup(int module);
-
-/* Offsets to Power Registers */
-#define TWL4030_VDAC_DEV_GRP           0x3B
-#define TWL4030_VDAC_DEDICATED         0x3E
-#define TWL4030_VAUX1_DEV_GRP          0x17
-#define TWL4030_VAUX1_DEDICATED                0x1A
-#define TWL4030_VAUX2_DEV_GRP          0x1B
-#define TWL4030_VAUX2_DEDICATED                0x1E
-#define TWL4030_VAUX3_DEV_GRP          0x1F
-#define TWL4030_VAUX3_DEDICATED                0x22
-
-#if defined(CONFIG_TWL4030_BCI_BATTERY) || \
-       defined(CONFIG_TWL4030_BCI_BATTERY_MODULE)
-       extern int twl4030charger_usb_en(int enable);
-#else
-       static inline int twl4030charger_usb_en(int enable) { return 0; }
-#endif
-
-/*----------------------------------------------------------------------*/
-
-/* Linux-specific regulator identifiers ... for now, we only support
- * the LDOs, and leave the three buck converters alone.  VDD1 and VDD2
- * need to tie into hardware based voltage scaling (cpufreq etc), while
- * VIO is generally fixed.
- */
-
-/* EXTERNAL dc-to-dc buck converters */
-#define TWL4030_REG_VDD1       0
-#define TWL4030_REG_VDD2       1
-#define TWL4030_REG_VIO                2
-
-/* EXTERNAL LDOs */
-#define TWL4030_REG_VDAC       3
-#define TWL4030_REG_VPLL1      4
-#define TWL4030_REG_VPLL2      5       /* not on all chips */
-#define TWL4030_REG_VMMC1      6
-#define TWL4030_REG_VMMC2      7       /* not on all chips */
-#define TWL4030_REG_VSIM       8       /* not on all chips */
-#define TWL4030_REG_VAUX1      9       /* not on all chips */
-#define TWL4030_REG_VAUX2_4030 10      /* (twl4030-specific) */
-#define TWL4030_REG_VAUX2      11      /* (twl5030 and newer) */
-#define TWL4030_REG_VAUX3      12      /* not on all chips */
-#define TWL4030_REG_VAUX4      13      /* not on all chips */
-
-/* INTERNAL LDOs */
-#define TWL4030_REG_VINTANA1   14
-#define TWL4030_REG_VINTANA2   15
-#define TWL4030_REG_VINTDIG    16
-#define TWL4030_REG_VUSB1V5    17
-#define TWL4030_REG_VUSB1V8    18
-#define TWL4030_REG_VUSB3V1    19
-
-#endif /* End of __TWL4030_H */
diff --git a/include/linux/mfd/88pm8607.h b/include/linux/mfd/88pm8607.h
new file mode 100644 (file)
index 0000000..f41b428
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * Marvell 88PM8607 Interface
+ *
+ * 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.
+ */
+
+#ifndef __LINUX_MFD_88PM8607_H
+#define __LINUX_MFD_88PM8607_H
+
+enum {
+       PM8607_ID_BUCK1 = 0,
+       PM8607_ID_BUCK2,
+       PM8607_ID_BUCK3,
+
+       PM8607_ID_LDO1,
+       PM8607_ID_LDO2,
+       PM8607_ID_LDO3,
+       PM8607_ID_LDO4,
+       PM8607_ID_LDO5,
+       PM8607_ID_LDO6,
+       PM8607_ID_LDO7,
+       PM8607_ID_LDO8,
+       PM8607_ID_LDO9,
+       PM8607_ID_LDO10,
+       PM8607_ID_LDO12,
+       PM8607_ID_LDO14,
+
+       PM8607_ID_RG_MAX,
+};
+
+#define CHIP_ID                                (0x40)
+#define CHIP_ID_MASK                   (0xF8)
+
+/* Interrupt Registers */
+#define PM8607_STATUS_1                        (0x01)
+#define PM8607_STATUS_2                        (0x02)
+#define PM8607_INT_STATUS1             (0x03)
+#define PM8607_INT_STATUS2             (0x04)
+#define PM8607_INT_STATUS3             (0x05)
+#define PM8607_INT_MASK_1              (0x06)
+#define PM8607_INT_MASK_2              (0x07)
+#define PM8607_INT_MASK_3              (0x08)
+
+/* Regulator Control Registers */
+#define PM8607_LDO1                    (0x10)
+#define PM8607_LDO2                    (0x11)
+#define PM8607_LDO3                    (0x12)
+#define PM8607_LDO4                    (0x13)
+#define PM8607_LDO5                    (0x14)
+#define PM8607_LDO6                    (0x15)
+#define PM8607_LDO7                    (0x16)
+#define PM8607_LDO8                    (0x17)
+#define PM8607_LDO9                    (0x18)
+#define PM8607_LDO10                   (0x19)
+#define PM8607_LDO12                   (0x1A)
+#define PM8607_LDO14                   (0x1B)
+#define PM8607_SLEEP_MODE1             (0x1C)
+#define PM8607_SLEEP_MODE2             (0x1D)
+#define PM8607_SLEEP_MODE3             (0x1E)
+#define PM8607_SLEEP_MODE4             (0x1F)
+#define PM8607_GO                      (0x20)
+#define PM8607_SLEEP_BUCK1             (0x21)
+#define PM8607_SLEEP_BUCK2             (0x22)
+#define PM8607_SLEEP_BUCK3             (0x23)
+#define PM8607_BUCK1                   (0x24)
+#define PM8607_BUCK2                   (0x25)
+#define PM8607_BUCK3                   (0x26)
+#define PM8607_BUCK_CONTROLS           (0x27)
+#define PM8607_SUPPLIES_EN11           (0x2B)
+#define PM8607_SUPPLIES_EN12           (0x2C)
+#define PM8607_GROUP1                  (0x2D)
+#define PM8607_GROUP2                  (0x2E)
+#define PM8607_GROUP3                  (0x2F)
+#define PM8607_GROUP4                  (0x30)
+#define PM8607_GROUP5                  (0x31)
+#define PM8607_GROUP6                  (0x32)
+#define PM8607_SUPPLIES_EN21           (0x33)
+#define PM8607_SUPPLIES_EN22           (0x34)
+
+/* RTC Control Registers */
+#define PM8607_RTC1                    (0xA0)
+#define PM8607_RTC_COUNTER1            (0xA1)
+#define PM8607_RTC_COUNTER2            (0xA2)
+#define PM8607_RTC_COUNTER3            (0xA3)
+#define PM8607_RTC_COUNTER4            (0xA4)
+#define PM8607_RTC_EXPIRE1             (0xA5)
+#define PM8607_RTC_EXPIRE2             (0xA6)
+#define PM8607_RTC_EXPIRE3             (0xA7)
+#define PM8607_RTC_EXPIRE4             (0xA8)
+#define PM8607_RTC_TRIM1               (0xA9)
+#define PM8607_RTC_TRIM2               (0xAA)
+#define PM8607_RTC_TRIM3               (0xAB)
+#define PM8607_RTC_TRIM4               (0xAC)
+#define PM8607_RTC_MISC1               (0xAD)
+#define PM8607_RTC_MISC2               (0xAE)
+#define PM8607_RTC_MISC3               (0xAF)
+
+/* Misc Registers */
+#define PM8607_CHIP_ID                 (0x00)
+#define PM8607_LDO1                    (0x10)
+#define PM8607_DVC3                    (0x26)
+#define PM8607_MISC1                   (0x40)
+
+/* bit definitions for PM8607 events */
+#define PM8607_EVENT_ONKEY             (1 << 0)
+#define PM8607_EVENT_EXTON             (1 << 1)
+#define PM8607_EVENT_CHG               (1 << 2)
+#define PM8607_EVENT_BAT               (1 << 3)
+#define PM8607_EVENT_RTC               (1 << 4)
+#define PM8607_EVENT_CC                        (1 << 5)
+#define PM8607_EVENT_VBAT              (1 << 8)
+#define PM8607_EVENT_VCHG              (1 << 9)
+#define PM8607_EVENT_VSYS              (1 << 10)
+#define PM8607_EVENT_TINT              (1 << 11)
+#define PM8607_EVENT_GPADC0            (1 << 12)
+#define PM8607_EVENT_GPADC1            (1 << 13)
+#define PM8607_EVENT_GPADC2            (1 << 14)
+#define PM8607_EVENT_GPADC3            (1 << 15)
+#define PM8607_EVENT_AUDIO_SHORT       (1 << 16)
+#define PM8607_EVENT_PEN               (1 << 17)
+#define PM8607_EVENT_HEADSET           (1 << 18)
+#define PM8607_EVENT_HOOK              (1 << 19)
+#define PM8607_EVENT_MICIN             (1 << 20)
+#define PM8607_EVENT_CHG_TIMEOUT       (1 << 21)
+#define PM8607_EVENT_CHG_DONE          (1 << 22)
+#define PM8607_EVENT_CHG_FAULT         (1 << 23)
+
+/* bit definitions of Status Query Interface */
+#define PM8607_STATUS_CC               (1 << 3)
+#define PM8607_STATUS_PEN              (1 << 4)
+#define PM8607_STATUS_HEADSET          (1 << 5)
+#define PM8607_STATUS_HOOK             (1 << 6)
+#define PM8607_STATUS_MICIN            (1 << 7)
+#define PM8607_STATUS_ONKEY            (1 << 8)
+#define PM8607_STATUS_EXTON            (1 << 9)
+#define PM8607_STATUS_CHG              (1 << 10)
+#define PM8607_STATUS_BAT              (1 << 11)
+#define PM8607_STATUS_VBUS             (1 << 12)
+#define PM8607_STATUS_OV               (1 << 13)
+
+/* bit definitions of BUCK3 */
+#define PM8607_BUCK3_DOUBLE            (1 << 6)
+
+/* bit definitions of Misc1 */
+#define PM8607_MISC1_PI2C              (1 << 0)
+
+/* Interrupt Number in 88PM8607 */
+enum {
+       PM8607_IRQ_ONKEY = 0,
+       PM8607_IRQ_EXTON,
+       PM8607_IRQ_CHG,
+       PM8607_IRQ_BAT,
+       PM8607_IRQ_RTC,
+       PM8607_IRQ_VBAT = 8,
+       PM8607_IRQ_VCHG,
+       PM8607_IRQ_VSYS,
+       PM8607_IRQ_TINT,
+       PM8607_IRQ_GPADC0,
+       PM8607_IRQ_GPADC1,
+       PM8607_IRQ_GPADC2,
+       PM8607_IRQ_GPADC3,
+       PM8607_IRQ_AUDIO_SHORT = 16,
+       PM8607_IRQ_PEN,
+       PM8607_IRQ_HEADSET,
+       PM8607_IRQ_HOOK,
+       PM8607_IRQ_MICIN,
+       PM8607_IRQ_CHG_FAIL,
+       PM8607_IRQ_CHG_DONE,
+       PM8607_IRQ_CHG_FAULT,
+};
+
+enum {
+       PM8607_CHIP_A0 = 0x40,
+       PM8607_CHIP_A1 = 0x41,
+       PM8607_CHIP_B0 = 0x48,
+};
+
+
+struct pm8607_chip {
+       struct device           *dev;
+       struct mutex            io_lock;
+       struct i2c_client       *client;
+
+       int (*read)(struct pm8607_chip *chip, int reg, int bytes, void *dest);
+       int (*write)(struct pm8607_chip *chip, int reg, int bytes, void *src);
+
+       int                     buck3_double;   /* DVC ramp slope double */
+       unsigned char           chip_id;
+
+};
+
+#define PM8607_MAX_REGULATOR   15      /* 3 Bucks, 12 LDOs */
+
+enum {
+       GI2C_PORT = 0,
+       PI2C_PORT,
+};
+
+struct pm8607_platform_data {
+       int     i2c_port;       /* Controlled by GI2C or PI2C */
+       struct regulator_init_data *regulator[PM8607_MAX_REGULATOR];
+};
+
+extern int pm8607_reg_read(struct pm8607_chip *, int);
+extern int pm8607_reg_write(struct pm8607_chip *, int, unsigned char);
+extern int pm8607_bulk_read(struct pm8607_chip *, int, int,
+                           unsigned char *);
+extern int pm8607_bulk_write(struct pm8607_chip *, int, int,
+                            unsigned char *);
+extern int pm8607_set_bits(struct pm8607_chip *, int, unsigned char,
+                          unsigned char);
+#endif /* __LINUX_MFD_88PM8607_H */
diff --git a/include/linux/mfd/ab4500.h b/include/linux/mfd/ab4500.h
new file mode 100644 (file)
index 0000000..a42a703
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2009 ST-Ericsson
+ *
+ * Author: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.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.
+ *
+ * AB4500 device core funtions, for client access
+ */
+#ifndef MFD_AB4500_H
+#define MFD_AB4500_H
+
+#include <linux/device.h>
+
+/*
+ * AB4500 bank addresses
+ */
+#define AB4500_SYS_CTRL1_BLOCK 0x1
+#define AB4500_SYS_CTRL2_BLOCK 0x2
+#define AB4500_REGU_CTRL1      0x3
+#define AB4500_REGU_CTRL2      0x4
+#define AB4500_USB             0x5
+#define AB4500_TVOUT           0x6
+#define AB4500_DBI             0x7
+#define AB4500_ECI_AV_ACC      0x8
+#define AB4500_RESERVED                0x9
+#define AB4500_GPADC           0xA
+#define AB4500_CHARGER         0xB
+#define AB4500_GAS_GAUGE       0xC
+#define AB4500_AUDIO           0xD
+#define AB4500_INTERRUPT       0xE
+#define AB4500_RTC             0xF
+#define AB4500_MISC            0x10
+#define AB4500_DEBUG           0x12
+#define AB4500_PROD_TEST       0x13
+#define AB4500_OTP_EMUL                0x15
+
+/*
+ * System control 1 register offsets.
+ * Bank = 0x01
+ */
+#define AB4500_TURNON_STAT_REG         0x0100
+#define AB4500_RESET_STAT_REG          0x0101
+#define AB4500_PONKEY1_PRESS_STAT_REG  0x0102
+
+#define AB4500_FSM_STAT1_REG           0x0140
+#define AB4500_FSM_STAT2_REG           0x0141
+#define AB4500_SYSCLK_REQ_STAT_REG     0x0142
+#define AB4500_USB_STAT1_REG           0x0143
+#define AB4500_USB_STAT2_REG           0x0144
+#define AB4500_STATUS_SPARE1_REG       0x0145
+#define AB4500_STATUS_SPARE2_REG       0x0146
+
+#define AB4500_CTRL1_REG               0x0180
+#define AB4500_CTRL2_REG               0x0181
+
+/*
+ * System control 2 register offsets.
+ * bank = 0x02
+ */
+#define AB4500_CTRL3_REG               0x0200
+#define AB4500_MAIN_WDOG_CTRL_REG      0x0201
+#define AB4500_MAIN_WDOG_TIMER_REG     0x0202
+#define AB4500_LOW_BAT_REG             0x0203
+#define AB4500_BATT_OK_REG             0x0204
+#define AB4500_SYSCLK_TIMER_REG                0x0205
+#define AB4500_SMPSCLK_CTRL_REG                0x0206
+#define AB4500_SMPSCLK_SEL1_REG                0x0207
+#define AB4500_SMPSCLK_SEL2_REG                0x0208
+#define AB4500_SMPSCLK_SEL3_REG                0x0209
+#define AB4500_SYSULPCLK_CONF_REG      0x020A
+#define AB4500_SYSULPCLK_CTRL1_REG     0x020B
+#define AB4500_SYSCLK_CTRL_REG         0x020C
+#define AB4500_SYSCLK_REQ1_VALID_REG   0x020D
+#define AB4500_SYSCLK_REQ_VALID_REG    0x020E
+#define AB4500_SYSCTRL_SPARE_REG       0x020F
+#define AB4500_PAD_CONF_REG            0x0210
+
+/*
+ * Regu control1 register offsets
+ * Bank = 0x03
+ */
+#define AB4500_REGU_SERIAL_CTRL1_REG   0x0300
+#define AB4500_REGU_SERIAL_CTRL2_REG   0x0301
+#define AB4500_REGU_SERIAL_CTRL3_REG   0x0302
+#define AB4500_REGU_REQ_CTRL1_REG      0x0303
+#define AB4500_REGU_REQ_CTRL2_REG      0x0304
+#define AB4500_REGU_REQ_CTRL3_REG      0x0305
+#define AB4500_REGU_REQ_CTRL4_REG      0x0306
+#define AB4500_REGU_MISC1_REG          0x0380
+#define AB4500_REGU_OTGSUPPLY_CTRL_REG 0x0381
+#define AB4500_REGU_VUSB_CTRL_REG      0x0382
+#define AB4500_REGU_VAUDIO_SUPPLY_REG  0x0383
+#define AB4500_REGU_CTRL1_SPARE_REG    0x0384
+
+/*
+ * Regu control2 Vmod register offsets
+ */
+#define AB4500_REGU_VMOD_REGU_REG      0x0440
+#define AB4500_REGU_VMOD_SEL1_REG      0x0441
+#define AB4500_REGU_VMOD_SEL2_REG      0x0442
+#define AB4500_REGU_CTRL_DISCH_REG     0x0443
+#define AB4500_REGU_CTRL_DISCH2_REG    0x0444
+
+/*
+ * USB/ULPI register offsets
+ * Bank : 0x5
+ */
+#define AB4500_USB_LINE_STAT_REG       0x0580
+#define AB4500_USB_LINE_CTRL1_REG      0x0581
+#define AB4500_USB_LINE_CTRL2_REG      0x0582
+#define AB4500_USB_LINE_CTRL3_REG      0x0583
+#define AB4500_USB_LINE_CTRL4_REG      0x0584
+#define AB4500_USB_LINE_CTRL5_REG      0x0585
+#define AB4500_USB_OTG_CTRL_REG                0x0587
+#define AB4500_USB_OTG_STAT_REG                0x0588
+#define AB4500_USB_OTG_STAT_REG                0x0588
+#define AB4500_USB_CTRL_SPARE_REG      0x0589
+#define AB4500_USB_PHY_CTRL_REG                0x058A
+
+/*
+ * TVOUT / CTRL register offsets
+ * Bank : 0x06
+ */
+#define AB4500_TVOUT_CTRL_REG          0x0680
+
+/*
+ * DBI register offsets
+ * Bank : 0x07
+ */
+#define AB4500_DBI_REG1_REG            0x0700
+#define AB4500_DBI_REG2_REG            0x0701
+
+/*
+ * ECI regsiter offsets
+ * Bank : 0x08
+ */
+#define AB4500_ECI_CTRL_REG            0x0800
+#define AB4500_ECI_HOOKLEVEL_REG       0x0801
+#define AB4500_ECI_DATAOUT_REG         0x0802
+#define AB4500_ECI_DATAIN_REG          0x0803
+
+/*
+ * AV Connector register offsets
+ * Bank : 0x08
+ */
+#define AB4500_AV_CONN_REG             0x0840
+
+/*
+ * Accessory detection register offsets
+ * Bank : 0x08
+ */
+#define AB4500_ACC_DET_DB1_REG         0x0880
+#define AB4500_ACC_DET_DB2_REG         0x0881
+
+/*
+ * GPADC register offsets
+ * Bank : 0x0A
+ */
+#define AB4500_GPADC_CTRL1_REG         0x0A00
+#define AB4500_GPADC_CTRL2_REG         0x0A01
+#define AB4500_GPADC_CTRL3_REG         0x0A02
+#define AB4500_GPADC_AUTO_TIMER_REG    0x0A03
+#define AB4500_GPADC_STAT_REG          0x0A04
+#define AB4500_GPADC_MANDATAL_REG      0x0A05
+#define AB4500_GPADC_MANDATAH_REG      0x0A06
+#define AB4500_GPADC_AUTODATAL_REG     0x0A07
+#define AB4500_GPADC_AUTODATAH_REG     0x0A08
+#define AB4500_GPADC_MUX_CTRL_REG      0x0A09
+
+/*
+ * Charger / status register offfsets
+ * Bank : 0x0B
+ */
+#define AB4500_CH_STATUS1_REG          0x0B00
+#define AB4500_CH_STATUS2_REG          0x0B01
+#define AB4500_CH_USBCH_STAT1_REG      0x0B02
+#define AB4500_CH_USBCH_STAT2_REG      0x0B03
+#define AB4500_CH_FSM_STAT_REG         0x0B04
+#define AB4500_CH_STAT_REG             0x0B05
+
+/*
+ * Charger / control register offfsets
+ * Bank : 0x0B
+ */
+#define AB4500_CH_VOLT_LVL_REG         0x0B40
+
+/*
+ * Charger / main control register offfsets
+ * Bank : 0x0B
+ */
+#define AB4500_MCH_CTRL1               0x0B80
+#define AB4500_MCH_CTRL2               0x0B81
+#define AB4500_MCH_IPT_CURLVL_REG      0x0B82
+#define AB4500_CH_WD_REG               0x0B83
+
+/*
+ * Charger / USB control register offsets
+ * Bank : 0x0B
+ */
+#define AB4500_USBCH_CTRL1_REG         0x0BC0
+#define AB4500_USBCH_CTRL2_REG         0x0BC1
+#define AB4500_USBCH_IPT_CRNTLVL_REG   0x0BC2
+
+/*
+ * RTC bank register offsets
+ * Bank : 0xF
+ */
+#define AB4500_RTC_SOFF_STAT_REG       0x0F00
+#define AB4500_RTC_CC_CONF_REG         0x0F01
+#define AB4500_RTC_READ_REQ_REG                0x0F02
+#define AB4500_RTC_WATCH_TSECMID_REG   0x0F03
+#define AB4500_RTC_WATCH_TSECHI_REG    0x0F04
+#define AB4500_RTC_WATCH_TMIN_LOW_REG  0x0F05
+#define AB4500_RTC_WATCH_TMIN_MID_REG  0x0F06
+#define AB4500_RTC_WATCH_TMIN_HI_REG   0x0F07
+#define AB4500_RTC_ALRM_MIN_LOW_REG    0x0F08
+#define AB4500_RTC_ALRM_MIN_MID_REG    0x0F09
+#define AB4500_RTC_ALRM_MIN_HI_REG     0x0F0A
+#define AB4500_RTC_STAT_REG            0x0F0B
+#define AB4500_RTC_BKUP_CHG_REG                0x0F0C
+#define AB4500_RTC_FORCE_BKUP_REG      0x0F0D
+#define AB4500_RTC_CALIB_REG           0x0F0E
+#define AB4500_RTC_SWITCH_STAT_REG     0x0F0F
+
+/*
+ * PWM Out generators
+ * Bank: 0x10
+ */
+#define AB4500_PWM_OUT_CTRL1_REG       0x1060
+#define AB4500_PWM_OUT_CTRL2_REG       0x1061
+#define AB4500_PWM_OUT_CTRL3_REG       0x1062
+#define AB4500_PWM_OUT_CTRL4_REG       0x1063
+#define AB4500_PWM_OUT_CTRL5_REG       0x1064
+#define AB4500_PWM_OUT_CTRL6_REG       0x1065
+#define AB4500_PWM_OUT_CTRL7_REG       0x1066
+
+#define AB4500_I2C_PAD_CTRL_REG                0x1067
+#define AB4500_REV_REG                 0x1080
+
+/**
+ * struct ab4500
+ * @spi: spi device structure
+ * @tx_buf: transmit buffer
+ * @rx_buf: receive buffer
+ * @lock: sync primitive
+ */
+struct ab4500 {
+       struct spi_device       *spi;
+       unsigned long           tx_buf[4];
+       unsigned long           rx_buf[4];
+       struct mutex            lock;
+};
+
+int ab4500_write(struct ab4500 *ab4500, unsigned char block,
+               unsigned long addr, unsigned char data);
+int ab4500_read(struct ab4500 *ab4500, unsigned char block,
+               unsigned long addr);
+
+#endif /* MFD_AB4500_H */
diff --git a/include/linux/mfd/adp5520.h b/include/linux/mfd/adp5520.h
new file mode 100644 (file)
index 0000000..ac37558
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ * Definitions and platform data for Analog Devices
+ * ADP5520/ADP5501 MFD PMICs (Backlight, LED, GPIO and Keys)
+ *
+ * Copyright 2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+
+#ifndef __LINUX_MFD_ADP5520_H
+#define __LINUX_MFD_ADP5520_H
+
+#define ID_ADP5520             5520
+#define ID_ADP5501             5501
+
+/*
+ * ADP5520/ADP5501 Register Map
+ */
+
+#define ADP5520_MODE_STATUS            0x00
+#define ADP5520_INTERRUPT_ENABLE       0x01
+#define ADP5520_BL_CONTROL             0x02
+#define ADP5520_BL_TIME                0x03
+#define ADP5520_BL_FADE                0x04
+#define ADP5520_DAYLIGHT_MAX           0x05
+#define ADP5520_DAYLIGHT_DIM           0x06
+#define ADP5520_OFFICE_MAX             0x07
+#define ADP5520_OFFICE_DIM             0x08
+#define ADP5520_DARK_MAX               0x09
+#define ADP5520_DARK_DIM               0x0A
+#define ADP5520_BL_VALUE               0x0B
+#define ADP5520_ALS_CMPR_CFG           0x0C
+#define ADP5520_L2_TRIP                0x0D
+#define ADP5520_L2_HYS                         0x0E
+#define ADP5520_L3_TRIP                0x0F
+#define ADP5520_L3_HYS                         0x10
+#define ADP5520_LED_CONTROL            0x11
+#define ADP5520_LED_TIME               0x12
+#define ADP5520_LED_FADE               0x13
+#define ADP5520_LED1_CURRENT           0x14
+#define ADP5520_LED2_CURRENT           0x15
+#define ADP5520_LED3_CURRENT           0x16
+
+/*
+ * ADP5520 Register Map
+ */
+
+#define ADP5520_GPIO_CFG_1             0x17
+#define ADP5520_GPIO_CFG_2             0x18
+#define ADP5520_GPIO_IN                0x19
+#define ADP5520_GPIO_OUT               0x1A
+#define ADP5520_GPIO_INT_EN            0x1B
+#define ADP5520_GPIO_INT_STAT          0x1C
+#define ADP5520_GPIO_INT_LVL           0x1D
+#define ADP5520_GPIO_DEBOUNCE          0x1E
+#define ADP5520_GPIO_PULLUP            0x1F
+#define ADP5520_KP_INT_STAT_1          0x20
+#define ADP5520_KP_INT_STAT_2          0x21
+#define ADP5520_KR_INT_STAT_1          0x22
+#define ADP5520_KR_INT_STAT_2          0x23
+#define ADP5520_KEY_STAT_1             0x24
+#define ADP5520_KEY_STAT_2             0x25
+
+/*
+ * MODE_STATUS bits
+ */
+
+#define ADP5520_nSTNBY         (1 << 7)
+#define ADP5520_BL_EN           (1 << 6)
+#define ADP5520_DIM_EN          (1 << 5)
+#define ADP5520_OVP_INT         (1 << 4)
+#define ADP5520_CMPR_INT        (1 << 3)
+#define ADP5520_GPI_INT         (1 << 2)
+#define ADP5520_KR_INT          (1 << 1)
+#define ADP5520_KP_INT          (1 << 0)
+
+/*
+ * INTERRUPT_ENABLE bits
+ */
+
+#define ADP5520_AUTO_LD_EN      (1 << 4)
+#define ADP5520_CMPR_IEN        (1 << 3)
+#define ADP5520_OVP_IEN         (1 << 2)
+#define ADP5520_KR_IEN          (1 << 1)
+#define ADP5520_KP_IEN          (1 << 0)
+
+/*
+ * BL_CONTROL bits
+ */
+
+#define ADP5520_BL_LVL          ((x) << 5)
+#define ADP5520_BL_LAW          ((x) << 4)
+#define ADP5520_BL_AUTO_ADJ     (1 << 3)
+#define ADP5520_OVP_EN          (1 << 2)
+#define ADP5520_FOVR            (1 << 1)
+#define ADP5520_KP_BL_EN        (1 << 0)
+
+/*
+ * ALS_CMPR_CFG bits
+ */
+
+#define ADP5520_L3_OUT         (1 << 3)
+#define ADP5520_L2_OUT         (1 << 2)
+#define ADP5520_L3_EN          (1 << 1)
+
+#define ADP5020_MAX_BRIGHTNESS 0x7F
+
+#define FADE_VAL(in, out)      ((0xF & (in)) | ((0xF & (out)) << 4))
+#define BL_CTRL_VAL(law, auto) (((1 & (auto)) << 3) | ((0x3 & (law)) << 4))
+#define ALS_CMPR_CFG_VAL(filt, l3_en)  (((0x7 & filt) << 5) | l3_en)
+
+/*
+ * LEDs subdevice bits and masks
+ */
+
+#define ADP5520_01_MAXLEDS 3
+
+#define ADP5520_FLAG_LED_MASK          0x3
+#define ADP5520_FLAG_OFFT_SHIFT        8
+#define ADP5520_FLAG_OFFT_MASK                 0x3
+
+#define ADP5520_R3_MODE                (1 << 5)
+#define ADP5520_C3_MODE                (1 << 4)
+#define ADP5520_LED_LAW                (1 << 3)
+#define ADP5520_LED3_EN                (1 << 2)
+#define ADP5520_LED2_EN                (1 << 1)
+#define ADP5520_LED1_EN                (1 << 0)
+
+/*
+ * GPIO subdevice bits and masks
+ */
+
+#define ADP5520_MAXGPIOS       8
+
+#define ADP5520_GPIO_C3                (1 << 7)        /* LED2 or GPIO7 aka C3 */
+#define ADP5520_GPIO_C2                (1 << 6)
+#define ADP5520_GPIO_C1                (1 << 5)
+#define ADP5520_GPIO_C0                (1 << 4)
+#define ADP5520_GPIO_R3                (1 << 3)        /* LED3 or GPIO3 aka R3 */
+#define ADP5520_GPIO_R2                (1 << 2)
+#define ADP5520_GPIO_R1                (1 << 1)
+#define ADP5520_GPIO_R0                (1 << 0)
+
+struct adp5520_gpio_platform_data {
+       unsigned gpio_start;
+       u8 gpio_en_mask;
+       u8 gpio_pullup_mask;
+};
+
+/*
+ * Keypad subdevice bits and masks
+ */
+
+#define ADP5520_MAXKEYS        16
+
+#define ADP5520_COL_C3                 (1 << 7)        /* LED2 or GPIO7 aka C3 */
+#define ADP5520_COL_C2         (1 << 6)
+#define ADP5520_COL_C1         (1 << 5)
+#define ADP5520_COL_C0         (1 << 4)
+#define ADP5520_ROW_R3         (1 << 3)        /* LED3 or GPIO3 aka R3 */
+#define ADP5520_ROW_R2         (1 << 2)
+#define ADP5520_ROW_R1         (1 << 1)
+#define ADP5520_ROW_R0         (1 << 0)
+
+#define ADP5520_KEY(row, col) (col + row * 4)
+#define ADP5520_KEYMAPSIZE     ADP5520_MAXKEYS
+
+struct adp5520_keys_platform_data {
+       int rows_en_mask;               /* Number of rows */
+       int cols_en_mask;               /* Number of columns */
+       const unsigned short *keymap;   /* Pointer to keymap */
+       unsigned short keymapsize;      /* Keymap size */
+       unsigned repeat:1;              /* Enable key repeat */
+};
+
+
+/*
+ * LEDs subdevice platform data
+ */
+
+#define FLAG_ID_ADP5520_LED1_ADP5501_LED0      1       /* ADP5520 PIN ILED */
+#define FLAG_ID_ADP5520_LED2_ADP5501_LED1      2       /* ADP5520 PIN C3 */
+#define FLAG_ID_ADP5520_LED3_ADP5501_LED2      3       /* ADP5520 PIN R3 */
+
+#define ADP5520_LED_DIS_BLINK  (0 << ADP5520_FLAG_OFFT_SHIFT)
+#define ADP5520_LED_OFFT_600ms (1 << ADP5520_FLAG_OFFT_SHIFT)
+#define ADP5520_LED_OFFT_800ms (2 << ADP5520_FLAG_OFFT_SHIFT)
+#define ADP5520_LED_OFFT_1200ms        (3 << ADP5520_FLAG_OFFT_SHIFT)
+
+#define ADP5520_LED_ONT_200ms  0
+#define ADP5520_LED_ONT_600ms  1
+#define ADP5520_LED_ONT_800ms  2
+#define ADP5520_LED_ONT_1200ms 3
+
+struct adp5520_leds_platform_data {
+       int num_leds;
+       struct led_info *leds;
+       u8 fade_in;             /* Backlight Fade-In Timer */
+       u8 fade_out;            /* Backlight Fade-Out Timer */
+       u8 led_on_time;
+};
+
+/*
+ * Backlight subdevice platform data
+ */
+
+#define ADP5520_FADE_T_DIS     0       /* Fade Timer Disabled */
+#define ADP5520_FADE_T_300ms   1       /* 0.3 Sec */
+#define ADP5520_FADE_T_600ms   2
+#define ADP5520_FADE_T_900ms   3
+#define ADP5520_FADE_T_1200ms  4
+#define ADP5520_FADE_T_1500ms  5
+#define ADP5520_FADE_T_1800ms  6
+#define ADP5520_FADE_T_2100ms  7
+#define ADP5520_FADE_T_2400ms  8
+#define ADP5520_FADE_T_2700ms  9
+#define ADP5520_FADE_T_3000ms  10
+#define ADP5520_FADE_T_3500ms  11
+#define ADP5520_FADE_T_4000ms  12
+#define ADP5520_FADE_T_4500ms  13
+#define ADP5520_FADE_T_5000ms  14
+#define ADP5520_FADE_T_5500ms  15      /* 5.5 Sec */
+
+#define ADP5520_BL_LAW_LINEAR  0
+#define ADP5520_BL_LAW_SQUARE  1
+#define ADP5520_BL_LAW_CUBIC1  2
+#define ADP5520_BL_LAW_CUBIC2  3
+
+#define ADP5520_BL_AMBL_FILT_80ms      0       /* Light sensor filter time */
+#define ADP5520_BL_AMBL_FILT_160ms     1
+#define ADP5520_BL_AMBL_FILT_320ms     2
+#define ADP5520_BL_AMBL_FILT_640ms     3
+#define ADP5520_BL_AMBL_FILT_1280ms    4
+#define ADP5520_BL_AMBL_FILT_2560ms    5
+#define ADP5520_BL_AMBL_FILT_5120ms    6
+#define ADP5520_BL_AMBL_FILT_10240ms   7       /* 10.24 sec */
+
+       /*
+        * Blacklight current 0..30mA
+        */
+#define ADP5520_BL_CUR_mA(I)           ((I * 127) / 30)
+
+       /*
+        * L2 comparator current 0..1000uA
+        */
+#define ADP5520_L2_COMP_CURR_uA(I)     ((I * 255) / 1000)
+
+       /*
+        * L3 comparator current 0..127uA
+        */
+#define ADP5520_L3_COMP_CURR_uA(I)     ((I * 255) / 127)
+
+struct adp5520_backlight_platform_data {
+       u8 fade_in;             /* Backlight Fade-In Timer */
+       u8 fade_out;            /* Backlight Fade-Out Timer */
+       u8 fade_led_law;        /* fade-on/fade-off transfer characteristic */
+
+       u8 en_ambl_sens;        /* 1 = enable ambient light sensor */
+       u8 abml_filt;           /* Light sensor filter time */
+       u8 l1_daylight_max;     /* use BL_CUR_mA(I) 0 <= I <= 30 mA */
+       u8 l1_daylight_dim;     /* typ = 0, use BL_CUR_mA(I) 0 <= I <= 30 mA */
+       u8 l2_office_max;       /* use BL_CUR_mA(I) 0 <= I <= 30 mA */
+       u8 l2_office_dim;       /* typ = 0, use BL_CUR_mA(I) 0 <= I <= 30 mA */
+       u8 l3_dark_max;         /* use BL_CUR_mA(I) 0 <= I <= 30 mA */
+       u8 l3_dark_dim;         /* typ = 0, use BL_CUR_mA(I) 0 <= I <= 30 mA */
+       u8 l2_trip;             /* use L2_COMP_CURR_uA(I) 0 <= I <= 1000 uA */
+       u8 l2_hyst;             /* use L2_COMP_CURR_uA(I) 0 <= I <= 1000 uA */
+       u8 l3_trip;             /* use L3_COMP_CURR_uA(I) 0 <= I <= 127 uA */
+       u8 l3_hyst;             /* use L3_COMP_CURR_uA(I) 0 <= I <= 127 uA */
+};
+
+/*
+ * MFD chip platform data
+ */
+
+struct adp5520_platform_data {
+       struct adp5520_keys_platform_data *keys;
+       struct adp5520_gpio_platform_data *gpio;
+       struct adp5520_leds_platform_data *leds;
+       struct adp5520_backlight_platform_data *backlight;
+};
+
+/*
+ * MFD chip functions
+ */
+
+extern int adp5520_read(struct device *dev, int reg, uint8_t *val);
+extern int adp5520_write(struct device *dev, int reg, u8 val);
+extern int adp5520_clr_bits(struct device *dev, int reg, uint8_t bit_mask);
+extern int adp5520_set_bits(struct device *dev, int reg, uint8_t bit_mask);
+
+extern int adp5520_register_notifier(struct device *dev,
+                struct notifier_block *nb, unsigned int events);
+
+extern int adp5520_unregister_notifier(struct device *dev,
+               struct notifier_block *nb, unsigned int events);
+
+#endif /* __LINUX_MFD_ADP5520_H */
index 3402042ddc31856e6ca4a7e05991c868ddf2633c..40c372165f3edc0413a709c57c4e728bd0198ca5 100644 (file)
@@ -231,9 +231,6 @@ void pcap_set_ts_bits(struct pcap_chip *, u32);
 #define PCAP_LED_4MA           1
 #define PCAP_LED_5MA           2
 #define PCAP_LED_9MA           3
-#define PCAP_LED_GPIO_VAL_MASK 0x00ffffff
-#define PCAP_LED_GPIO_EN       0x01000000
-#define PCAP_LED_GPIO_INVERT   0x02000000
 #define PCAP_LED_T_MASK                0xf
 #define PCAP_LED_C_MASK                0x3
 #define PCAP_BL_MASK           0x1f
index 47e698cb0f16264572c07a611de386686214555e..95cf9360553fb3d1a836e1ccabdcefb245c04b4a 100644 (file)
 
 #include <linux/platform_device.h>
 #include <linux/mfd/mc13783.h>
-#include <linux/workqueue.h>
 #include <linux/mutex.h>
-
-struct mc13783_irq {
-       void (*handler)(int, void *);
-       void *data;
-};
-
-#define MC13783_NUM_IRQ                2
-#define MC13783_IRQ_TS         0
-#define MC13783_IRQ_REGULATOR  1
-
-#define MC13783_ADC_MODE_TS            1
-#define MC13783_ADC_MODE_SINGLE_CHAN   2
-#define MC13783_ADC_MODE_MULT_CHAN     3
+#include <linux/interrupt.h>
 
 struct mc13783 {
-       int revision;
-       struct device *dev;
-       struct spi_device *spi_device;
-
-       int (*read_dev)(void *data, char reg, int count, u32 *dst);
-       int (*write_dev)(void *data, char reg, int count, const u32 *src);
-
-       struct mutex io_lock;
-       void *io_data;
+       struct spi_device *spidev;
+       struct mutex lock;
        int irq;
-       unsigned int flags;
+       int flags;
 
-       struct mc13783_irq irq_handler[MC13783_NUM_IRQ];
-       struct work_struct work;
-       struct completion adc_done;
-       unsigned int ts_active;
-       struct mutex adc_conv_lock;
+       irq_handler_t irqhandler[MC13783_NUM_IRQ];
+       void *irqdata[MC13783_NUM_IRQ];
 
+       /* XXX these should go as platformdata to the regulator subdevice */
        struct mc13783_regulator_init_data *regulators;
        int num_regulators;
 };
 
-int mc13783_reg_read(struct mc13783 *, int reg_num, u32 *);
-int mc13783_reg_write(struct mc13783 *, int, u32);
-int mc13783_set_bits(struct mc13783 *, int, u32, u32);
-int mc13783_free_irq(struct mc13783 *mc13783, int irq);
-int mc13783_register_irq(struct mc13783 *mc13783, int irq,
-               void (*handler) (int, void *), void *data);
-
 #define MC13783_REG_INTERRUPT_STATUS_0          0
 #define MC13783_REG_INTERRUPT_MASK_0            1
 #define MC13783_REG_INTERRUPT_SENSE_0           2
@@ -136,55 +107,6 @@ int mc13783_register_irq(struct mc13783 *mc13783, int irq,
 #define MC13783_REG_TEST_3                     63
 #define MC13783_REG_NB                         64
 
-
-/*
- * Interrupt Status
- */
-#define MC13783_INT_STAT_ADCDONEI      (1 << 0)
-#define MC13783_INT_STAT_ADCBISDONEI   (1 << 1)
-#define MC13783_INT_STAT_TSI           (1 << 2)
-#define MC13783_INT_STAT_WHIGHI                (1 << 3)
-#define MC13783_INT_STAT_WLOWI         (1 << 4)
-#define MC13783_INT_STAT_CHGDETI       (1 << 6)
-#define MC13783_INT_STAT_CHGOVI                (1 << 7)
-#define MC13783_INT_STAT_CHGREVI       (1 << 8)
-#define MC13783_INT_STAT_CHGSHORTI     (1 << 9)
-#define MC13783_INT_STAT_CCCVI         (1 << 10)
-#define MC13783_INT_STAT_CHGCURRI      (1 << 11)
-#define MC13783_INT_STAT_BPONI         (1 << 12)
-#define MC13783_INT_STAT_LOBATLI       (1 << 13)
-#define MC13783_INT_STAT_LOBATHI       (1 << 14)
-#define MC13783_INT_STAT_UDPI          (1 << 15)
-#define MC13783_INT_STAT_USBI          (1 << 16)
-#define MC13783_INT_STAT_IDI           (1 << 19)
-#define MC13783_INT_STAT_Unused                (1 << 20)
-#define MC13783_INT_STAT_SE1I          (1 << 21)
-#define MC13783_INT_STAT_CKDETI                (1 << 22)
-#define MC13783_INT_STAT_UDMI          (1 << 23)
-
-/*
- * Interrupt Mask
- */
-#define MC13783_INT_MASK_ADCDONEM      (1 << 0)
-#define MC13783_INT_MASK_ADCBISDONEM   (1 << 1)
-#define MC13783_INT_MASK_TSM           (1 << 2)
-#define MC13783_INT_MASK_WHIGHM                (1 << 3)
-#define MC13783_INT_MASK_WLOWM         (1 << 4)
-#define MC13783_INT_MASK_CHGDETM       (1 << 6)
-#define MC13783_INT_MASK_CHGOVM                (1 << 7)
-#define MC13783_INT_MASK_CHGREVM       (1 << 8)
-#define MC13783_INT_MASK_CHGSHORTM     (1 << 9)
-#define MC13783_INT_MASK_CCCVM         (1 << 10)
-#define MC13783_INT_MASK_CHGCURRM      (1 << 11)
-#define MC13783_INT_MASK_BPONM         (1 << 12)
-#define MC13783_INT_MASK_LOBATLM       (1 << 13)
-#define MC13783_INT_MASK_LOBATHM       (1 << 14)
-#define MC13783_INT_MASK_UDPM          (1 << 15)
-#define MC13783_INT_MASK_USBM          (1 << 16)
-#define MC13783_INT_MASK_IDM           (1 << 19)
-#define MC13783_INT_MASK_SE1M          (1 << 21)
-#define MC13783_INT_MASK_CKDETM                (1 << 22)
-
 /*
  * Reg Regulator Mode 0
  */
@@ -284,113 +206,15 @@ int mc13783_register_irq(struct mc13783 *mc13783, int irq,
 #define MC13783_SWCTRL_SW3_STBY                (1 << 21)
 #define MC13783_SWCTRL_SW3_MODE                (1 << 22)
 
-/*
- * ADC/Touch
- */
-#define MC13783_ADC0_LICELLCON         (1 << 0)
-#define MC13783_ADC0_CHRGICON          (1 << 1)
-#define MC13783_ADC0_BATICON           (1 << 2)
-#define MC13783_ADC0_RTHEN             (1 << 3)
-#define MC13783_ADC0_DTHEN             (1 << 4)
-#define MC13783_ADC0_UIDEN             (1 << 5)
-#define MC13783_ADC0_ADOUTEN           (1 << 6)
-#define MC13783_ADC0_ADOUTPER          (1 << 7)
-#define MC13783_ADC0_ADREFEN           (1 << 10)
-#define MC13783_ADC0_ADREFMODE         (1 << 11)
-#define MC13783_ADC0_TSMOD0            (1 << 12)
-#define MC13783_ADC0_TSMOD1            (1 << 13)
-#define MC13783_ADC0_TSMOD2            (1 << 14)
-#define MC13783_ADC0_CHRGRAWDIV                (1 << 15)
-#define MC13783_ADC0_ADINC1            (1 << 16)
-#define MC13783_ADC0_ADINC2            (1 << 17)
-#define MC13783_ADC0_WCOMP             (1 << 18)
-#define MC13783_ADC0_ADCBIS0           (1 << 23)
-
-#define MC13783_ADC1_ADEN              (1 << 0)
-#define MC13783_ADC1_RAND              (1 << 1)
-#define MC13783_ADC1_ADSEL             (1 << 3)
-#define MC13783_ADC1_TRIGMASK          (1 << 4)
-#define MC13783_ADC1_ADA10             (1 << 5)
-#define MC13783_ADC1_ADA11             (1 << 6)
-#define MC13783_ADC1_ADA12             (1 << 7)
-#define MC13783_ADC1_ADA20             (1 << 8)
-#define MC13783_ADC1_ADA21             (1 << 9)
-#define MC13783_ADC1_ADA22             (1 << 10)
-#define MC13783_ADC1_ATO0              (1 << 11)
-#define MC13783_ADC1_ATO1              (1 << 12)
-#define MC13783_ADC1_ATO2              (1 << 13)
-#define MC13783_ADC1_ATO3              (1 << 14)
-#define MC13783_ADC1_ATO4              (1 << 15)
-#define MC13783_ADC1_ATO5              (1 << 16)
-#define MC13783_ADC1_ATO6              (1 << 17)
-#define MC13783_ADC1_ATO7              (1 << 18)
-#define MC13783_ADC1_ATOX              (1 << 19)
-#define MC13783_ADC1_ASC               (1 << 20)
-#define MC13783_ADC1_ADTRIGIGN         (1 << 21)
-#define MC13783_ADC1_ADONESHOT         (1 << 22)
-#define MC13783_ADC1_ADCBIS1           (1 << 23)
-
-#define MC13783_ADC1_CHAN0_SHIFT       5
-#define MC13783_ADC1_CHAN1_SHIFT       8
-
-#define MC13783_ADC2_ADD10             (1 << 2)
-#define MC13783_ADC2_ADD11             (1 << 3)
-#define MC13783_ADC2_ADD12             (1 << 4)
-#define MC13783_ADC2_ADD13             (1 << 5)
-#define MC13783_ADC2_ADD14             (1 << 6)
-#define MC13783_ADC2_ADD15             (1 << 7)
-#define MC13783_ADC2_ADD16             (1 << 8)
-#define MC13783_ADC2_ADD17             (1 << 9)
-#define MC13783_ADC2_ADD18             (1 << 10)
-#define MC13783_ADC2_ADD19             (1 << 11)
-#define MC13783_ADC2_ADD20             (1 << 14)
-#define MC13783_ADC2_ADD21             (1 << 15)
-#define MC13783_ADC2_ADD22             (1 << 16)
-#define MC13783_ADC2_ADD23             (1 << 17)
-#define MC13783_ADC2_ADD24             (1 << 18)
-#define MC13783_ADC2_ADD25             (1 << 19)
-#define MC13783_ADC2_ADD26             (1 << 20)
-#define MC13783_ADC2_ADD27             (1 << 21)
-#define MC13783_ADC2_ADD28             (1 << 22)
-#define MC13783_ADC2_ADD29             (1 << 23)
+static inline int mc13783_set_bits(struct mc13783 *mc13783, unsigned int offset,
+               u32 mask, u32 val)
+{
+       int ret;
+       mc13783_lock(mc13783);
+       ret = mc13783_reg_rmw(mc13783, offset, mask, val);
+       mc13783_unlock(mc13783);
 
-#define MC13783_ADC3_WHIGH0            (1 << 0)
-#define MC13783_ADC3_WHIGH1            (1 << 1)
-#define MC13783_ADC3_WHIGH2            (1 << 2)
-#define MC13783_ADC3_WHIGH3            (1 << 3)
-#define MC13783_ADC3_WHIGH4            (1 << 4)
-#define MC13783_ADC3_WHIGH5            (1 << 5)
-#define MC13783_ADC3_ICID0             (1 << 6)
-#define MC13783_ADC3_ICID1             (1 << 7)
-#define MC13783_ADC3_ICID2             (1 << 8)
-#define MC13783_ADC3_WLOW0             (1 << 9)
-#define MC13783_ADC3_WLOW1             (1 << 10)
-#define MC13783_ADC3_WLOW2             (1 << 11)
-#define MC13783_ADC3_WLOW3             (1 << 12)
-#define MC13783_ADC3_WLOW4             (1 << 13)
-#define MC13783_ADC3_WLOW5             (1 << 14)
-#define MC13783_ADC3_ADCBIS2           (1 << 23)
-
-#define MC13783_ADC4_ADDBIS10          (1 << 2)
-#define MC13783_ADC4_ADDBIS11          (1 << 3)
-#define MC13783_ADC4_ADDBIS12          (1 << 4)
-#define MC13783_ADC4_ADDBIS13          (1 << 5)
-#define MC13783_ADC4_ADDBIS14          (1 << 6)
-#define MC13783_ADC4_ADDBIS15          (1 << 7)
-#define MC13783_ADC4_ADDBIS16          (1 << 8)
-#define MC13783_ADC4_ADDBIS17          (1 << 9)
-#define MC13783_ADC4_ADDBIS18          (1 << 10)
-#define MC13783_ADC4_ADDBIS19          (1 << 11)
-#define MC13783_ADC4_ADDBIS20          (1 << 14)
-#define MC13783_ADC4_ADDBIS21          (1 << 15)
-#define MC13783_ADC4_ADDBIS22          (1 << 16)
-#define MC13783_ADC4_ADDBIS23          (1 << 17)
-#define MC13783_ADC4_ADDBIS24          (1 << 18)
-#define MC13783_ADC4_ADDBIS25          (1 << 19)
-#define MC13783_ADC4_ADDBIS26          (1 << 20)
-#define MC13783_ADC4_ADDBIS27          (1 << 21)
-#define MC13783_ADC4_ADDBIS28          (1 << 22)
-#define MC13783_ADC4_ADDBIS29          (1 << 23)
+       return ret;
+}
 
 #endif /* __LINUX_MFD_MC13783_PRIV_H */
-
index b3a2a7243573e2d5438688881b08c36497ca795f..35680409b8cfd3674c0a319e252fbb204ca5e1c9 100644 (file)
@@ -1,28 +1,50 @@
 /*
- * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright 2009 Pengutronix
+ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
  *
- * Initial development of this code was funded by
- * Phytec Messtechnik GmbH, http://www.phytec.de
- *
- * 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.
+ * 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_MFD_MC13783_H
+#define __LINUX_MFD_MC13783_H
 
-#ifndef __INCLUDE_LINUX_MFD_MC13783_H
-#define __INCLUDE_LINUX_MFD_MC13783_H
+#include <linux/interrupt.h>
 
 struct mc13783;
+
+void mc13783_lock(struct mc13783 *mc13783);
+void mc13783_unlock(struct mc13783 *mc13783);
+
+int mc13783_reg_read(struct mc13783 *mc13783, unsigned int offset, u32 *val);
+int mc13783_reg_write(struct mc13783 *mc13783, unsigned int offset, u32 val);
+int mc13783_reg_rmw(struct mc13783 *mc13783, unsigned int offset,
+               u32 mask, u32 val);
+
+int mc13783_irq_request(struct mc13783 *mc13783, int irq,
+               irq_handler_t handler, const char *name, void *dev);
+int mc13783_irq_request_nounmask(struct mc13783 *mc13783, int irq,
+               irq_handler_t handler, const char *name, void *dev);
+int mc13783_irq_free(struct mc13783 *mc13783, int irq, void *dev);
+int mc13783_ackirq(struct mc13783 *mc13783, int irq);
+
+int mc13783_mask(struct mc13783 *mc13783, int irq);
+int mc13783_unmask(struct mc13783 *mc13783, int irq);
+
+#define MC13783_ADC0           43
+#define MC13783_ADC0_ADREFEN           (1 << 10)
+#define MC13783_ADC0_ADREFMODE         (1 << 11)
+#define MC13783_ADC0_TSMOD0            (1 << 12)
+#define MC13783_ADC0_TSMOD1            (1 << 13)
+#define MC13783_ADC0_TSMOD2            (1 << 14)
+#define MC13783_ADC0_ADINC1            (1 << 16)
+#define MC13783_ADC0_ADINC2            (1 << 17)
+
+#define MC13783_ADC0_TSMOD_MASK                (MC13783_ADC0_TSMOD0 | \
+                                       MC13783_ADC0_TSMOD1 | \
+                                       MC13783_ADC0_TSMOD2)
+
+/* to be cleaned up */
 struct regulator_init_data;
 
 struct mc13783_regulator_init_data {
@@ -30,23 +52,30 @@ struct mc13783_regulator_init_data {
        struct regulator_init_data *init_data;
 };
 
-struct mc13783_platform_data {
-       struct mc13783_regulator_init_data *regulators;
+struct mc13783_regulator_platform_data {
        int num_regulators;
-       unsigned int flags;
+       struct mc13783_regulator_init_data *regulators;
 };
 
-/* mc13783_platform_data flags */
+struct mc13783_platform_data {
+       int num_regulators;
+       struct mc13783_regulator_init_data *regulators;
+
 #define MC13783_USE_TOUCHSCREEN (1 << 0)
 #define MC13783_USE_CODEC      (1 << 1)
 #define MC13783_USE_ADC                (1 << 2)
 #define MC13783_USE_RTC                (1 << 3)
 #define MC13783_USE_REGULATOR  (1 << 4)
+       unsigned int flags;
+};
+
+#define MC13783_ADC_MODE_TS            1
+#define MC13783_ADC_MODE_SINGLE_CHAN   2
+#define MC13783_ADC_MODE_MULT_CHAN     3
 
 int mc13783_adc_do_conversion(struct mc13783 *mc13783, unsigned int mode,
                unsigned int channel, unsigned int *sample);
 
-void mc13783_adc_set_ts_status(struct mc13783 *mc13783, unsigned int status);
 
 #define        MC13783_SW_SW1A         0
 #define        MC13783_SW_SW1B         1
@@ -80,5 +109,46 @@ void mc13783_adc_set_ts_status(struct mc13783 *mc13783, unsigned int status);
 #define        MC13783_REGU_V3         29
 #define        MC13783_REGU_V4         30
 
-#endif /* __INCLUDE_LINUX_MFD_MC13783_H */
+#define MC13783_IRQ_ADCDONE    0
+#define MC13783_IRQ_ADCBISDONE 1
+#define MC13783_IRQ_TS         2
+#define MC13783_IRQ_WHIGH      3
+#define MC13783_IRQ_WLOW       4
+#define MC13783_IRQ_CHGDET     6
+#define MC13783_IRQ_CHGOV      7
+#define MC13783_IRQ_CHGREV     8
+#define MC13783_IRQ_CHGSHORT   9
+#define MC13783_IRQ_CCCV       10
+#define MC13783_IRQ_CHGCURR    11
+#define MC13783_IRQ_BPON       12
+#define MC13783_IRQ_LOBATL     13
+#define MC13783_IRQ_LOBATH     14
+#define MC13783_IRQ_UDP                15
+#define MC13783_IRQ_USB                16
+#define MC13783_IRQ_ID         19
+#define MC13783_IRQ_SE1                21
+#define MC13783_IRQ_CKDET      22
+#define MC13783_IRQ_UDM                23
+#define MC13783_IRQ_1HZ                24
+#define MC13783_IRQ_TODA       25
+#define MC13783_IRQ_ONOFD1     27
+#define MC13783_IRQ_ONOFD2     28
+#define MC13783_IRQ_ONOFD3     29
+#define MC13783_IRQ_SYSRST     30
+#define MC13783_IRQ_RTCRST     31
+#define MC13783_IRQ_PC         32
+#define MC13783_IRQ_WARM       33
+#define MC13783_IRQ_MEMHLD     34
+#define MC13783_IRQ_PWRRDY     35
+#define MC13783_IRQ_THWARNL    36
+#define MC13783_IRQ_THWARNH    37
+#define MC13783_IRQ_CLK                38
+#define MC13783_IRQ_SEMAF      39
+#define MC13783_IRQ_MC2B       41
+#define MC13783_IRQ_HSDET      42
+#define MC13783_IRQ_HSL                43
+#define MC13783_IRQ_ALSPTH     44
+#define MC13783_IRQ_AHSSHORT   45
+#define MC13783_NUM_IRQ                46
 
+#endif /* __LINUX_MFD_MC13783_H */
index 9aba7b779fbc35ee13896e8643f97a976ee49758..d9034cc87f187b764979ecad8d27cd9ef77514b5 100644 (file)
@@ -40,10 +40,6 @@ struct pcf50633_platform_data {
        u8 resumers[5];
 };
 
-struct pcf50633_subdev_pdata {
-       struct pcf50633 *pcf;
-};
-
 struct pcf50633_irq {
        void (*handler) (int, void *);
        void *data;
@@ -217,5 +213,9 @@ enum pcf50633_reg_int5 {
 #define PCF50633_REG_LEDCTL 0x2a
 #define PCF50633_REG_LEDDIM 0x2b
 
-#endif
+static inline struct pcf50633 *dev_to_pcf50633(struct device *dev)
+{
+       return dev_get_drvdata(dev);
+}
 
+#endif
index 91eb493bf14cffc5a8095c729c9c274afb9fea3c..5184b79c700bdc0c7df7ba5016df71e7d2d85665 100644 (file)
@@ -16,7 +16,6 @@
 #define __MFD_WM831X_CORE_H__
 
 #include <linux/interrupt.h>
-#include <linux/workqueue.h>
 
 /*
  * Register values.
 #define WM831X_DC3_SLEEP_CONTROL                0x4063
 #define WM831X_DC4_CONTROL                      0x4064
 #define WM831X_DC4_SLEEP_CONTROL                0x4065
+#define WM832X_DC4_SLEEP_CONTROL                0x4067
 #define WM831X_EPE1_CONTROL                     0x4066
 #define WM831X_EPE2_CONTROL                     0x4067
 #define WM831X_LDO1_CONTROL                     0x4068
 
 struct regulator_dev;
 
+#define WM831X_NUM_IRQ_REGS 5
+
 struct wm831x {
        struct mutex io_lock;
 
@@ -248,10 +250,11 @@ struct wm831x {
 
        int irq;  /* Our chip IRQ */
        struct mutex irq_lock;
-       struct workqueue_struct *irq_wq;
-       struct work_struct irq_work;
        unsigned int irq_base;
-       int irq_masks[5];
+       int irq_masks_cur[WM831X_NUM_IRQ_REGS];   /* Currently active value */
+       int irq_masks_cache[WM831X_NUM_IRQ_REGS]; /* Cached hardware value */
+
+       int num_gpio;
 
        struct mutex auxadc_lock;
 
@@ -278,12 +281,30 @@ int wm831x_bulk_read(struct wm831x *wm831x, unsigned short reg,
 int wm831x_irq_init(struct wm831x *wm831x, int irq);
 void wm831x_irq_exit(struct wm831x *wm831x);
 
-int __must_check wm831x_request_irq(struct wm831x *wm831x,
-                                   unsigned int irq, irq_handler_t handler,
-                                   unsigned long flags, const char *name,
-                                   void *dev);
-void wm831x_free_irq(struct wm831x *wm831x, unsigned int, void *);
-void wm831x_disable_irq(struct wm831x *wm831x, int irq);
-void wm831x_enable_irq(struct wm831x *wm831x, int irq);
+static inline int __must_check wm831x_request_irq(struct wm831x *wm831x,
+                                                 unsigned int irq,
+                                                 irq_handler_t handler,
+                                                 unsigned long flags,
+                                                 const char *name,
+                                                 void *dev)
+{
+       return request_threaded_irq(irq, NULL, handler, flags, name, dev);
+}
+
+static inline void wm831x_free_irq(struct wm831x *wm831x,
+                                  unsigned int irq, void *dev)
+{
+       free_irq(irq, dev);
+}
+
+static inline void wm831x_disable_irq(struct wm831x *wm831x, int irq)
+{
+       disable_irq(irq);
+}
+
+static inline void wm831x_enable_irq(struct wm831x *wm831x, int irq)
+{
+       enable_irq(irq);
+}
 
 #endif
index 90d820260aad579638fdfacd6d7e04a2ac12c907..415c228743d562f3e93bc2c67a49b8dfbbe58a5b 100644 (file)
@@ -91,6 +91,7 @@ struct wm831x_pdata {
        /** Called after subdevices are set up */
        int (*post_init)(struct wm831x *wm831x);
 
+       int irq_base;
        int gpio_base;
        struct wm831x_backlight_pdata *backlight;
        struct wm831x_backup_pdata *backup;
index 1d595de6a055d80962226f2b04ebe5ac8c18ceee..43868899bf4915a56779089651c9532ac1ecf2ec 100644 (file)
@@ -15,7 +15,7 @@
 
 #include <linux/kernel.h>
 #include <linux/mutex.h>
-#include <linux/workqueue.h>
+#include <linux/interrupt.h>
 
 #include <linux/mfd/wm8350/audio.h>
 #include <linux/mfd/wm8350/gpio.h>
@@ -601,7 +601,7 @@ extern const u16 wm8352_mode3_defaults[];
 struct wm8350;
 
 struct wm8350_irq {
-       void (*handler) (struct wm8350 *, int, void *);
+       irq_handler_t handler;
        void *data;
 };
 
@@ -646,10 +646,12 @@ struct wm8350 {
  * @init: Function called during driver initialisation.  Should be
  *        used by the platform to configure GPIO functions and similar.
  * @irq_high: Set if WM8350 IRQ is active high.
+ * @irq_base: Base IRQ for genirq (not currently used).
  */
 struct wm8350_platform_data {
        int (*init)(struct wm8350 *wm8350);
        int irq_high;
+       int irq_base;
 };
 
 
@@ -676,11 +678,13 @@ int wm8350_block_write(struct wm8350 *wm8350, int reg, int size, u16 *src);
  * WM8350 internal interrupts
  */
 int wm8350_register_irq(struct wm8350 *wm8350, int irq,
-                       void (*handler) (struct wm8350 *, int, void *),
-                       void *data);
+                       irq_handler_t handler, unsigned long flags,
+                       const char *name, void *data);
 int wm8350_free_irq(struct wm8350 *wm8350, int irq);
 int wm8350_mask_irq(struct wm8350 *wm8350, int irq);
 int wm8350_unmask_irq(struct wm8350 *wm8350, int irq);
-
+int wm8350_irq_init(struct wm8350 *wm8350, int irq,
+                   struct wm8350_platform_data *pdata);
+int wm8350_irq_exit(struct wm8350 *wm8350);
 
 #endif
index ed91e8f5d298fb8ea393927be7f621e746cf83f6..71af3d6ebe9d1ba1957285d8332a364f4237c724 100644 (file)
 #define WM8350_GPIO_DEBOUNCE_OFF               0
 #define WM8350_GPIO_DEBOUNCE_ON                        1
 
+/*
+ * R30 (0x1E) - GPIO Interrupt Status
+ */
+#define WM8350_GP12_EINT                        0x1000
+#define WM8350_GP11_EINT                        0x0800
+#define WM8350_GP10_EINT                        0x0400
+#define WM8350_GP9_EINT                         0x0200
+#define WM8350_GP8_EINT                         0x0100
+#define WM8350_GP7_EINT                         0x0080
+#define WM8350_GP6_EINT                         0x0040
+#define WM8350_GP5_EINT                         0x0020
+#define WM8350_GP4_EINT                         0x0010
+#define WM8350_GP3_EINT                         0x0008
+#define WM8350_GP2_EINT                         0x0004
+#define WM8350_GP1_EINT                         0x0002
+#define WM8350_GP0_EINT                         0x0001
+
+
 /*
  * R128 (0x80) - GPIO Debounce
  */
index c4c060208109b35ca6ebde436c0d6302ba93cd6a..9b8299af3741be370af6a3443dc5b73d3ba05b11 100644 (file)
 #define SEQ4_STATUS_RECALLABLE_STATE_REVOKED   0x00000040
 #define SEQ4_STATUS_LEASE_MOVED                        0x00000080
 #define SEQ4_STATUS_RESTART_RECLAIM_NEEDED     0x00000100
+#define SEQ4_STATUS_CB_PATH_DOWN_SESSION       0x00000200
+#define SEQ4_STATUS_BACKCHANNEL_FAULT          0x00000400
 
 #define NFS4_MAX_UINT64        (~(u64)0)
 
@@ -528,6 +530,7 @@ enum {
        NFSPROC4_CLNT_DESTROY_SESSION,
        NFSPROC4_CLNT_SEQUENCE,
        NFSPROC4_CLNT_GET_LEASE_TIME,
+       NFSPROC4_CLNT_RECLAIM_COMPLETE,
 };
 
 /* nfs41 types */
index 320569eabe3bcc88dea530ac8634d59223a80409..34fc6be5bfcfd95d03534b59687564fe82071042 100644 (file)
@@ -209,6 +209,7 @@ struct nfs4_session {
        unsigned long                   session_state;
        u32                             hash_alg;
        u32                             ssv_len;
+       struct completion               complete;
 
        /* The fore and back channel */
        struct nfs4_channel_attrs       fc_attrs;
index 62f63fb0c4c8d6cd54c8c798e5d7239408d45d34..51071b335751daa2723a849a23f0595748a7878e 100644 (file)
@@ -170,8 +170,9 @@ struct nfs4_sequence_args {
 struct nfs4_sequence_res {
        struct nfs4_session     *sr_session;
        u8                      sr_slotid;      /* slot used to send request */
-       unsigned long           sr_renewal_time;
        int                     sr_status;      /* sequence operation status */
+       unsigned long           sr_renewal_time;
+       u32                     sr_status_flags;
 };
 
 struct nfs4_get_lease_time_args {
@@ -938,6 +939,16 @@ struct nfs41_create_session_args {
 struct nfs41_create_session_res {
        struct nfs_client              *client;
 };
+
+struct nfs41_reclaim_complete_args {
+       /* In the future extend to include curr_fh for use with migration */
+       unsigned char                   one_fs:1;
+       struct nfs4_sequence_args       seq_args;
+};
+
+struct nfs41_reclaim_complete_res {
+       struct nfs4_sequence_res        seq_res;
+};
 #endif /* CONFIG_NFS_V4_1 */
 
 struct nfs_page;
index 04771b9c33160552cf050e2270af7ce360fd066d..bf1e6708084909b786f19a6fdb095b1573b53df4 100644 (file)
@@ -1255,7 +1255,7 @@ extern int pci_pci_problems;
 
 extern unsigned long pci_cardbus_io_size;
 extern unsigned long pci_cardbus_mem_size;
-extern u8 pci_dfl_cache_line_size;
+extern u8 __devinitdata pci_dfl_cache_line_size;
 extern u8 pci_cache_line_size;
 
 extern unsigned long pci_hotplug_io_size;
index 9bd03193ecd48c5e2c1283309a2c8ac2914cab37..5a5d6ce4bd55a156c979c89072b0c830c93fc5d2 100644 (file)
@@ -60,6 +60,7 @@
 
 #define DEFINE_PER_CPU_SECTION(type, name, sec)                                \
        __PCPU_DUMMY_ATTRS char __pcpu_scope_##name;                    \
+       extern __PCPU_DUMMY_ATTRS char __pcpu_unique_##name;            \
        __PCPU_DUMMY_ATTRS char __pcpu_unique_##name;                   \
        __PCPU_ATTRS(sec) PER_CPU_DEF_ATTRIBUTES __weak                 \
        __typeof__(type) per_cpu__##name
index 878836ca999c0f3e2b65836cbe8bd7816d44ffaa..cf5efbcf716c8cecf74d4d315e2619f6fdcfa1f4 100644 (file)
@@ -34,8 +34,6 @@
 
 #ifdef CONFIG_SMP
 
-#ifndef CONFIG_HAVE_LEGACY_PER_CPU_AREA
-
 /* minimum unit size, also is the maximum supported allocation size */
 #define PCPU_MIN_UNIT_SIZE             PFN_ALIGN(64 << 10)
 
@@ -130,30 +128,9 @@ extern int __init pcpu_page_first_chunk(size_t reserved_size,
 #define per_cpu_ptr(ptr, cpu)  SHIFT_PERCPU_PTR((ptr), per_cpu_offset((cpu)))
 
 extern void *__alloc_reserved_percpu(size_t size, size_t align);
-
-#else /* CONFIG_HAVE_LEGACY_PER_CPU_AREA */
-
-struct percpu_data {
-       void *ptrs[1];
-};
-
-/* pointer disguising messes up the kmemleak objects tracking */
-#ifndef CONFIG_DEBUG_KMEMLEAK
-#define __percpu_disguise(pdata) (struct percpu_data *)~(unsigned long)(pdata)
-#else
-#define __percpu_disguise(pdata) (struct percpu_data *)(pdata)
-#endif
-
-#define per_cpu_ptr(ptr, cpu)                                          \
-({                                                                     \
-        struct percpu_data *__p = __percpu_disguise(ptr);              \
-        (__typeof__(ptr))__p->ptrs[(cpu)];                             \
-})
-
-#endif /* CONFIG_HAVE_LEGACY_PER_CPU_AREA */
-
 extern void *__alloc_percpu(size_t size, size_t align);
 extern void free_percpu(void *__pdata);
+extern phys_addr_t per_cpu_ptr_to_phys(void *addr);
 
 #ifndef CONFIG_HAVE_SETUP_PER_CPU_AREA
 extern void __init setup_per_cpu_areas(void);
@@ -179,6 +156,11 @@ static inline void free_percpu(void *p)
        kfree(p);
 }
 
+static inline phys_addr_t per_cpu_ptr_to_phys(void *addr)
+{
+       return __pa(addr);
+}
+
 static inline void __init setup_per_cpu_areas(void) { }
 
 static inline void *pcpu_lpage_remapped(void *kaddr)
@@ -188,8 +170,8 @@ static inline void *pcpu_lpage_remapped(void *kaddr)
 
 #endif /* CONFIG_SMP */
 
-#define alloc_percpu(type)     (type *)__alloc_percpu(sizeof(type), \
-                                                      __alignof__(type))
+#define alloc_percpu(type)     \
+       (typeof(type) *)__alloc_percpu(sizeof(type), __alignof__(type))
 
 /*
  * Optional methods for optimized non-lvalue per-cpu variable access.
@@ -243,4 +225,404 @@ do {                                                                      \
 # define percpu_xor(var, val)          __percpu_generic_to_op(var, (val), ^=)
 #endif
 
+/*
+ * Branching function to split up a function into a set of functions that
+ * are called for different scalar sizes of the objects handled.
+ */
+
+extern void __bad_size_call_parameter(void);
+
+#define __pcpu_size_call_return(stem, variable)                                \
+({     typeof(variable) pscr_ret__;                                    \
+       switch(sizeof(variable)) {                                      \
+       case 1: pscr_ret__ = stem##1(variable);break;                   \
+       case 2: pscr_ret__ = stem##2(variable);break;                   \
+       case 4: pscr_ret__ = stem##4(variable);break;                   \
+       case 8: pscr_ret__ = stem##8(variable);break;                   \
+       default:                                                        \
+               __bad_size_call_parameter();break;                      \
+       }                                                               \
+       pscr_ret__;                                                     \
+})
+
+#define __pcpu_size_call(stem, variable, ...)                          \
+do {                                                                   \
+       switch(sizeof(variable)) {                                      \
+               case 1: stem##1(variable, __VA_ARGS__);break;           \
+               case 2: stem##2(variable, __VA_ARGS__);break;           \
+               case 4: stem##4(variable, __VA_ARGS__);break;           \
+               case 8: stem##8(variable, __VA_ARGS__);break;           \
+               default:                                                \
+                       __bad_size_call_parameter();break;              \
+       }                                                               \
+} while (0)
+
+/*
+ * Optimized manipulation for memory allocated through the per cpu
+ * allocator or for addresses of per cpu variables (can be determined
+ * using per_cpu_var(xx).
+ *
+ * These operation guarantee exclusivity of access for other operations
+ * on the *same* processor. The assumption is that per cpu data is only
+ * accessed by a single processor instance (the current one).
+ *
+ * The first group is used for accesses that must be done in a
+ * preemption safe way since we know that the context is not preempt
+ * safe. Interrupts may occur. If the interrupt modifies the variable
+ * too then RMW actions will not be reliable.
+ *
+ * The arch code can provide optimized functions in two ways:
+ *
+ * 1. Override the function completely. F.e. define this_cpu_add().
+ *    The arch must then ensure that the various scalar format passed
+ *    are handled correctly.
+ *
+ * 2. Provide functions for certain scalar sizes. F.e. provide
+ *    this_cpu_add_2() to provide per cpu atomic operations for 2 byte
+ *    sized RMW actions. If arch code does not provide operations for
+ *    a scalar size then the fallback in the generic code will be
+ *    used.
+ */
+
+#define _this_cpu_generic_read(pcp)                                    \
+({     typeof(pcp) ret__;                                              \
+       preempt_disable();                                              \
+       ret__ = *this_cpu_ptr(&(pcp));                                  \
+       preempt_enable();                                               \
+       ret__;                                                          \
+})
+
+#ifndef this_cpu_read
+# ifndef this_cpu_read_1
+#  define this_cpu_read_1(pcp) _this_cpu_generic_read(pcp)
+# endif
+# ifndef this_cpu_read_2
+#  define this_cpu_read_2(pcp) _this_cpu_generic_read(pcp)
+# endif
+# ifndef this_cpu_read_4
+#  define this_cpu_read_4(pcp) _this_cpu_generic_read(pcp)
+# endif
+# ifndef this_cpu_read_8
+#  define this_cpu_read_8(pcp) _this_cpu_generic_read(pcp)
+# endif
+# define this_cpu_read(pcp)    __pcpu_size_call_return(this_cpu_read_, (pcp))
+#endif
+
+#define _this_cpu_generic_to_op(pcp, val, op)                          \
+do {                                                                   \
+       preempt_disable();                                              \
+       *__this_cpu_ptr(&pcp) op val;                                   \
+       preempt_enable();                                               \
+} while (0)
+
+#ifndef this_cpu_write
+# ifndef this_cpu_write_1
+#  define this_cpu_write_1(pcp, val)   _this_cpu_generic_to_op((pcp), (val), =)
+# endif
+# ifndef this_cpu_write_2
+#  define this_cpu_write_2(pcp, val)   _this_cpu_generic_to_op((pcp), (val), =)
+# endif
+# ifndef this_cpu_write_4
+#  define this_cpu_write_4(pcp, val)   _this_cpu_generic_to_op((pcp), (val), =)
+# endif
+# ifndef this_cpu_write_8
+#  define this_cpu_write_8(pcp, val)   _this_cpu_generic_to_op((pcp), (val), =)
+# endif
+# define this_cpu_write(pcp, val)      __pcpu_size_call(this_cpu_write_, (pcp), (val))
+#endif
+
+#ifndef this_cpu_add
+# ifndef this_cpu_add_1
+#  define this_cpu_add_1(pcp, val)     _this_cpu_generic_to_op((pcp), (val), +=)
+# endif
+# ifndef this_cpu_add_2
+#  define this_cpu_add_2(pcp, val)     _this_cpu_generic_to_op((pcp), (val), +=)
+# endif
+# ifndef this_cpu_add_4
+#  define this_cpu_add_4(pcp, val)     _this_cpu_generic_to_op((pcp), (val), +=)
+# endif
+# ifndef this_cpu_add_8
+#  define this_cpu_add_8(pcp, val)     _this_cpu_generic_to_op((pcp), (val), +=)
+# endif
+# define this_cpu_add(pcp, val)                __pcpu_size_call(this_cpu_add_, (pcp), (val))
+#endif
+
+#ifndef this_cpu_sub
+# define this_cpu_sub(pcp, val)                this_cpu_add((pcp), -(val))
+#endif
+
+#ifndef this_cpu_inc
+# define this_cpu_inc(pcp)             this_cpu_add((pcp), 1)
+#endif
+
+#ifndef this_cpu_dec
+# define this_cpu_dec(pcp)             this_cpu_sub((pcp), 1)
+#endif
+
+#ifndef this_cpu_and
+# ifndef this_cpu_and_1
+#  define this_cpu_and_1(pcp, val)     _this_cpu_generic_to_op((pcp), (val), &=)
+# endif
+# ifndef this_cpu_and_2
+#  define this_cpu_and_2(pcp, val)     _this_cpu_generic_to_op((pcp), (val), &=)
+# endif
+# ifndef this_cpu_and_4
+#  define this_cpu_and_4(pcp, val)     _this_cpu_generic_to_op((pcp), (val), &=)
+# endif
+# ifndef this_cpu_and_8
+#  define this_cpu_and_8(pcp, val)     _this_cpu_generic_to_op((pcp), (val), &=)
+# endif
+# define this_cpu_and(pcp, val)                __pcpu_size_call(this_cpu_and_, (pcp), (val))
+#endif
+
+#ifndef this_cpu_or
+# ifndef this_cpu_or_1
+#  define this_cpu_or_1(pcp, val)      _this_cpu_generic_to_op((pcp), (val), |=)
+# endif
+# ifndef this_cpu_or_2
+#  define this_cpu_or_2(pcp, val)      _this_cpu_generic_to_op((pcp), (val), |=)
+# endif
+# ifndef this_cpu_or_4
+#  define this_cpu_or_4(pcp, val)      _this_cpu_generic_to_op((pcp), (val), |=)
+# endif
+# ifndef this_cpu_or_8
+#  define this_cpu_or_8(pcp, val)      _this_cpu_generic_to_op((pcp), (val), |=)
+# endif
+# define this_cpu_or(pcp, val)         __pcpu_size_call(this_cpu_or_, (pcp), (val))
+#endif
+
+#ifndef this_cpu_xor
+# ifndef this_cpu_xor_1
+#  define this_cpu_xor_1(pcp, val)     _this_cpu_generic_to_op((pcp), (val), ^=)
+# endif
+# ifndef this_cpu_xor_2
+#  define this_cpu_xor_2(pcp, val)     _this_cpu_generic_to_op((pcp), (val), ^=)
+# endif
+# ifndef this_cpu_xor_4
+#  define this_cpu_xor_4(pcp, val)     _this_cpu_generic_to_op((pcp), (val), ^=)
+# endif
+# ifndef this_cpu_xor_8
+#  define this_cpu_xor_8(pcp, val)     _this_cpu_generic_to_op((pcp), (val), ^=)
+# endif
+# define this_cpu_xor(pcp, val)                __pcpu_size_call(this_cpu_or_, (pcp), (val))
+#endif
+
+/*
+ * Generic percpu operations that do not require preemption handling.
+ * Either we do not care about races or the caller has the
+ * responsibility of handling preemptions issues. Arch code can still
+ * override these instructions since the arch per cpu code may be more
+ * efficient and may actually get race freeness for free (that is the
+ * case for x86 for example).
+ *
+ * If there is no other protection through preempt disable and/or
+ * disabling interupts then one of these RMW operations can show unexpected
+ * behavior because the execution thread was rescheduled on another processor
+ * or an interrupt occurred and the same percpu variable was modified from
+ * the interrupt context.
+ */
+#ifndef __this_cpu_read
+# ifndef __this_cpu_read_1
+#  define __this_cpu_read_1(pcp)       (*__this_cpu_ptr(&(pcp)))
+# endif
+# ifndef __this_cpu_read_2
+#  define __this_cpu_read_2(pcp)       (*__this_cpu_ptr(&(pcp)))
+# endif
+# ifndef __this_cpu_read_4
+#  define __this_cpu_read_4(pcp)       (*__this_cpu_ptr(&(pcp)))
+# endif
+# ifndef __this_cpu_read_8
+#  define __this_cpu_read_8(pcp)       (*__this_cpu_ptr(&(pcp)))
+# endif
+# define __this_cpu_read(pcp)  __pcpu_size_call_return(__this_cpu_read_, (pcp))
+#endif
+
+#define __this_cpu_generic_to_op(pcp, val, op)                         \
+do {                                                                   \
+       *__this_cpu_ptr(&(pcp)) op val;                                 \
+} while (0)
+
+#ifndef __this_cpu_write
+# ifndef __this_cpu_write_1
+#  define __this_cpu_write_1(pcp, val) __this_cpu_generic_to_op((pcp), (val), =)
+# endif
+# ifndef __this_cpu_write_2
+#  define __this_cpu_write_2(pcp, val) __this_cpu_generic_to_op((pcp), (val), =)
+# endif
+# ifndef __this_cpu_write_4
+#  define __this_cpu_write_4(pcp, val) __this_cpu_generic_to_op((pcp), (val), =)
+# endif
+# ifndef __this_cpu_write_8
+#  define __this_cpu_write_8(pcp, val) __this_cpu_generic_to_op((pcp), (val), =)
+# endif
+# define __this_cpu_write(pcp, val)    __pcpu_size_call(__this_cpu_write_, (pcp), (val))
+#endif
+
+#ifndef __this_cpu_add
+# ifndef __this_cpu_add_1
+#  define __this_cpu_add_1(pcp, val)   __this_cpu_generic_to_op((pcp), (val), +=)
+# endif
+# ifndef __this_cpu_add_2
+#  define __this_cpu_add_2(pcp, val)   __this_cpu_generic_to_op((pcp), (val), +=)
+# endif
+# ifndef __this_cpu_add_4
+#  define __this_cpu_add_4(pcp, val)   __this_cpu_generic_to_op((pcp), (val), +=)
+# endif
+# ifndef __this_cpu_add_8
+#  define __this_cpu_add_8(pcp, val)   __this_cpu_generic_to_op((pcp), (val), +=)
+# endif
+# define __this_cpu_add(pcp, val)      __pcpu_size_call(__this_cpu_add_, (pcp), (val))
+#endif
+
+#ifndef __this_cpu_sub
+# define __this_cpu_sub(pcp, val)      __this_cpu_add((pcp), -(val))
+#endif
+
+#ifndef __this_cpu_inc
+# define __this_cpu_inc(pcp)           __this_cpu_add((pcp), 1)
+#endif
+
+#ifndef __this_cpu_dec
+# define __this_cpu_dec(pcp)           __this_cpu_sub((pcp), 1)
+#endif
+
+#ifndef __this_cpu_and
+# ifndef __this_cpu_and_1
+#  define __this_cpu_and_1(pcp, val)   __this_cpu_generic_to_op((pcp), (val), &=)
+# endif
+# ifndef __this_cpu_and_2
+#  define __this_cpu_and_2(pcp, val)   __this_cpu_generic_to_op((pcp), (val), &=)
+# endif
+# ifndef __this_cpu_and_4
+#  define __this_cpu_and_4(pcp, val)   __this_cpu_generic_to_op((pcp), (val), &=)
+# endif
+# ifndef __this_cpu_and_8
+#  define __this_cpu_and_8(pcp, val)   __this_cpu_generic_to_op((pcp), (val), &=)
+# endif
+# define __this_cpu_and(pcp, val)      __pcpu_size_call(__this_cpu_and_, (pcp), (val))
+#endif
+
+#ifndef __this_cpu_or
+# ifndef __this_cpu_or_1
+#  define __this_cpu_or_1(pcp, val)    __this_cpu_generic_to_op((pcp), (val), |=)
+# endif
+# ifndef __this_cpu_or_2
+#  define __this_cpu_or_2(pcp, val)    __this_cpu_generic_to_op((pcp), (val), |=)
+# endif
+# ifndef __this_cpu_or_4
+#  define __this_cpu_or_4(pcp, val)    __this_cpu_generic_to_op((pcp), (val), |=)
+# endif
+# ifndef __this_cpu_or_8
+#  define __this_cpu_or_8(pcp, val)    __this_cpu_generic_to_op((pcp), (val), |=)
+# endif
+# define __this_cpu_or(pcp, val)       __pcpu_size_call(__this_cpu_or_, (pcp), (val))
+#endif
+
+#ifndef __this_cpu_xor
+# ifndef __this_cpu_xor_1
+#  define __this_cpu_xor_1(pcp, val)   __this_cpu_generic_to_op((pcp), (val), ^=)
+# endif
+# ifndef __this_cpu_xor_2
+#  define __this_cpu_xor_2(pcp, val)   __this_cpu_generic_to_op((pcp), (val), ^=)
+# endif
+# ifndef __this_cpu_xor_4
+#  define __this_cpu_xor_4(pcp, val)   __this_cpu_generic_to_op((pcp), (val), ^=)
+# endif
+# ifndef __this_cpu_xor_8
+#  define __this_cpu_xor_8(pcp, val)   __this_cpu_generic_to_op((pcp), (val), ^=)
+# endif
+# define __this_cpu_xor(pcp, val)      __pcpu_size_call(__this_cpu_xor_, (pcp), (val))
+#endif
+
+/*
+ * IRQ safe versions of the per cpu RMW operations. Note that these operations
+ * are *not* safe against modification of the same variable from another
+ * processors (which one gets when using regular atomic operations)
+ . They are guaranteed to be atomic vs. local interrupts and
+ * preemption only.
+ */
+#define irqsafe_cpu_generic_to_op(pcp, val, op)                                \
+do {                                                                   \
+       unsigned long flags;                                            \
+       local_irq_save(flags);                                          \
+       *__this_cpu_ptr(&(pcp)) op val;                                 \
+       local_irq_restore(flags);                                       \
+} while (0)
+
+#ifndef irqsafe_cpu_add
+# ifndef irqsafe_cpu_add_1
+#  define irqsafe_cpu_add_1(pcp, val) irqsafe_cpu_generic_to_op((pcp), (val), +=)
+# endif
+# ifndef irqsafe_cpu_add_2
+#  define irqsafe_cpu_add_2(pcp, val) irqsafe_cpu_generic_to_op((pcp), (val), +=)
+# endif
+# ifndef irqsafe_cpu_add_4
+#  define irqsafe_cpu_add_4(pcp, val) irqsafe_cpu_generic_to_op((pcp), (val), +=)
+# endif
+# ifndef irqsafe_cpu_add_8
+#  define irqsafe_cpu_add_8(pcp, val) irqsafe_cpu_generic_to_op((pcp), (val), +=)
+# endif
+# define irqsafe_cpu_add(pcp, val) __pcpu_size_call(irqsafe_cpu_add_, (pcp), (val))
+#endif
+
+#ifndef irqsafe_cpu_sub
+# define irqsafe_cpu_sub(pcp, val)     irqsafe_cpu_add((pcp), -(val))
+#endif
+
+#ifndef irqsafe_cpu_inc
+# define irqsafe_cpu_inc(pcp)  irqsafe_cpu_add((pcp), 1)
+#endif
+
+#ifndef irqsafe_cpu_dec
+# define irqsafe_cpu_dec(pcp)  irqsafe_cpu_sub((pcp), 1)
+#endif
+
+#ifndef irqsafe_cpu_and
+# ifndef irqsafe_cpu_and_1
+#  define irqsafe_cpu_and_1(pcp, val) irqsafe_cpu_generic_to_op((pcp), (val), &=)
+# endif
+# ifndef irqsafe_cpu_and_2
+#  define irqsafe_cpu_and_2(pcp, val) irqsafe_cpu_generic_to_op((pcp), (val), &=)
+# endif
+# ifndef irqsafe_cpu_and_4
+#  define irqsafe_cpu_and_4(pcp, val) irqsafe_cpu_generic_to_op((pcp), (val), &=)
+# endif
+# ifndef irqsafe_cpu_and_8
+#  define irqsafe_cpu_and_8(pcp, val) irqsafe_cpu_generic_to_op((pcp), (val), &=)
+# endif
+# define irqsafe_cpu_and(pcp, val) __pcpu_size_call(irqsafe_cpu_and_, (val))
+#endif
+
+#ifndef irqsafe_cpu_or
+# ifndef irqsafe_cpu_or_1
+#  define irqsafe_cpu_or_1(pcp, val) irqsafe_cpu_generic_to_op((pcp), (val), |=)
+# endif
+# ifndef irqsafe_cpu_or_2
+#  define irqsafe_cpu_or_2(pcp, val) irqsafe_cpu_generic_to_op((pcp), (val), |=)
+# endif
+# ifndef irqsafe_cpu_or_4
+#  define irqsafe_cpu_or_4(pcp, val) irqsafe_cpu_generic_to_op((pcp), (val), |=)
+# endif
+# ifndef irqsafe_cpu_or_8
+#  define irqsafe_cpu_or_8(pcp, val) irqsafe_cpu_generic_to_op((pcp), (val), |=)
+# endif
+# define irqsafe_cpu_or(pcp, val) __pcpu_size_call(irqsafe_cpu_or_, (val))
+#endif
+
+#ifndef irqsafe_cpu_xor
+# ifndef irqsafe_cpu_xor_1
+#  define irqsafe_cpu_xor_1(pcp, val) irqsafe_cpu_generic_to_op((pcp), (val), ^=)
+# endif
+# ifndef irqsafe_cpu_xor_2
+#  define irqsafe_cpu_xor_2(pcp, val) irqsafe_cpu_generic_to_op((pcp), (val), ^=)
+# endif
+# ifndef irqsafe_cpu_xor_4
+#  define irqsafe_cpu_xor_4(pcp, val) irqsafe_cpu_generic_to_op((pcp), (val), ^=)
+# endif
+# ifndef irqsafe_cpu_xor_8
+#  define irqsafe_cpu_xor_8(pcp, val) irqsafe_cpu_generic_to_op((pcp), (val), ^=)
+# endif
+# define irqsafe_cpu_xor(pcp, val) __pcpu_size_call(irqsafe_cpu_xor_, (val))
+#endif
+
 #endif /* __LINUX_PERCPU_H */
index d92480f8285c76bec5b67fb5950fdc12f2d06c3c..1cbbd2c11aa921e59d52deaa65b5dc3853e72c17 100644 (file)
@@ -78,6 +78,25 @@ struct raid6_calls {
 /* Selected algorithm */
 extern struct raid6_calls raid6_call;
 
+/* Various routine sets */
+extern const struct raid6_calls raid6_intx1;
+extern const struct raid6_calls raid6_intx2;
+extern const struct raid6_calls raid6_intx4;
+extern const struct raid6_calls raid6_intx8;
+extern const struct raid6_calls raid6_intx16;
+extern const struct raid6_calls raid6_intx32;
+extern const struct raid6_calls raid6_mmxx1;
+extern const struct raid6_calls raid6_mmxx2;
+extern const struct raid6_calls raid6_sse1x1;
+extern const struct raid6_calls raid6_sse1x2;
+extern const struct raid6_calls raid6_sse2x1;
+extern const struct raid6_calls raid6_sse2x2;
+extern const struct raid6_calls raid6_sse2x4;
+extern const struct raid6_calls raid6_altivec1;
+extern const struct raid6_calls raid6_altivec2;
+extern const struct raid6_calls raid6_altivec4;
+extern const struct raid6_calls raid6_altivec8;
+
 /* Algorithm list */
 extern const struct raid6_calls * const raid6_algos[];
 int raid6_select_algo(void);
index 850d057500dece3f52497b2bed3aab51dd677852..ca6b2b31799197463220b53179b4a1cd41ead85e 100644 (file)
@@ -110,7 +110,7 @@ extern struct cache_sizes malloc_sizes[];
 void *kmem_cache_alloc(struct kmem_cache *, gfp_t);
 void *__kmalloc(size_t size, gfp_t flags);
 
-#ifdef CONFIG_KMEMTRACE
+#ifdef CONFIG_TRACING
 extern void *kmem_cache_alloc_notrace(struct kmem_cache *cachep, gfp_t flags);
 extern size_t slab_buffer_size(struct kmem_cache *cachep);
 #else
@@ -166,7 +166,7 @@ found:
 extern void *__kmalloc_node(size_t size, gfp_t flags, int node);
 extern void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node);
 
-#ifdef CONFIG_KMEMTRACE
+#ifdef CONFIG_TRACING
 extern void *kmem_cache_alloc_node_notrace(struct kmem_cache *cachep,
                                           gfp_t flags,
                                           int nodeid);
index 5ad70a60fd7473ee7f9a46a8355e847363b6c596..1e14beb23f9ba757c8db47e049261bbec0c9c6f3 100644 (file)
@@ -217,7 +217,7 @@ static __always_inline struct kmem_cache *kmalloc_slab(size_t size)
 void *kmem_cache_alloc(struct kmem_cache *, gfp_t);
 void *__kmalloc(size_t size, gfp_t flags);
 
-#ifdef CONFIG_KMEMTRACE
+#ifdef CONFIG_TRACING
 extern void *kmem_cache_alloc_notrace(struct kmem_cache *s, gfp_t gfpflags);
 #else
 static __always_inline void *
@@ -266,7 +266,7 @@ static __always_inline void *kmalloc(size_t size, gfp_t flags)
 void *__kmalloc_node(size_t size, gfp_t flags, int node);
 void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node);
 
-#ifdef CONFIG_KMEMTRACE
+#ifdef CONFIG_TRACING
 extern void *kmem_cache_alloc_node_notrace(struct kmem_cache *s,
                                           gfp_t gfpflags,
                                           int node);
diff --git a/include/linux/spi/mpc52xx_spi.h b/include/linux/spi/mpc52xx_spi.h
deleted file mode 100644 (file)
index d1004cf..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-
-#ifndef INCLUDE_MPC5200_SPI_H
-#define INCLUDE_MPC5200_SPI_H
-
-extern void mpc52xx_spi_set_premessage_hook(struct spi_master *master,
-                                           void (*hook)(struct spi_message *m,
-                                                        void *context),
-                                           void *hook_context);
-
-#endif
diff --git a/include/linux/spi/sh_msiof.h b/include/linux/spi/sh_msiof.h
new file mode 100644 (file)
index 0000000..2e8db3d
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __SPI_SH_MSIOF_H__
+#define __SPI_SH_MSIOF_H__
+
+struct sh_msiof_spi_info {
+       int tx_fifo_override;
+       int rx_fifo_override;
+       u16 num_chipselect;
+};
+
+#endif /* __SPI_SH_MSIOF_H__ */
diff --git a/include/linux/spi/xilinx_spi.h b/include/linux/spi/xilinx_spi.h
new file mode 100644 (file)
index 0000000..6f17278
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef __LINUX_SPI_XILINX_SPI_H
+#define __LINUX_SPI_XILINX_SPI_H
+
+/**
+ * struct xspi_platform_data - Platform data of the Xilinx SPI driver
+ * @num_chipselect:    Number of chip select by the IP.
+ * @little_endian:     If registers should be accessed little endian or not.
+ * @bits_per_word:     Number of bits per word.
+ * @devices:           Devices to add when the driver is probed.
+ * @num_devices:       Number of devices in the devices array.
+ */
+struct xspi_platform_data {
+       u16 num_chipselect;
+       bool little_endian;
+       u8 bits_per_word;
+       struct spi_board_info *devices;
+       u8 num_devices;
+};
+
+#endif /* __LINUX_SPI_XILINX_SPI_H */
index 401097781fc0601e5b7359ea15ec76ad2a3f5f03..1906782ec86bc6b668998e17bc3a68d6c244a334 100644 (file)
@@ -130,12 +130,14 @@ struct rpc_task_setup {
 #define RPC_TASK_DYNAMIC       0x0080          /* task was kmalloc'ed */
 #define RPC_TASK_KILLED                0x0100          /* task was killed */
 #define RPC_TASK_SOFT          0x0200          /* Use soft timeouts */
+#define RPC_TASK_SOFTCONN      0x0400          /* Fail if can't connect */
 
 #define RPC_IS_ASYNC(t)                ((t)->tk_flags & RPC_TASK_ASYNC)
 #define RPC_IS_SWAPPER(t)      ((t)->tk_flags & RPC_TASK_SWAPPER)
 #define RPC_DO_ROOTOVERRIDE(t) ((t)->tk_flags & RPC_TASK_ROOTCREDS)
 #define RPC_ASSASSINATED(t)    ((t)->tk_flags & RPC_TASK_KILLED)
 #define RPC_IS_SOFT(t)         ((t)->tk_flags & RPC_TASK_SOFT)
+#define RPC_IS_SOFTCONN(t)     ((t)->tk_flags & RPC_TASK_SOFTCONN)
 
 #define RPC_TASK_RUNNING       0
 #define RPC_TASK_QUEUED                1
index 2d0f222388a8e9f2dfb3f8bec716eff2999d78f2..d85889710f9b6a4fbf5040fd941c1cfca7847428 100644 (file)
@@ -76,24 +76,22 @@ DECLARE_PER_CPU(struct vm_event_state, vm_event_states);
 
 static inline void __count_vm_event(enum vm_event_item item)
 {
-       __get_cpu_var(vm_event_states).event[item]++;
+       __this_cpu_inc(per_cpu_var(vm_event_states).event[item]);
 }
 
 static inline void count_vm_event(enum vm_event_item item)
 {
-       get_cpu_var(vm_event_states).event[item]++;
-       put_cpu();
+       this_cpu_inc(per_cpu_var(vm_event_states).event[item]);
 }
 
 static inline void __count_vm_events(enum vm_event_item item, long delta)
 {
-       __get_cpu_var(vm_event_states).event[item] += delta;
+       __this_cpu_add(per_cpu_var(vm_event_states).event[item], delta);
 }
 
 static inline void count_vm_events(enum vm_event_item item, long delta)
 {
-       get_cpu_var(vm_event_states).event[item] += delta;
-       put_cpu();
+       this_cpu_add(per_cpu_var(vm_event_states).event[item], delta);
 }
 
 extern void all_vm_events(unsigned long *);
index 0302f31a2fb7e53956f089efac74848fbd15466d..b0173202cad96f3a8aa55df85d16b2d11a62b608 100644 (file)
@@ -88,12 +88,7 @@ struct neigh_statistics {
        unsigned long unres_discards;   /* number of unresolved drops */
 };
 
-#define NEIGH_CACHE_STAT_INC(tbl, field)                               \
-       do {                                                            \
-               preempt_disable();                                      \
-               (per_cpu_ptr((tbl)->stats, smp_processor_id())->field)++; \
-               preempt_enable();                                       \
-       } while (0)
+#define NEIGH_CACHE_STAT_INC(tbl, field) this_cpu_inc((tbl)->stats->field)
 
 struct neighbour {
        struct neighbour        *next;
index 5cf7270e3ffc3e94c6d80bd79168056e9c1e539f..a0904adfb8f7aba343152a5af47aa7e818c3b39d 100644 (file)
@@ -293,11 +293,11 @@ extern unsigned int nf_conntrack_htable_size;
 extern unsigned int nf_conntrack_max;
 
 #define NF_CT_STAT_INC(net, count)     \
-       (per_cpu_ptr((net)->ct.stat, raw_smp_processor_id())->count++)
+       __this_cpu_inc((net)->ct.stat->count)
 #define NF_CT_STAT_INC_ATOMIC(net, count)              \
 do {                                                   \
        local_bh_disable();                             \
-       per_cpu_ptr((net)->ct.stat, raw_smp_processor_id())->count++;   \
+       __this_cpu_inc((net)->ct.stat->count);          \
        local_bh_enable();                              \
 } while (0)
 
index 8c842e06bec86ad77cbe2f612d1a29d09bb3b421..f0d756f2ac99773f573613d145752b2984dddd13 100644 (file)
@@ -136,45 +136,31 @@ struct linux_xfrm_mib {
 #define SNMP_STAT_BHPTR(name)  (name[0])
 #define SNMP_STAT_USRPTR(name) (name[1])
 
-#define SNMP_INC_STATS_BH(mib, field)  \
-       (per_cpu_ptr(mib[0], raw_smp_processor_id())->mibs[field]++)
-#define SNMP_INC_STATS_USER(mib, field) \
-       do { \
-               per_cpu_ptr(mib[1], get_cpu())->mibs[field]++; \
-               put_cpu(); \
-       } while (0)
-#define SNMP_INC_STATS(mib, field)     \
-       do { \
-               per_cpu_ptr(mib[!in_softirq()], get_cpu())->mibs[field]++; \
-               put_cpu(); \
-       } while (0)
-#define SNMP_DEC_STATS(mib, field)     \
-       do { \
-               per_cpu_ptr(mib[!in_softirq()], get_cpu())->mibs[field]--; \
-               put_cpu(); \
-       } while (0)
-#define SNMP_ADD_STATS(mib, field, addend)     \
-       do { \
-               per_cpu_ptr(mib[!in_softirq()], get_cpu())->mibs[field] += addend; \
-               put_cpu(); \
-       } while (0)
-#define SNMP_ADD_STATS_BH(mib, field, addend)  \
-       (per_cpu_ptr(mib[0], raw_smp_processor_id())->mibs[field] += addend)
-#define SNMP_ADD_STATS_USER(mib, field, addend)        \
-       do { \
-               per_cpu_ptr(mib[1], get_cpu())->mibs[field] += addend; \
-               put_cpu(); \
-       } while (0)
+#define SNMP_INC_STATS_BH(mib, field)  \
+                       __this_cpu_inc(mib[0]->mibs[field])
+#define SNMP_INC_STATS_USER(mib, field)        \
+                       this_cpu_inc(mib[1]->mibs[field])
+#define SNMP_INC_STATS(mib, field)     \
+                       this_cpu_inc(mib[!in_softirq()]->mibs[field])
+#define SNMP_DEC_STATS(mib, field)     \
+                       this_cpu_dec(mib[!in_softirq()]->mibs[field])
+#define SNMP_ADD_STATS_BH(mib, field, addend)  \
+                       __this_cpu_add(mib[0]->mibs[field], addend)
+#define SNMP_ADD_STATS_USER(mib, field, addend)        \
+                       this_cpu_add(mib[1]->mibs[field], addend)
 #define SNMP_UPD_PO_STATS(mib, basefield, addend)      \
        do { \
-               __typeof__(mib[0]) ptr = per_cpu_ptr(mib[!in_softirq()], get_cpu());\
+               __typeof__(mib[0]) ptr; \
+               preempt_disable(); \
+               ptr = this_cpu_ptr((mib)[!in_softirq()]); \
                ptr->mibs[basefield##PKTS]++; \
                ptr->mibs[basefield##OCTETS] += addend;\
-               put_cpu(); \
+               preempt_enable(); \
        } while (0)
 #define SNMP_UPD_PO_STATS_BH(mib, basefield, addend)   \
        do { \
-               __typeof__(mib[0]) ptr = per_cpu_ptr(mib[!in_softirq()], raw_smp_processor_id());\
+               __typeof__(mib[0]) ptr = \
+                       __this_cpu_ptr((mib)[!in_softirq()]); \
                ptr->mibs[basefield##PKTS]++; \
                ptr->mibs[basefield##OCTETS] += addend;\
        } while (0)
index afc2bfb9e917bcb63ebda29847b00e848111d8be..75fa3530345ba362f7460d18e7749ed08f3654c1 100644 (file)
@@ -126,8 +126,8 @@ typedef struct irq_req_t {
 #define IRQ_TYPE_TIME                  0x01
 #define IRQ_TYPE_DYNAMIC_SHARING       0x02
 #define IRQ_FORCED_PULSE               0x04
-#define IRQ_FIRST_SHARED               0x08
-//#define IRQ_HANDLE_PRESENT           0x10
+#define IRQ_FIRST_SHARED               0x08 /* unused */
+#define IRQ_HANDLE_PRESENT             0x10 /* unused */
 #define IRQ_PULSE_ALLOCATED            0x100
 
 /* Bits in IRQInfo1 field */
index d403c12f797820928bb040ff166e9469c532ba81..ee148573c11435750dc26e12d135b03a584d3e08 100644 (file)
@@ -82,7 +82,7 @@ struct pcmcia_device {
        /* the hardware "function" device; certain subdevices can
         * share one hardware "function" device. */
        u8                      func;
-       struct config_t*        function_config;
+       struct config_t         *function_config;
 
        struct list_head        socket_device_list;
 
@@ -121,14 +121,14 @@ struct pcmcia_device {
        u16                     manf_id;
        u16                     card_id;
 
-       char *                  prod_id[4];
+       char                    *prod_id[4];
 
        u64                     dma_mask;
        struct device           dev;
 
 #ifdef CONFIG_PCMCIA_IOCTL
        /* device driver wanted by cardmgr */
-       struct pcmcia_driver *  cardmgr;
+       struct pcmcia_driver    *cardmgr;
 #endif
 
        /* data private to drivers */
index 8d19b9401a5bba76d7f7614728e6d7496c78c998..0fa06e5d5376463c8d8f8f33e990daf9801b3a72 100644 (file)
@@ -15,8 +15,8 @@
 #ifndef _LINUX_MEM_OP_H
 #define _LINUX_MEM_OP_H
 
+#include <linux/io.h>
 #include <asm/uaccess.h>
-#include <asm/io.h>
 
 /*
    If UNSAFE_MEMCPY is defined, we use the (optimized) system routines
index 7c23be706f128bbc02365e868687aa3dbcc73047..cbfba885eb85b8376dcc60bb0fb4608944b35015 100644 (file)
@@ -154,7 +154,7 @@ struct pcmcia_socket {
        struct list_head                socket_list;
        struct completion               socket_released;
 
-       /* deprecated */
+       /* deprecated */
        unsigned int                    sock;           /* socket number */
 
 
@@ -164,7 +164,7 @@ struct pcmcia_socket {
        u_int                           map_size;
        u_int                           io_offset;
        u_int                           pci_irq;
-       struct pci_dev *                cb_dev;
+       struct pci_dev                  *cb_dev;
 
 
        /* socket setup is done so resources should be able to be allocated.
@@ -179,9 +179,9 @@ struct pcmcia_socket {
        u8                              reserved:5;
 
        /* socket operations */
-       struct pccard_operations *      ops;
-       struct pccard_resource_ops *    resource_ops;
-       void *                          resource_data;
+       struct pccard_operations        *ops;
+       struct pccard_resource_ops      *resource_ops;
+       void                            *resource_data;
 
        /* Zoom video behaviour is so chip specific its not worth adding
           this to _ops */
@@ -245,7 +245,7 @@ struct pcmcia_socket {
 
        /* cardbus (32-bit) */
 #ifdef CONFIG_CARDBUS
-       struct resource *               cb_cis_res;
+       struct resource                 *cb_cis_res;
        void __iomem                    *cb_cis_virt;
 #endif /* CONFIG_CARDBUS */
 
index 4f8df01dbe51ad05e1957fa7e1eecd20af7e0765..429540c70d3f497ae7fc58998b0f248817a2cbf9 100644 (file)
@@ -140,7 +140,8 @@ static inline struct lock_class *hlock_class(struct held_lock *hlock)
 }
 
 #ifdef CONFIG_LOCK_STAT
-static DEFINE_PER_CPU(struct lock_class_stats[MAX_LOCKDEP_KEYS], lock_stats);
+static DEFINE_PER_CPU(struct lock_class_stats[MAX_LOCKDEP_KEYS],
+                     cpu_lock_stats);
 
 static inline u64 lockstat_clock(void)
 {
@@ -198,7 +199,7 @@ struct lock_class_stats lock_stats(struct lock_class *class)
        memset(&stats, 0, sizeof(struct lock_class_stats));
        for_each_possible_cpu(cpu) {
                struct lock_class_stats *pcs =
-                       &per_cpu(lock_stats, cpu)[class - lock_classes];
+                       &per_cpu(cpu_lock_stats, cpu)[class - lock_classes];
 
                for (i = 0; i < ARRAY_SIZE(stats.contention_point); i++)
                        stats.contention_point[i] += pcs->contention_point[i];
@@ -225,7 +226,7 @@ void clear_lock_stats(struct lock_class *class)
 
        for_each_possible_cpu(cpu) {
                struct lock_class_stats *cpu_stats =
-                       &per_cpu(lock_stats, cpu)[class - lock_classes];
+                       &per_cpu(cpu_lock_stats, cpu)[class - lock_classes];
 
                memset(cpu_stats, 0, sizeof(struct lock_class_stats));
        }
@@ -235,12 +236,12 @@ void clear_lock_stats(struct lock_class *class)
 
 static struct lock_class_stats *get_lock_stats(struct lock_class *class)
 {
-       return &get_cpu_var(lock_stats)[class - lock_classes];
+       return &get_cpu_var(cpu_lock_stats)[class - lock_classes];
 }
 
 static void put_lock_stats(struct lock_class_stats *stats)
 {
-       put_cpu_var(lock_stats);
+       put_cpu_var(cpu_lock_stats);
 }
 
 static void lock_release_holdtime(struct held_lock *hlock)
index 5842a71cf0527163c960cc8c41d549a5033e3443..12afc5a3ddd3a73972604050695ff4ab4ef708f6 100644 (file)
@@ -370,8 +370,6 @@ EXPORT_SYMBOL_GPL(find_module);
 
 #ifdef CONFIG_SMP
 
-#ifndef CONFIG_HAVE_LEGACY_PER_CPU_AREA
-
 static void *percpu_modalloc(unsigned long size, unsigned long align,
                             const char *name)
 {
@@ -395,154 +393,6 @@ static void percpu_modfree(void *freeme)
        free_percpu(freeme);
 }
 
-#else /* ... CONFIG_HAVE_LEGACY_PER_CPU_AREA */
-
-/* Number of blocks used and allocated. */
-static unsigned int pcpu_num_used, pcpu_num_allocated;
-/* Size of each block.  -ve means used. */
-static int *pcpu_size;
-
-static int split_block(unsigned int i, unsigned short size)
-{
-       /* Reallocation required? */
-       if (pcpu_num_used + 1 > pcpu_num_allocated) {
-               int *new;
-
-               new = krealloc(pcpu_size, sizeof(new[0])*pcpu_num_allocated*2,
-                              GFP_KERNEL);
-               if (!new)
-                       return 0;
-
-               pcpu_num_allocated *= 2;
-               pcpu_size = new;
-       }
-
-       /* Insert a new subblock */
-       memmove(&pcpu_size[i+1], &pcpu_size[i],
-               sizeof(pcpu_size[0]) * (pcpu_num_used - i));
-       pcpu_num_used++;
-
-       pcpu_size[i+1] -= size;
-       pcpu_size[i] = size;
-       return 1;
-}
-
-static inline unsigned int block_size(int val)
-{
-       if (val < 0)
-               return -val;
-       return val;
-}
-
-static void *percpu_modalloc(unsigned long size, unsigned long align,
-                            const char *name)
-{
-       unsigned long extra;
-       unsigned int i;
-       void *ptr;
-       int cpu;
-
-       if (align > PAGE_SIZE) {
-               printk(KERN_WARNING "%s: per-cpu alignment %li > %li\n",
-                      name, align, PAGE_SIZE);
-               align = PAGE_SIZE;
-       }
-
-       ptr = __per_cpu_start;
-       for (i = 0; i < pcpu_num_used; ptr += block_size(pcpu_size[i]), i++) {
-               /* Extra for alignment requirement. */
-               extra = ALIGN((unsigned long)ptr, align) - (unsigned long)ptr;
-               BUG_ON(i == 0 && extra != 0);
-
-               if (pcpu_size[i] < 0 || pcpu_size[i] < extra + size)
-                       continue;
-
-               /* Transfer extra to previous block. */
-               if (pcpu_size[i-1] < 0)
-                       pcpu_size[i-1] -= extra;
-               else
-                       pcpu_size[i-1] += extra;
-               pcpu_size[i] -= extra;
-               ptr += extra;
-
-               /* Split block if warranted */
-               if (pcpu_size[i] - size > sizeof(unsigned long))
-                       if (!split_block(i, size))
-                               return NULL;
-
-               /* add the per-cpu scanning areas */
-               for_each_possible_cpu(cpu)
-                       kmemleak_alloc(ptr + per_cpu_offset(cpu), size, 0,
-                                      GFP_KERNEL);
-
-               /* Mark allocated */
-               pcpu_size[i] = -pcpu_size[i];
-               return ptr;
-       }
-
-       printk(KERN_WARNING "Could not allocate %lu bytes percpu data\n",
-              size);
-       return NULL;
-}
-
-static void percpu_modfree(void *freeme)
-{
-       unsigned int i;
-       void *ptr = __per_cpu_start + block_size(pcpu_size[0]);
-       int cpu;
-
-       /* First entry is core kernel percpu data. */
-       for (i = 1; i < pcpu_num_used; ptr += block_size(pcpu_size[i]), i++) {
-               if (ptr == freeme) {
-                       pcpu_size[i] = -pcpu_size[i];
-                       goto free;
-               }
-       }
-       BUG();
-
- free:
-       /* remove the per-cpu scanning areas */
-       for_each_possible_cpu(cpu)
-               kmemleak_free(freeme + per_cpu_offset(cpu));
-
-       /* Merge with previous? */
-       if (pcpu_size[i-1] >= 0) {
-               pcpu_size[i-1] += pcpu_size[i];
-               pcpu_num_used--;
-               memmove(&pcpu_size[i], &pcpu_size[i+1],
-                       (pcpu_num_used - i) * sizeof(pcpu_size[0]));
-               i--;
-       }
-       /* Merge with next? */
-       if (i+1 < pcpu_num_used && pcpu_size[i+1] >= 0) {
-               pcpu_size[i] += pcpu_size[i+1];
-               pcpu_num_used--;
-               memmove(&pcpu_size[i+1], &pcpu_size[i+2],
-                       (pcpu_num_used - (i+1)) * sizeof(pcpu_size[0]));
-       }
-}
-
-static int percpu_modinit(void)
-{
-       pcpu_num_used = 2;
-       pcpu_num_allocated = 2;
-       pcpu_size = kmalloc(sizeof(pcpu_size[0]) * pcpu_num_allocated,
-                           GFP_KERNEL);
-       /* Static in-kernel percpu data (used). */
-       pcpu_size[0] = -(__per_cpu_end-__per_cpu_start);
-       /* Free room. */
-       pcpu_size[1] = PERCPU_ENOUGH_ROOM + pcpu_size[0];
-       if (pcpu_size[1] < 0) {
-               printk(KERN_ERR "No per-cpu room for modules.\n");
-               pcpu_num_used = 1;
-       }
-
-       return 0;
-}
-__initcall(percpu_modinit);
-
-#endif /* CONFIG_HAVE_LEGACY_PER_CPU_AREA */
-
 static unsigned int find_pcpusec(Elf_Ehdr *hdr,
                                 Elf_Shdr *sechdrs,
                                 const char *secstrings)
index a621a67ef4e3bd5e4aa97522cdff8b443db15e32..9bb52177af02a3e20aa347e3b65c0a236caa1922 100644 (file)
@@ -763,13 +763,13 @@ static void rcu_torture_timer(unsigned long unused)
                /* Should not happen, but... */
                pipe_count = RCU_TORTURE_PIPE_LEN;
        }
-       ++__get_cpu_var(rcu_torture_count)[pipe_count];
+       __this_cpu_inc(per_cpu_var(rcu_torture_count)[pipe_count]);
        completed = cur_ops->completed() - completed;
        if (completed > RCU_TORTURE_PIPE_LEN) {
                /* Should not happen, but... */
                completed = RCU_TORTURE_PIPE_LEN;
        }
-       ++__get_cpu_var(rcu_torture_batch)[completed];
+       __this_cpu_inc(per_cpu_var(rcu_torture_batch)[completed]);
        preempt_enable();
        cur_ops->readunlock(idx);
 }
@@ -818,13 +818,13 @@ rcu_torture_reader(void *arg)
                        /* Should not happen, but... */
                        pipe_count = RCU_TORTURE_PIPE_LEN;
                }
-               ++__get_cpu_var(rcu_torture_count)[pipe_count];
+               __this_cpu_inc(per_cpu_var(rcu_torture_count)[pipe_count]);
                completed = cur_ops->completed() - completed;
                if (completed > RCU_TORTURE_PIPE_LEN) {
                        /* Should not happen, but... */
                        completed = RCU_TORTURE_PIPE_LEN;
                }
-               ++__get_cpu_var(rcu_torture_batch)[completed];
+               __this_cpu_inc(per_cpu_var(rcu_torture_batch)[completed]);
                preempt_enable();
                cur_ops->readunlock(idx);
                schedule();
index ff39cadf621e91834dcdc9116d123f8912eab225..fd05861b2111005a5a88b386d7d77ee036f5e160 100644 (file)
@@ -298,7 +298,7 @@ static DEFINE_PER_CPU_SHARED_ALIGNED(struct cfs_rq, init_tg_cfs_rq);
 
 #ifdef CONFIG_RT_GROUP_SCHED
 static DEFINE_PER_CPU(struct sched_rt_entity, init_sched_rt_entity);
-static DEFINE_PER_CPU_SHARED_ALIGNED(struct rt_rq, init_rt_rq);
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct rt_rq, init_rt_rq_var);
 #endif /* CONFIG_RT_GROUP_SCHED */
 #else /* !CONFIG_USER_SCHED */
 #define root_task_group init_task_group
@@ -8286,14 +8286,14 @@ enum s_alloc {
  */
 #ifdef CONFIG_SCHED_SMT
 static DEFINE_PER_CPU(struct static_sched_domain, cpu_domains);
-static DEFINE_PER_CPU(struct static_sched_group, sched_group_cpus);
+static DEFINE_PER_CPU(struct static_sched_group, sched_groups);
 
 static int
 cpu_to_cpu_group(int cpu, const struct cpumask *cpu_map,
                 struct sched_group **sg, struct cpumask *unused)
 {
        if (sg)
-               *sg = &per_cpu(sched_group_cpus, cpu).sg;
+               *sg = &per_cpu(sched_groups, cpu).sg;
        return cpu;
 }
 #endif /* CONFIG_SCHED_SMT */
@@ -9583,7 +9583,7 @@ void __init sched_init(void)
 #elif defined CONFIG_USER_SCHED
                init_tg_rt_entry(&root_task_group, &rq->rt, NULL, i, 0, NULL);
                init_tg_rt_entry(&init_task_group,
-                               &per_cpu(init_rt_rq, i),
+                               &per_cpu(init_rt_rq_var, i),
                                &per_cpu(init_sched_rt_entity, i), i, 1,
                                root_task_group.rt_se[i]);
 #endif
index 21939d9e830e22b040f15e5562c97b0a8b8a9e47..a09502e2ef758721917ab537e345da0036197628 100644 (file)
@@ -697,7 +697,7 @@ void __init softirq_init(void)
        open_softirq(HI_SOFTIRQ, tasklet_hi_action);
 }
 
-static int ksoftirqd(void * __bind_cpu)
+static int run_ksoftirqd(void * __bind_cpu)
 {
        set_current_state(TASK_INTERRUPTIBLE);
 
@@ -810,7 +810,7 @@ static int __cpuinit cpu_callback(struct notifier_block *nfb,
        switch (action) {
        case CPU_UP_PREPARE:
        case CPU_UP_PREPARE_FROZEN:
-               p = kthread_create(ksoftirqd, hcpu, "ksoftirqd/%d", hotcpu);
+               p = kthread_create(run_ksoftirqd, hcpu, "ksoftirqd/%d", hotcpu);
                if (IS_ERR(p)) {
                        printk("ksoftirqd for %i failed\n", hotcpu);
                        return NOTIFY_BAD;
index 81324d12eb35a5db7fae8a0ae3d18c76ca38ce67..d22579087e27a5bdb04e3962b117432c29497b33 100644 (file)
@@ -22,9 +22,9 @@
 
 static DEFINE_SPINLOCK(print_lock);
 
-static DEFINE_PER_CPU(unsigned long, touch_timestamp);
-static DEFINE_PER_CPU(unsigned long, print_timestamp);
-static DEFINE_PER_CPU(struct task_struct *, watchdog_task);
+static DEFINE_PER_CPU(unsigned long, softlockup_touch_ts); /* touch timestamp */
+static DEFINE_PER_CPU(unsigned long, softlockup_print_ts); /* print timestamp */
+static DEFINE_PER_CPU(struct task_struct *, softlockup_watchdog);
 
 static int __read_mostly did_panic;
 int __read_mostly softlockup_thresh = 60;
@@ -70,12 +70,12 @@ static void __touch_softlockup_watchdog(void)
 {
        int this_cpu = raw_smp_processor_id();
 
-       __raw_get_cpu_var(touch_timestamp) = get_timestamp(this_cpu);
+       __raw_get_cpu_var(softlockup_touch_ts) = get_timestamp(this_cpu);
 }
 
 void touch_softlockup_watchdog(void)
 {
-       __raw_get_cpu_var(touch_timestamp) = 0;
+       __raw_get_cpu_var(softlockup_touch_ts) = 0;
 }
 EXPORT_SYMBOL(touch_softlockup_watchdog);
 
@@ -85,7 +85,7 @@ void touch_all_softlockup_watchdogs(void)
 
        /* Cause each CPU to re-update its timestamp rather than complain */
        for_each_online_cpu(cpu)
-               per_cpu(touch_timestamp, cpu) = 0;
+               per_cpu(softlockup_touch_ts, cpu) = 0;
 }
 EXPORT_SYMBOL(touch_all_softlockup_watchdogs);
 
@@ -104,28 +104,28 @@ int proc_dosoftlockup_thresh(struct ctl_table *table, int write,
 void softlockup_tick(void)
 {
        int this_cpu = smp_processor_id();
-       unsigned long touch_timestamp = per_cpu(touch_timestamp, this_cpu);
-       unsigned long print_timestamp;
+       unsigned long touch_ts = per_cpu(softlockup_touch_ts, this_cpu);
+       unsigned long print_ts;
        struct pt_regs *regs = get_irq_regs();
        unsigned long now;
 
        /* Is detection switched off? */
-       if (!per_cpu(watchdog_task, this_cpu) || softlockup_thresh <= 0) {
+       if (!per_cpu(softlockup_watchdog, this_cpu) || softlockup_thresh <= 0) {
                /* Be sure we don't false trigger if switched back on */
-               if (touch_timestamp)
-                       per_cpu(touch_timestamp, this_cpu) = 0;
+               if (touch_ts)
+                       per_cpu(softlockup_touch_ts, this_cpu) = 0;
                return;
        }
 
-       if (touch_timestamp == 0) {
+       if (touch_ts == 0) {
                __touch_softlockup_watchdog();
                return;
        }
 
-       print_timestamp = per_cpu(print_timestamp, this_cpu);
+       print_ts = per_cpu(softlockup_print_ts, this_cpu);
 
        /* report at most once a second */
-       if (print_timestamp == touch_timestamp || did_panic)
+       if (print_ts == touch_ts || did_panic)
                return;
 
        /* do not print during early bootup: */
@@ -140,18 +140,18 @@ void softlockup_tick(void)
         * Wake up the high-prio watchdog task twice per
         * threshold timespan.
         */
-       if (now > touch_timestamp + softlockup_thresh/2)
-               wake_up_process(per_cpu(watchdog_task, this_cpu));
+       if (now > touch_ts + softlockup_thresh/2)
+               wake_up_process(per_cpu(softlockup_watchdog, this_cpu));
 
        /* Warn about unreasonable delays: */
-       if (now <= (touch_timestamp + softlockup_thresh))
+       if (now <= (touch_ts + softlockup_thresh))
                return;
 
-       per_cpu(print_timestamp, this_cpu) = touch_timestamp;
+       per_cpu(softlockup_print_ts, this_cpu) = touch_ts;
 
        spin_lock(&print_lock);
        printk(KERN_ERR "BUG: soft lockup - CPU#%d stuck for %lus! [%s:%d]\n",
-                       this_cpu, now - touch_timestamp,
+                       this_cpu, now - touch_ts,
                        current->comm, task_pid_nr(current));
        print_modules();
        print_irqtrace_events(current);
@@ -209,32 +209,32 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
        switch (action) {
        case CPU_UP_PREPARE:
        case CPU_UP_PREPARE_FROZEN:
-               BUG_ON(per_cpu(watchdog_task, hotcpu));
+               BUG_ON(per_cpu(softlockup_watchdog, hotcpu));
                p = kthread_create(watchdog, hcpu, "watchdog/%d", hotcpu);
                if (IS_ERR(p)) {
                        printk(KERN_ERR "watchdog for %i failed\n", hotcpu);
                        return NOTIFY_BAD;
                }
-               per_cpu(touch_timestamp, hotcpu) = 0;
-               per_cpu(watchdog_task, hotcpu) = p;
+               per_cpu(softlockup_touch_ts, hotcpu) = 0;
+               per_cpu(softlockup_watchdog, hotcpu) = p;
                kthread_bind(p, hotcpu);
                break;
        case CPU_ONLINE:
        case CPU_ONLINE_FROZEN:
-               wake_up_process(per_cpu(watchdog_task, hotcpu));
+               wake_up_process(per_cpu(softlockup_watchdog, hotcpu));
                break;
 #ifdef CONFIG_HOTPLUG_CPU
        case CPU_UP_CANCELED:
        case CPU_UP_CANCELED_FROZEN:
-               if (!per_cpu(watchdog_task, hotcpu))
+               if (!per_cpu(softlockup_watchdog, hotcpu))
                        break;
                /* Unbind so it can run.  Fall thru. */
-               kthread_bind(per_cpu(watchdog_task, hotcpu),
+               kthread_bind(per_cpu(softlockup_watchdog, hotcpu),
                             cpumask_any(cpu_online_mask));
        case CPU_DEAD:
        case CPU_DEAD_FROZEN:
-               p = per_cpu(watchdog_task, hotcpu);
-               per_cpu(watchdog_task, hotcpu) = NULL;
+               p = per_cpu(softlockup_watchdog, hotcpu);
+               per_cpu(softlockup_watchdog, hotcpu) = NULL;
                kthread_stop(p);
                break;
 #endif /* CONFIG_HOTPLUG_CPU */
index ee5681f8d7ecd2f1429d5455ea2839f12921b42f..63b117e9eba13fb430372601bdc36ff7d3ef42a2 100644 (file)
@@ -86,7 +86,7 @@ static DEFINE_SPINLOCK(table_lock);
 /*
  * Per-CPU lookup locks for fast hash lookup:
  */
-static DEFINE_PER_CPU(spinlock_t, lookup_lock);
+static DEFINE_PER_CPU(spinlock_t, tstats_lookup_lock);
 
 /*
  * Mutex to serialize state changes with show-stats activities:
@@ -245,7 +245,7 @@ void timer_stats_update_stats(void *timer, pid_t pid, void *startf,
        if (likely(!timer_stats_active))
                return;
 
-       lock = &per_cpu(lookup_lock, raw_smp_processor_id());
+       lock = &per_cpu(tstats_lookup_lock, raw_smp_processor_id());
 
        input.timer = timer;
        input.start_func = startf;
@@ -348,9 +348,10 @@ static void sync_access(void)
        int cpu;
 
        for_each_online_cpu(cpu) {
-               spin_lock_irqsave(&per_cpu(lookup_lock, cpu), flags);
+               spinlock_t *lock = &per_cpu(tstats_lookup_lock, cpu);
+               spin_lock_irqsave(lock, flags);
                /* nothing */
-               spin_unlock_irqrestore(&per_cpu(lookup_lock, cpu), flags);
+               spin_unlock_irqrestore(lock, flags);
        }
 }
 
@@ -408,7 +409,7 @@ void __init init_timer_stats(void)
        int cpu;
 
        for_each_possible_cpu(cpu)
-               spin_lock_init(&per_cpu(lookup_lock, cpu));
+               spin_lock_init(&per_cpu(tstats_lookup_lock, cpu));
 }
 
 static int __init init_tstats_procfs(void)
index 88bd9ae2a9ed9b71b881c665f7cdb4eb722cf309..c82dfd92fdfd8d663b6146ea6a584d42ea715508 100644 (file)
@@ -86,17 +86,17 @@ static int dummy_set_flag(u32 old_flags, u32 bit, int set)
  */
 static int tracing_disabled = 1;
 
-DEFINE_PER_CPU(local_t, ftrace_cpu_disabled);
+DEFINE_PER_CPU(int, ftrace_cpu_disabled);
 
 static inline void ftrace_disable_cpu(void)
 {
        preempt_disable();
-       local_inc(&__get_cpu_var(ftrace_cpu_disabled));
+       __this_cpu_inc(per_cpu_var(ftrace_cpu_disabled));
 }
 
 static inline void ftrace_enable_cpu(void)
 {
-       local_dec(&__get_cpu_var(ftrace_cpu_disabled));
+       __this_cpu_dec(per_cpu_var(ftrace_cpu_disabled));
        preempt_enable();
 }
 
@@ -203,7 +203,7 @@ cycle_t ftrace_now(int cpu)
  */
 static struct trace_array      max_tr;
 
-static DEFINE_PER_CPU(struct trace_array_cpu, max_data);
+static DEFINE_PER_CPU(struct trace_array_cpu, max_tr_data);
 
 /* tracer_enabled is used to toggle activation of a tracer */
 static int                     tracer_enabled = 1;
@@ -1085,7 +1085,7 @@ trace_function(struct trace_array *tr,
        struct ftrace_entry *entry;
 
        /* If we are reading the ring buffer, don't trace */
-       if (unlikely(local_read(&__get_cpu_var(ftrace_cpu_disabled))))
+       if (unlikely(__this_cpu_read(per_cpu_var(ftrace_cpu_disabled))))
                return;
 
        event = trace_buffer_lock_reserve(buffer, TRACE_FN, sizeof(*entry),
@@ -4454,7 +4454,7 @@ __init static int tracer_alloc_buffers(void)
        /* Allocate the first page for all buffers */
        for_each_tracing_cpu(i) {
                global_trace.data[i] = &per_cpu(global_trace_cpu, i);
-               max_tr.data[i] = &per_cpu(max_data, i);
+               max_tr.data[i] = &per_cpu(max_tr_data, i);
        }
 
        trace_init_cmdlines();
index 7fa33cab69629299a9d4470fbf13db81d20e3c94..a52bed2eedd848ec5e7c249d479baa8d14a98ad6 100644 (file)
@@ -443,7 +443,7 @@ extern int DYN_FTRACE_TEST_NAME(void);
 
 extern int ring_buffer_expanded;
 extern bool tracing_selftest_disabled;
-DECLARE_PER_CPU(local_t, ftrace_cpu_disabled);
+DECLARE_PER_CPU(int, ftrace_cpu_disabled);
 
 #ifdef CONFIG_FTRACE_STARTUP_TEST
 extern int trace_selftest_startup_function(struct tracer *trace,
index a43d009c561a28bcbf1078626e086c63bf475d5e..b1342c5d37cfb821cfb96fcfd610cb95cdfb1082 100644 (file)
@@ -187,7 +187,7 @@ static int __trace_graph_entry(struct trace_array *tr,
        struct ring_buffer *buffer = tr->buffer;
        struct ftrace_graph_ent_entry *entry;
 
-       if (unlikely(local_read(&__get_cpu_var(ftrace_cpu_disabled))))
+       if (unlikely(__this_cpu_read(per_cpu_var(ftrace_cpu_disabled))))
                return 0;
 
        event = trace_buffer_lock_reserve(buffer, TRACE_GRAPH_ENT,
@@ -251,7 +251,7 @@ static void __trace_graph_return(struct trace_array *tr,
        struct ring_buffer *buffer = tr->buffer;
        struct ftrace_graph_ret_entry *entry;
 
-       if (unlikely(local_read(&__get_cpu_var(ftrace_cpu_disabled))))
+       if (unlikely(__this_cpu_read(per_cpu_var(ftrace_cpu_disabled))))
                return;
 
        event = trace_buffer_lock_reserve(buffer, TRACE_GRAPH_RET,
index 69543a905cd5f1c92086cb47576a21028db11a37..7b97000745f5cc38601aff4101b58d9d8bb99b6c 100644 (file)
 
 #define BTS_BUFFER_SIZE (1 << 13)
 
-static DEFINE_PER_CPU(struct bts_tracer *, tracer);
-static DEFINE_PER_CPU(unsigned char[BTS_BUFFER_SIZE], buffer);
+static DEFINE_PER_CPU(struct bts_tracer *, hwb_tracer);
+static DEFINE_PER_CPU(unsigned char[BTS_BUFFER_SIZE], hwb_buffer);
 
-#define this_tracer per_cpu(tracer, smp_processor_id())
+#define this_tracer per_cpu(hwb_tracer, smp_processor_id())
 
 static int trace_hw_branches_enabled __read_mostly;
 static int trace_hw_branches_suspended __read_mostly;
@@ -32,12 +32,13 @@ static struct trace_array *hw_branch_trace __read_mostly;
 
 static void bts_trace_init_cpu(int cpu)
 {
-       per_cpu(tracer, cpu) =
-               ds_request_bts_cpu(cpu, per_cpu(buffer, cpu), BTS_BUFFER_SIZE,
-                                  NULL, (size_t)-1, BTS_KERNEL);
+       per_cpu(hwb_tracer, cpu) =
+               ds_request_bts_cpu(cpu, per_cpu(hwb_buffer, cpu),
+                                  BTS_BUFFER_SIZE, NULL, (size_t)-1,
+                                  BTS_KERNEL);
 
-       if (IS_ERR(per_cpu(tracer, cpu)))
-               per_cpu(tracer, cpu) = NULL;
+       if (IS_ERR(per_cpu(hwb_tracer, cpu)))
+               per_cpu(hwb_tracer, cpu) = NULL;
 }
 
 static int bts_trace_init(struct trace_array *tr)
@@ -51,7 +52,7 @@ static int bts_trace_init(struct trace_array *tr)
        for_each_online_cpu(cpu) {
                bts_trace_init_cpu(cpu);
 
-               if (likely(per_cpu(tracer, cpu)))
+               if (likely(per_cpu(hwb_tracer, cpu)))
                        trace_hw_branches_enabled = 1;
        }
        trace_hw_branches_suspended = 0;
@@ -67,9 +68,9 @@ static void bts_trace_reset(struct trace_array *tr)
 
        get_online_cpus();
        for_each_online_cpu(cpu) {
-               if (likely(per_cpu(tracer, cpu))) {
-                       ds_release_bts(per_cpu(tracer, cpu));
-                       per_cpu(tracer, cpu) = NULL;
+               if (likely(per_cpu(hwb_tracer, cpu))) {
+                       ds_release_bts(per_cpu(hwb_tracer, cpu));
+                       per_cpu(hwb_tracer, cpu) = NULL;
                }
        }
        trace_hw_branches_enabled = 0;
@@ -83,8 +84,8 @@ static void bts_trace_start(struct trace_array *tr)
 
        get_online_cpus();
        for_each_online_cpu(cpu)
-               if (likely(per_cpu(tracer, cpu)))
-                       ds_resume_bts(per_cpu(tracer, cpu));
+               if (likely(per_cpu(hwb_tracer, cpu)))
+                       ds_resume_bts(per_cpu(hwb_tracer, cpu));
        trace_hw_branches_suspended = 0;
        put_online_cpus();
 }
@@ -95,8 +96,8 @@ static void bts_trace_stop(struct trace_array *tr)
 
        get_online_cpus();
        for_each_online_cpu(cpu)
-               if (likely(per_cpu(tracer, cpu)))
-                       ds_suspend_bts(per_cpu(tracer, cpu));
+               if (likely(per_cpu(hwb_tracer, cpu)))
+                       ds_suspend_bts(per_cpu(hwb_tracer, cpu));
        trace_hw_branches_suspended = 1;
        put_online_cpus();
 }
@@ -114,16 +115,16 @@ static int __cpuinit bts_hotcpu_handler(struct notifier_block *nfb,
                        bts_trace_init_cpu(cpu);
 
                        if (trace_hw_branches_suspended &&
-                           likely(per_cpu(tracer, cpu)))
-                               ds_suspend_bts(per_cpu(tracer, cpu));
+                           likely(per_cpu(hwb_tracer, cpu)))
+                               ds_suspend_bts(per_cpu(hwb_tracer, cpu));
                }
                break;
 
        case CPU_DOWN_PREPARE:
                /* The notification is sent with interrupts enabled. */
-               if (likely(per_cpu(tracer, cpu))) {
-                       ds_release_bts(per_cpu(tracer, cpu));
-                       per_cpu(tracer, cpu) = NULL;
+               if (likely(per_cpu(hwb_tracer, cpu))) {
+                       ds_release_bts(per_cpu(hwb_tracer, cpu));
+                       per_cpu(hwb_tracer, cpu) = NULL;
                }
        }
 
@@ -258,8 +259,8 @@ static void trace_bts_prepare(struct trace_iterator *iter)
 
        get_online_cpus();
        for_each_online_cpu(cpu)
-               if (likely(per_cpu(tracer, cpu)))
-                       ds_suspend_bts(per_cpu(tracer, cpu));
+               if (likely(per_cpu(hwb_tracer, cpu)))
+                       ds_suspend_bts(per_cpu(hwb_tracer, cpu));
        /*
         * We need to collect the trace on the respective cpu since ftrace
         * implicitly adds the record for the current cpu.
@@ -268,8 +269,8 @@ static void trace_bts_prepare(struct trace_iterator *iter)
        on_each_cpu(trace_bts_cpu, iter->tr, 1);
 
        for_each_online_cpu(cpu)
-               if (likely(per_cpu(tracer, cpu)))
-                       ds_resume_bts(per_cpu(tracer, cpu));
+               if (likely(per_cpu(hwb_tracer, cpu)))
+                       ds_resume_bts(per_cpu(hwb_tracer, cpu));
        put_online_cpus();
 }
 
index ebf849042ed3d6dd6dc7543d47d35585077b8a1b..82131d0f8d85fbfb007e084e882333771dd47c10 100644 (file)
@@ -34,11 +34,7 @@ obj-$(CONFIG_FAILSLAB) += failslab.o
 obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o
 obj-$(CONFIG_FS_XIP) += filemap_xip.o
 obj-$(CONFIG_MIGRATION) += migrate.o
-ifndef CONFIG_HAVE_LEGACY_PER_CPU_AREA
 obj-$(CONFIG_SMP) += percpu.o
-else
-obj-$(CONFIG_SMP) += allocpercpu.o
-endif
 obj-$(CONFIG_QUICKLIST) += quicklist.o
 obj-$(CONFIG_CGROUP_MEM_RES_CTLR) += memcontrol.o page_cgroup.o
 obj-$(CONFIG_MEMORY_FAILURE) += memory-failure.o
diff --git a/mm/allocpercpu.c b/mm/allocpercpu.c
deleted file mode 100644 (file)
index df34cea..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * linux/mm/allocpercpu.c
- *
- * Separated from slab.c August 11, 2006 Christoph Lameter
- */
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/bootmem.h>
-#include <asm/sections.h>
-
-#ifndef cache_line_size
-#define cache_line_size()      L1_CACHE_BYTES
-#endif
-
-/**
- * percpu_depopulate - depopulate per-cpu data for given cpu
- * @__pdata: per-cpu data to depopulate
- * @cpu: depopulate per-cpu data for this cpu
- *
- * Depopulating per-cpu data for a cpu going offline would be a typical
- * use case. You need to register a cpu hotplug handler for that purpose.
- */
-static void percpu_depopulate(void *__pdata, int cpu)
-{
-       struct percpu_data *pdata = __percpu_disguise(__pdata);
-
-       kfree(pdata->ptrs[cpu]);
-       pdata->ptrs[cpu] = NULL;
-}
-
-/**
- * percpu_depopulate_mask - depopulate per-cpu data for some cpu's
- * @__pdata: per-cpu data to depopulate
- * @mask: depopulate per-cpu data for cpu's selected through mask bits
- */
-static void __percpu_depopulate_mask(void *__pdata, const cpumask_t *mask)
-{
-       int cpu;
-       for_each_cpu_mask_nr(cpu, *mask)
-               percpu_depopulate(__pdata, cpu);
-}
-
-#define percpu_depopulate_mask(__pdata, mask) \
-       __percpu_depopulate_mask((__pdata), &(mask))
-
-/**
- * percpu_populate - populate per-cpu data for given cpu
- * @__pdata: per-cpu data to populate further
- * @size: size of per-cpu object
- * @gfp: may sleep or not etc.
- * @cpu: populate per-data for this cpu
- *
- * Populating per-cpu data for a cpu coming online would be a typical
- * use case. You need to register a cpu hotplug handler for that purpose.
- * Per-cpu object is populated with zeroed buffer.
- */
-static void *percpu_populate(void *__pdata, size_t size, gfp_t gfp, int cpu)
-{
-       struct percpu_data *pdata = __percpu_disguise(__pdata);
-       int node = cpu_to_node(cpu);
-
-       /*
-        * We should make sure each CPU gets private memory.
-        */
-       size = roundup(size, cache_line_size());
-
-       BUG_ON(pdata->ptrs[cpu]);
-       if (node_online(node))
-               pdata->ptrs[cpu] = kmalloc_node(size, gfp|__GFP_ZERO, node);
-       else
-               pdata->ptrs[cpu] = kzalloc(size, gfp);
-       return pdata->ptrs[cpu];
-}
-
-/**
- * percpu_populate_mask - populate per-cpu data for more cpu's
- * @__pdata: per-cpu data to populate further
- * @size: size of per-cpu object
- * @gfp: may sleep or not etc.
- * @mask: populate per-cpu data for cpu's selected through mask bits
- *
- * Per-cpu objects are populated with zeroed buffers.
- */
-static int __percpu_populate_mask(void *__pdata, size_t size, gfp_t gfp,
-                                 cpumask_t *mask)
-{
-       cpumask_t populated;
-       int cpu;
-
-       cpus_clear(populated);
-       for_each_cpu_mask_nr(cpu, *mask)
-               if (unlikely(!percpu_populate(__pdata, size, gfp, cpu))) {
-                       __percpu_depopulate_mask(__pdata, &populated);
-                       return -ENOMEM;
-               } else
-                       cpu_set(cpu, populated);
-       return 0;
-}
-
-#define percpu_populate_mask(__pdata, size, gfp, mask) \
-       __percpu_populate_mask((__pdata), (size), (gfp), &(mask))
-
-/**
- * alloc_percpu - initial setup of per-cpu data
- * @size: size of per-cpu object
- * @align: alignment
- *
- * Allocate dynamic percpu area.  Percpu objects are populated with
- * zeroed buffers.
- */
-void *__alloc_percpu(size_t size, size_t align)
-{
-       /*
-        * We allocate whole cache lines to avoid false sharing
-        */
-       size_t sz = roundup(nr_cpu_ids * sizeof(void *), cache_line_size());
-       void *pdata = kzalloc(sz, GFP_KERNEL);
-       void *__pdata = __percpu_disguise(pdata);
-
-       /*
-        * Can't easily make larger alignment work with kmalloc.  WARN
-        * on it.  Larger alignment should only be used for module
-        * percpu sections on SMP for which this path isn't used.
-        */
-       WARN_ON_ONCE(align > SMP_CACHE_BYTES);
-
-       if (unlikely(!pdata))
-               return NULL;
-       if (likely(!__percpu_populate_mask(__pdata, size, GFP_KERNEL,
-                                          &cpu_possible_map)))
-               return __pdata;
-       kfree(pdata);
-       return NULL;
-}
-EXPORT_SYMBOL_GPL(__alloc_percpu);
-
-/**
- * free_percpu - final cleanup of per-cpu data
- * @__pdata: object to clean up
- *
- * We simply clean up any per-cpu object left. No need for the client to
- * track and specify through a bis mask which per-cpu objects are to free.
- */
-void free_percpu(void *__pdata)
-{
-       if (unlikely(!__pdata))
-               return;
-       __percpu_depopulate_mask(__pdata, cpu_possible_mask);
-       kfree(__percpu_disguise(__pdata));
-}
-EXPORT_SYMBOL_GPL(free_percpu);
-
-/*
- * Generic percpu area setup.
- */
-#ifndef CONFIG_HAVE_SETUP_PER_CPU_AREA
-unsigned long __per_cpu_offset[NR_CPUS] __read_mostly;
-
-EXPORT_SYMBOL(__per_cpu_offset);
-
-void __init setup_per_cpu_areas(void)
-{
-       unsigned long size, i;
-       char *ptr;
-       unsigned long nr_possible_cpus = num_possible_cpus();
-
-       /* Copy section for each CPU (we discard the original) */
-       size = ALIGN(PERCPU_ENOUGH_ROOM, PAGE_SIZE);
-       ptr = alloc_bootmem_pages(size * nr_possible_cpus);
-
-       for_each_possible_cpu(i) {
-               __per_cpu_offset[i] = ptr - __per_cpu_start;
-               memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
-               ptr += size;
-       }
-}
-#endif /* CONFIG_HAVE_SETUP_PER_CPU_AREA */
index 7dbcb22316d2b2e482de278a8023c6429fe7bfaf..0bc640fd68fa64c38915d40fe20db545c1784799 100644 (file)
@@ -1044,7 +1044,7 @@ static int do_pages_stat(struct mm_struct *mm, unsigned long nr_pages,
        int err;
 
        for (i = 0; i < nr_pages; i += chunk_nr) {
-               if (chunk_nr + i > nr_pages)
+               if (chunk_nr > nr_pages - i)
                        chunk_nr = nr_pages - i;
 
                err = copy_from_user(chunk_pages, &pages[i],
index 5adfc268b408936a3d18ae9014ce70e49590738d..442010cc91c6c82eb8489e64d21500baa52b5911 100644 (file)
@@ -46,8 +46,6 @@
  *
  * To use this allocator, arch code should do the followings.
  *
- * - drop CONFIG_HAVE_LEGACY_PER_CPU_AREA
- *
  * - define __addr_to_pcpu_ptr() and __pcpu_ptr_to_addr() to translate
  *   regular address to percpu pointer and back if they need to be
  *   different from the default
@@ -74,6 +72,7 @@
 #include <asm/cacheflush.h>
 #include <asm/sections.h>
 #include <asm/tlbflush.h>
+#include <asm/io.h>
 
 #define PCPU_SLOT_BASE_SHIFT           5       /* 1-31 shares the same slot */
 #define PCPU_DFL_MAP_ALLOC             16      /* start a map with 16 ents */
@@ -1302,6 +1301,27 @@ void free_percpu(void *ptr)
 }
 EXPORT_SYMBOL_GPL(free_percpu);
 
+/**
+ * per_cpu_ptr_to_phys - convert translated percpu address to physical address
+ * @addr: the address to be converted to physical address
+ *
+ * Given @addr which is dereferenceable address obtained via one of
+ * percpu access macros, this function translates it into its physical
+ * address.  The caller is responsible for ensuring @addr stays valid
+ * until this function finishes.
+ *
+ * RETURNS:
+ * The physical address for @addr.
+ */
+phys_addr_t per_cpu_ptr_to_phys(void *addr)
+{
+       if ((unsigned long)addr < VMALLOC_START ||
+                       (unsigned long)addr >= VMALLOC_END)
+               return __pa(addr);
+       else
+               return page_to_phys(vmalloc_to_page(addr));
+}
+
 static inline size_t pcpu_calc_fc_sizes(size_t static_size,
                                        size_t reserved_size,
                                        ssize_t *dyn_sizep)
index a6c9166996a9f389e72f3c71a2df7bacc937fe6f..3f4822938f4605f4e6e1cf55f996f812332cd4a6 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -490,7 +490,7 @@ static void **dbg_userword(struct kmem_cache *cachep, void *objp)
 
 #endif
 
-#ifdef CONFIG_KMEMTRACE
+#ifdef CONFIG_TRACING
 size_t slab_buffer_size(struct kmem_cache *cachep)
 {
        return cachep->buffer_size;
@@ -697,7 +697,7 @@ static inline void init_lock_keys(void)
 static DEFINE_MUTEX(cache_chain_mutex);
 static struct list_head cache_chain;
 
-static DEFINE_PER_CPU(struct delayed_work, reap_work);
+static DEFINE_PER_CPU(struct delayed_work, slab_reap_work);
 
 static inline struct array_cache *cpu_cache_get(struct kmem_cache *cachep)
 {
@@ -838,7 +838,7 @@ __setup("noaliencache", noaliencache_setup);
  * objects freed on different nodes from which they were allocated) and the
  * flushing of remote pcps by calling drain_node_pages.
  */
-static DEFINE_PER_CPU(unsigned long, reap_node);
+static DEFINE_PER_CPU(unsigned long, slab_reap_node);
 
 static void init_reap_node(int cpu)
 {
@@ -848,17 +848,17 @@ static void init_reap_node(int cpu)
        if (node == MAX_NUMNODES)
                node = first_node(node_online_map);
 
-       per_cpu(reap_node, cpu) = node;
+       per_cpu(slab_reap_node, cpu) = node;
 }
 
 static void next_reap_node(void)
 {
-       int node = __get_cpu_var(reap_node);
+       int node = __get_cpu_var(slab_reap_node);
 
        node = next_node(node, node_online_map);
        if (unlikely(node >= MAX_NUMNODES))
                node = first_node(node_online_map);
-       __get_cpu_var(reap_node) = node;
+       __get_cpu_var(slab_reap_node) = node;
 }
 
 #else
@@ -875,7 +875,7 @@ static void next_reap_node(void)
  */
 static void __cpuinit start_cpu_timer(int cpu)
 {
-       struct delayed_work *reap_work = &per_cpu(reap_work, cpu);
+       struct delayed_work *reap_work = &per_cpu(slab_reap_work, cpu);
 
        /*
         * When this gets called from do_initcalls via cpucache_init(),
@@ -1039,7 +1039,7 @@ static void __drain_alien_cache(struct kmem_cache *cachep,
  */
 static void reap_alien(struct kmem_cache *cachep, struct kmem_list3 *l3)
 {
-       int node = __get_cpu_var(reap_node);
+       int node = __get_cpu_var(slab_reap_node);
 
        if (l3->alien) {
                struct array_cache *ac = l3->alien[node];
@@ -1300,9 +1300,9 @@ static int __cpuinit cpuup_callback(struct notifier_block *nfb,
                 * anything expensive but will only modify reap_work
                 * and reschedule the timer.
                */
-               cancel_rearming_delayed_work(&per_cpu(reap_work, cpu));
+               cancel_rearming_delayed_work(&per_cpu(slab_reap_work, cpu));
                /* Now the cache_reaper is guaranteed to be not running. */
-               per_cpu(reap_work, cpu).work.func = NULL;
+               per_cpu(slab_reap_work, cpu).work.func = NULL;
                break;
        case CPU_DOWN_FAILED:
        case CPU_DOWN_FAILED_FROZEN:
@@ -3578,7 +3578,7 @@ void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags)
 }
 EXPORT_SYMBOL(kmem_cache_alloc);
 
-#ifdef CONFIG_KMEMTRACE
+#ifdef CONFIG_TRACING
 void *kmem_cache_alloc_notrace(struct kmem_cache *cachep, gfp_t flags)
 {
        return __cache_alloc(cachep, flags, __builtin_return_address(0));
@@ -3641,7 +3641,7 @@ void *kmem_cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid)
 }
 EXPORT_SYMBOL(kmem_cache_alloc_node);
 
-#ifdef CONFIG_KMEMTRACE
+#ifdef CONFIG_TRACING
 void *kmem_cache_alloc_node_notrace(struct kmem_cache *cachep,
                                    gfp_t flags,
                                    int nodeid)
@@ -3669,7 +3669,7 @@ __do_kmalloc_node(size_t size, gfp_t flags, int node, void *caller)
        return ret;
 }
 
-#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_KMEMTRACE)
+#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_TRACING)
 void *__kmalloc_node(size_t size, gfp_t flags, int node)
 {
        return __do_kmalloc_node(size, flags, node,
@@ -3689,7 +3689,7 @@ void *__kmalloc_node(size_t size, gfp_t flags, int node)
        return __do_kmalloc_node(size, flags, node, NULL);
 }
 EXPORT_SYMBOL(__kmalloc_node);
-#endif /* CONFIG_DEBUG_SLAB */
+#endif /* CONFIG_DEBUG_SLAB || CONFIG_TRACING */
 #endif /* CONFIG_NUMA */
 
 /**
@@ -3721,7 +3721,7 @@ static __always_inline void *__do_kmalloc(size_t size, gfp_t flags,
 }
 
 
-#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_KMEMTRACE)
+#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_TRACING)
 void *__kmalloc(size_t size, gfp_t flags)
 {
        return __do_kmalloc(size, flags, __builtin_return_address(0));
index da0ce55965dcdf3303822e81b0193e2f15780ac1..8d71aaf888d770b27ba26df5d4d9592832a87b2d 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -1754,7 +1754,7 @@ void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags)
 }
 EXPORT_SYMBOL(kmem_cache_alloc);
 
-#ifdef CONFIG_KMEMTRACE
+#ifdef CONFIG_TRACING
 void *kmem_cache_alloc_notrace(struct kmem_cache *s, gfp_t gfpflags)
 {
        return slab_alloc(s, gfpflags, -1, _RET_IP_);
@@ -1775,7 +1775,7 @@ void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t gfpflags, int node)
 EXPORT_SYMBOL(kmem_cache_alloc_node);
 #endif
 
-#ifdef CONFIG_KMEMTRACE
+#ifdef CONFIG_TRACING
 void *kmem_cache_alloc_node_notrace(struct kmem_cache *s,
                                    gfp_t gfpflags,
                                    int node)
index 0f551a4a44cddc7a042d47bbcd85c7126569ee69..9b08d790df6fe441a2b8c2002ed9f0e1a4677641 100644 (file)
@@ -761,7 +761,7 @@ static struct vmap_block *new_vmap_block(gfp_t gfp_mask)
        spin_lock(&vbq->lock);
        list_add(&vb->free_list, &vbq->free);
        spin_unlock(&vbq->lock);
-       put_cpu_var(vmap_cpu_blocks);
+       put_cpu_var(vmap_block_queue);
 
        return vb;
 }
@@ -826,7 +826,7 @@ again:
                }
                spin_unlock(&vb->lock);
        }
-       put_cpu_var(vmap_cpu_blocks);
+       put_cpu_var(vmap_block_queue);
        rcu_read_unlock();
 
        if (!addr) {
index c81321f9feec1cb28eee1b7e07237017336b89d0..dad2327e45804e16a8ff07564a80eb0cac79f482 100644 (file)
@@ -883,11 +883,10 @@ static void vmstat_update(struct work_struct *w)
 
 static void __cpuinit start_cpu_timer(int cpu)
 {
-       struct delayed_work *vmstat_work = &per_cpu(vmstat_work, cpu);
+       struct delayed_work *work = &per_cpu(vmstat_work, cpu);
 
-       INIT_DELAYED_WORK_DEFERRABLE(vmstat_work, vmstat_update);
-       schedule_delayed_work_on(cpu, vmstat_work,
-                                __round_jiffies_relative(HZ, cpu));
+       INIT_DELAYED_WORK_DEFERRABLE(work, vmstat_update);
+       schedule_delayed_work_on(cpu, work, __round_jiffies_relative(HZ, cpu));
 }
 
 /*
index c7450c8f0a7c040ac756bfd28220152e9d3713b8..6dcdd2517819ea2a170038e1d21b35a193606c68 100644 (file)
@@ -55,16 +55,8 @@ static size_t rpc_ntop6_noscopeid(const struct sockaddr *sap,
 
        /*
         * RFC 4291, Section 2.2.1
-        *
-        * To keep the result as short as possible, especially
-        * since we don't shorthand, we don't want leading zeros
-        * in each halfword, so avoid %pI6.
         */
-       return snprintf(buf, buflen, "%x:%x:%x:%x:%x:%x:%x:%x",
-               ntohs(addr->s6_addr16[0]), ntohs(addr->s6_addr16[1]),
-               ntohs(addr->s6_addr16[2]), ntohs(addr->s6_addr16[3]),
-               ntohs(addr->s6_addr16[4]), ntohs(addr->s6_addr16[5]),
-               ntohs(addr->s6_addr16[6]), ntohs(addr->s6_addr16[7]));
+       return snprintf(buf, buflen, "%pI6c", addr);
 }
 
 static size_t rpc_ntop6(const struct sockaddr *sap,
index 7535a7bed2fa89b35910112b9f62e84915cb1513..f394fc190a496f81125a467ec4723862da12c5f2 100644 (file)
@@ -123,16 +123,19 @@ rpcauth_unhash_cred_locked(struct rpc_cred *cred)
        clear_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags);
 }
 
-static void
+static int
 rpcauth_unhash_cred(struct rpc_cred *cred)
 {
        spinlock_t *cache_lock;
+       int ret;
 
        cache_lock = &cred->cr_auth->au_credcache->lock;
        spin_lock(cache_lock);
-       if (atomic_read(&cred->cr_count) == 0)
+       ret = atomic_read(&cred->cr_count) == 0;
+       if (ret)
                rpcauth_unhash_cred_locked(cred);
        spin_unlock(cache_lock);
+       return ret;
 }
 
 /*
@@ -446,31 +449,35 @@ void
 put_rpccred(struct rpc_cred *cred)
 {
        /* Fast path for unhashed credentials */
-       if (test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0)
-               goto need_lock;
-
-       if (!atomic_dec_and_test(&cred->cr_count))
+       if (test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) == 0) {
+               if (atomic_dec_and_test(&cred->cr_count))
+                       cred->cr_ops->crdestroy(cred);
                return;
-       goto out_destroy;
-need_lock:
+       }
+
        if (!atomic_dec_and_lock(&cred->cr_count, &rpc_credcache_lock))
                return;
        if (!list_empty(&cred->cr_lru)) {
                number_cred_unused--;
                list_del_init(&cred->cr_lru);
        }
-       if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0)
-               rpcauth_unhash_cred(cred);
        if (test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0) {
-               cred->cr_expire = jiffies;
-               list_add_tail(&cred->cr_lru, &cred_unused);
-               number_cred_unused++;
-               spin_unlock(&rpc_credcache_lock);
-               return;
+               if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) != 0) {
+                       cred->cr_expire = jiffies;
+                       list_add_tail(&cred->cr_lru, &cred_unused);
+                       number_cred_unused++;
+                       goto out_nodestroy;
+               }
+               if (!rpcauth_unhash_cred(cred)) {
+                       /* We were hashed and someone looked us up... */
+                       goto out_nodestroy;
+               }
        }
        spin_unlock(&rpc_credcache_lock);
-out_destroy:
        cred->cr_ops->crdestroy(cred);
+       return;
+out_nodestroy:
+       spin_unlock(&rpc_credcache_lock);
 }
 EXPORT_SYMBOL_GPL(put_rpccred);
 
index fc6a43ccd95091154cb7aeff1aa457102efe5e93..3c3c50f38a1c4a773113db4f5388b27bc85453f8 100644 (file)
@@ -304,7 +304,7 @@ __gss_find_upcall(struct rpc_inode *rpci, uid_t uid)
  * to that upcall instead of adding the new upcall.
  */
 static inline struct gss_upcall_msg *
-gss_add_msg(struct gss_auth *gss_auth, struct gss_upcall_msg *gss_msg)
+gss_add_msg(struct gss_upcall_msg *gss_msg)
 {
        struct rpc_inode *rpci = gss_msg->inode;
        struct inode *inode = &rpci->vfs_inode;
@@ -445,7 +445,7 @@ gss_setup_upcall(struct rpc_clnt *clnt, struct gss_auth *gss_auth, struct rpc_cr
        gss_new = gss_alloc_msg(gss_auth, uid, clnt, gss_cred->gc_machine_cred);
        if (IS_ERR(gss_new))
                return gss_new;
-       gss_msg = gss_add_msg(gss_auth, gss_new);
+       gss_msg = gss_add_msg(gss_new);
        if (gss_msg == gss_new) {
                struct inode *inode = &gss_new->inode->vfs_inode;
                int res = rpc_queue_upcall(inode, &gss_new->msg);
@@ -485,7 +485,7 @@ gss_refresh_upcall(struct rpc_task *task)
        dprintk("RPC: %5u gss_refresh_upcall for uid %u\n", task->tk_pid,
                                                                cred->cr_uid);
        gss_msg = gss_setup_upcall(task->tk_client, gss_auth, cred);
-       if (IS_ERR(gss_msg) == -EAGAIN) {
+       if (PTR_ERR(gss_msg) == -EAGAIN) {
                /* XXX: warning on the first, under the assumption we
                 * shouldn't normally hit this case on a refresh. */
                warn_gssd();
index 38829e20500bf787aa59189501aaf7ce323a113c..154034b675bd90de493d1438ff46a2b230178742 100644 (file)
@@ -79,7 +79,7 @@ static void   call_connect_status(struct rpc_task *task);
 
 static __be32  *rpc_encode_header(struct rpc_task *task);
 static __be32  *rpc_verify_header(struct rpc_task *task);
-static int     rpc_ping(struct rpc_clnt *clnt, int flags);
+static int     rpc_ping(struct rpc_clnt *clnt);
 
 static void rpc_register_client(struct rpc_clnt *clnt)
 {
@@ -340,7 +340,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
                return clnt;
 
        if (!(args->flags & RPC_CLNT_CREATE_NOPING)) {
-               int err = rpc_ping(clnt, RPC_TASK_SOFT);
+               int err = rpc_ping(clnt);
                if (err != 0) {
                        rpc_shutdown_client(clnt);
                        return ERR_PTR(err);
@@ -528,7 +528,7 @@ struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *old,
        clnt->cl_prog     = program->number;
        clnt->cl_vers     = version->number;
        clnt->cl_stats    = program->stats;
-       err = rpc_ping(clnt, RPC_TASK_SOFT);
+       err = rpc_ping(clnt);
        if (err != 0) {
                rpc_shutdown_client(clnt);
                clnt = ERR_PTR(err);
@@ -1060,7 +1060,7 @@ call_bind_status(struct rpc_task *task)
                goto retry_timeout;
        case -EPFNOSUPPORT:
                /* server doesn't support any rpcbind version we know of */
-               dprintk("RPC: %5u remote rpcbind service unavailable\n",
+               dprintk("RPC: %5u unrecognized remote rpcbind service\n",
                                task->tk_pid);
                break;
        case -EPROTONOSUPPORT:
@@ -1069,6 +1069,21 @@ call_bind_status(struct rpc_task *task)
                task->tk_status = 0;
                task->tk_action = call_bind;
                return;
+       case -ECONNREFUSED:             /* connection problems */
+       case -ECONNRESET:
+       case -ENOTCONN:
+       case -EHOSTDOWN:
+       case -EHOSTUNREACH:
+       case -ENETUNREACH:
+       case -EPIPE:
+               dprintk("RPC: %5u remote rpcbind unreachable: %d\n",
+                               task->tk_pid, task->tk_status);
+               if (!RPC_IS_SOFTCONN(task)) {
+                       rpc_delay(task, 5*HZ);
+                       goto retry_timeout;
+               }
+               status = task->tk_status;
+               break;
        default:
                dprintk("RPC: %5u unrecognized rpcbind error (%d)\n",
                                task->tk_pid, -task->tk_status);
@@ -1180,11 +1195,25 @@ static void
 call_transmit_status(struct rpc_task *task)
 {
        task->tk_action = call_status;
+
+       /*
+        * Common case: success.  Force the compiler to put this
+        * test first.
+        */
+       if (task->tk_status == 0) {
+               xprt_end_transmit(task);
+               rpc_task_force_reencode(task);
+               return;
+       }
+
        switch (task->tk_status) {
        case -EAGAIN:
                break;
        default:
+               dprint_status(task);
                xprt_end_transmit(task);
+               rpc_task_force_reencode(task);
+               break;
                /*
                 * Special cases: if we've been waiting on the
                 * socket's write_space() callback, or if the
@@ -1192,11 +1221,16 @@ call_transmit_status(struct rpc_task *task)
                 * then hold onto the transport lock.
                 */
        case -ECONNREFUSED:
-       case -ECONNRESET:
-       case -ENOTCONN:
        case -EHOSTDOWN:
        case -EHOSTUNREACH:
        case -ENETUNREACH:
+               if (RPC_IS_SOFTCONN(task)) {
+                       xprt_end_transmit(task);
+                       rpc_exit(task, task->tk_status);
+                       break;
+               }
+       case -ECONNRESET:
+       case -ENOTCONN:
        case -EPIPE:
                rpc_task_force_reencode(task);
        }
@@ -1346,6 +1380,10 @@ call_timeout(struct rpc_task *task)
        dprintk("RPC: %5u call_timeout (major)\n", task->tk_pid);
        task->tk_timeouts++;
 
+       if (RPC_IS_SOFTCONN(task)) {
+               rpc_exit(task, -ETIMEDOUT);
+               return;
+       }
        if (RPC_IS_SOFT(task)) {
                if (clnt->cl_chatty)
                        printk(KERN_NOTICE "%s: server %s not responding, timed out\n",
@@ -1675,14 +1713,14 @@ static struct rpc_procinfo rpcproc_null = {
        .p_decode = rpcproc_decode_null,
 };
 
-static int rpc_ping(struct rpc_clnt *clnt, int flags)
+static int rpc_ping(struct rpc_clnt *clnt)
 {
        struct rpc_message msg = {
                .rpc_proc = &rpcproc_null,
        };
        int err;
        msg.rpc_cred = authnull_ops.lookup_cred(NULL, NULL, 0);
-       err = rpc_call_sync(clnt, &msg, flags);
+       err = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT | RPC_TASK_SOFTCONN);
        put_rpccred(msg.rpc_cred);
        return err;
 }
index 830faf4d9997c971bb717ee0a2210efb2f22bc63..3e3772d8eb921ce00af629ad11627ad3677ea613 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/in6.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
+#include <linux/mutex.h>
 #include <net/ipv6.h>
 
 #include <linux/sunrpc/clnt.h>
@@ -110,6 +111,9 @@ static void                 rpcb_getport_done(struct rpc_task *, void *);
 static void                    rpcb_map_release(void *data);
 static struct rpc_program      rpcb_program;
 
+static struct rpc_clnt *       rpcb_local_clnt;
+static struct rpc_clnt *       rpcb_local_clnt4;
+
 struct rpcbind_args {
        struct rpc_xprt *       r_xprt;
 
@@ -163,21 +167,60 @@ static const struct sockaddr_in rpcb_inaddr_loopback = {
        .sin_port               = htons(RPCBIND_PORT),
 };
 
-static struct rpc_clnt *rpcb_create_local(struct sockaddr *addr,
-                                         size_t addrlen, u32 version)
+static DEFINE_MUTEX(rpcb_create_local_mutex);
+
+/*
+ * Returns zero on success, otherwise a negative errno value
+ * is returned.
+ */
+static int rpcb_create_local(void)
 {
        struct rpc_create_args args = {
-               .protocol       = XPRT_TRANSPORT_UDP,
-               .address        = addr,
-               .addrsize       = addrlen,
+               .protocol       = XPRT_TRANSPORT_TCP,
+               .address        = (struct sockaddr *)&rpcb_inaddr_loopback,
+               .addrsize       = sizeof(rpcb_inaddr_loopback),
                .servername     = "localhost",
                .program        = &rpcb_program,
-               .version        = version,
+               .version        = RPCBVERS_2,
                .authflavor     = RPC_AUTH_UNIX,
                .flags          = RPC_CLNT_CREATE_NOPING,
        };
+       struct rpc_clnt *clnt, *clnt4;
+       int result = 0;
+
+       if (rpcb_local_clnt)
+               return result;
+
+       mutex_lock(&rpcb_create_local_mutex);
+       if (rpcb_local_clnt)
+               goto out;
+
+       clnt = rpc_create(&args);
+       if (IS_ERR(clnt)) {
+               dprintk("RPC:       failed to create local rpcbind "
+                               "client (errno %ld).\n", PTR_ERR(clnt));
+               result = -PTR_ERR(clnt);
+               goto out;
+       }
 
-       return rpc_create(&args);
+       /*
+        * This results in an RPC ping.  On systems running portmapper,
+        * the v4 ping will fail.  Proceed anyway, but disallow rpcb
+        * v4 upcalls.
+        */
+       clnt4 = rpc_bind_new_program(clnt, &rpcb_program, RPCBVERS_4);
+       if (IS_ERR(clnt4)) {
+               dprintk("RPC:       failed to create local rpcbind v4 "
+                               "cleint (errno %ld).\n", PTR_ERR(clnt4));
+               clnt4 = NULL;
+       }
+
+       rpcb_local_clnt = clnt;
+       rpcb_local_clnt4 = clnt4;
+
+out:
+       mutex_unlock(&rpcb_create_local_mutex);
+       return result;
 }
 
 static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
@@ -209,22 +252,13 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
        return rpc_create(&args);
 }
 
-static int rpcb_register_call(const u32 version, struct rpc_message *msg)
+static int rpcb_register_call(struct rpc_clnt *clnt, struct rpc_message *msg)
 {
-       struct sockaddr *addr = (struct sockaddr *)&rpcb_inaddr_loopback;
-       size_t addrlen = sizeof(rpcb_inaddr_loopback);
-       struct rpc_clnt *rpcb_clnt;
        int result, error = 0;
 
        msg->rpc_resp = &result;
 
-       rpcb_clnt = rpcb_create_local(addr, addrlen, version);
-       if (!IS_ERR(rpcb_clnt)) {
-               error = rpc_call_sync(rpcb_clnt, msg, 0);
-               rpc_shutdown_client(rpcb_clnt);
-       } else
-               error = PTR_ERR(rpcb_clnt);
-
+       error = rpc_call_sync(clnt, msg, RPC_TASK_SOFTCONN);
        if (error < 0) {
                dprintk("RPC:       failed to contact local rpcbind "
                                "server (errno %d).\n", -error);
@@ -279,6 +313,11 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port)
        struct rpc_message msg = {
                .rpc_argp       = &map,
        };
+       int error;
+
+       error = rpcb_create_local();
+       if (error)
+               return error;
 
        dprintk("RPC:       %sregistering (%u, %u, %d, %u) with local "
                        "rpcbind\n", (port ? "" : "un"),
@@ -288,7 +327,7 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port)
        if (port)
                msg.rpc_proc = &rpcb_procedures2[RPCBPROC_SET];
 
-       return rpcb_register_call(RPCBVERS_2, &msg);
+       return rpcb_register_call(rpcb_local_clnt, &msg);
 }
 
 /*
@@ -313,7 +352,7 @@ static int rpcb_register_inet4(const struct sockaddr *sap,
        if (port)
                msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
 
-       result = rpcb_register_call(RPCBVERS_4, msg);
+       result = rpcb_register_call(rpcb_local_clnt4, msg);
        kfree(map->r_addr);
        return result;
 }
@@ -340,7 +379,7 @@ static int rpcb_register_inet6(const struct sockaddr *sap,
        if (port)
                msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
 
-       result = rpcb_register_call(RPCBVERS_4, msg);
+       result = rpcb_register_call(rpcb_local_clnt4, msg);
        kfree(map->r_addr);
        return result;
 }
@@ -356,7 +395,7 @@ static int rpcb_unregister_all_protofamilies(struct rpc_message *msg)
        map->r_addr = "";
        msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET];
 
-       return rpcb_register_call(RPCBVERS_4, msg);
+       return rpcb_register_call(rpcb_local_clnt4, msg);
 }
 
 /**
@@ -414,6 +453,13 @@ int rpcb_v4_register(const u32 program, const u32 version,
        struct rpc_message msg = {
                .rpc_argp       = &map,
        };
+       int error;
+
+       error = rpcb_create_local();
+       if (error)
+               return error;
+       if (rpcb_local_clnt4 == NULL)
+               return -EPROTONOSUPPORT;
 
        if (address == NULL)
                return rpcb_unregister_all_protofamilies(&msg);
@@ -491,7 +537,7 @@ static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbi
                .rpc_message = &msg,
                .callback_ops = &rpcb_getport_ops,
                .callback_data = map,
-               .flags = RPC_TASK_ASYNC,
+               .flags = RPC_TASK_ASYNC | RPC_TASK_SOFTCONN,
        };
 
        return rpc_run_task(&task_setup_data);
@@ -1027,3 +1073,15 @@ static struct rpc_program rpcb_program = {
        .version        = rpcb_version,
        .stats          = &rpcb_stats,
 };
+
+/**
+ * cleanup_rpcb_clnt - remove xprtsock's sysctls, unregister
+ *
+ */
+void cleanup_rpcb_clnt(void)
+{
+       if (rpcb_local_clnt4)
+               rpc_shutdown_client(rpcb_local_clnt4);
+       if (rpcb_local_clnt)
+               rpc_shutdown_client(rpcb_local_clnt);
+}
index 8cce92189019c7e8d73cc874820a88187067de22..f438347d817b2bb5889ea6d364db5abeceb819e9 100644 (file)
@@ -24,6 +24,8 @@
 
 extern struct cache_detail ip_map_cache, unix_gid_cache;
 
+extern void cleanup_rpcb_clnt(void);
+
 static int __init
 init_sunrpc(void)
 {
@@ -53,6 +55,7 @@ out:
 static void __exit
 cleanup_sunrpc(void)
 {
+       cleanup_rpcb_clnt();
        rpcauth_remove_module();
        cleanup_socket_xprt();
        svc_cleanup_xprt_sock();
index fd46d42afa89ed89e6fe2813822f7570e6683160..469de292c23c34b8ba9a0f9ea24e07d4b77d5e09 100644 (file)
@@ -700,6 +700,10 @@ void xprt_connect(struct rpc_task *task)
        }
        if (!xprt_lock_write(xprt, task))
                return;
+
+       if (test_and_clear_bit(XPRT_CLOSE_WAIT, &xprt->state))
+               xprt->ops->close(xprt);
+
        if (xprt_connected(xprt))
                xprt_release_write(xprt, task);
        else {
index 04732d09013eaa745c1e557d7d0a53f02699e21c..3d739e5d15d8b65a77be7fcb80a9ed012ba7c0d3 100644 (file)
@@ -2019,7 +2019,7 @@ static void xs_connect(struct rpc_task *task)
        if (xprt_test_and_set_connecting(xprt))
                return;
 
-       if (transport->sock != NULL) {
+       if (transport->sock != NULL && !RPC_IS_SOFTCONN(task)) {
                dprintk("RPC:       xs_connect delayed xprt %p for %lu "
                                "seconds\n",
                                xprt, xprt->reestablish_timeout / HZ);
index f0d14452632b554fa3d85681d075a729b54ebb2f..9cf0a6fad6ba8bc03a11dca5e658fde8ed8f6af4 100755 (executable)
@@ -295,6 +295,9 @@ if ($arch eq "x86_64") {
     $ld .= " -m elf64_sparc";
     $cc .= " -m64";
     $objcopy .= " -O elf64-sparc";
+} elsif ($arch eq "microblaze") {
+    # Microblaze calls '_mcount' instead of plain 'mcount'.
+    $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$";
 } else {
     die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD";
 }
index 7717e01fc07127f51e99c3a669a18be75ab6a0eb..edaa729126bb731b0f86a55a7277f258f2774f4c 100644 (file)
@@ -143,7 +143,8 @@ static int snd_pdacf_probe(struct pcmcia_device *link)
        link->io.NumPorts1 = 16;
 
        link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_FORCED_PULSE;
-       // link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
+       /* FIXME: This driver should be updated to allow for dynamic IRQ sharing */
+       /* link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_FORCED_PULSE; */
 
        link->irq.Handler = pdacf_interrupt;
        link->conf.Attributes = CONF_ENABLE_IRQ;
index 5f1681f6ca766531d07270e82c1f81494f0d86a4..2a27f7b56726ab951219fd36289d595ba92fdad7 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
-#include <linux/i2c/twl4030.h>
+#include <linux/i2c/twl.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -175,7 +175,7 @@ static int twl4030_write(struct snd_soc_codec *codec,
 {
        twl4030_write_reg_cache(codec, reg, value);
        if (likely(reg < TWL4030_REG_SW_SHADOW))
-               return twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value,
+               return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value,
                                            reg);
        else
                return 0;
@@ -261,7 +261,7 @@ static void twl4030_power_up(struct snd_soc_codec *codec)
        do {
                /* this takes a little while, so don't slam i2c */
                udelay(2000);
-               twl4030_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte,
+               twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte,
                                    TWL4030_REG_ANAMICL);
        } while ((i++ < 100) &&
                 ((byte & TWL4030_CNCL_OFFSET_START) ==
@@ -542,7 +542,7 @@ static int pin_name##pga_event(struct snd_soc_dapm_widget *w,               \
                break;                                                  \
        case SND_SOC_DAPM_POST_PMD:                                     \
                reg_val = twl4030_read_reg_cache(w->codec, reg);        \
-               twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,        \
+               twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,    \
                                        reg_val & (~mask),              \
                                        reg);                           \
                break;                                                  \
@@ -679,7 +679,7 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
                mdelay((ramp_base[(hs_pop & TWL4030_RAMP_DELAY) >> 2] /
                        twl4030->sysclk) + 1);
                /* Bypass the reg_cache to mute the headset */
-               twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
+               twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
                                        hs_gain & (~0x0f),
                                        TWL4030_REG_HS_GAIN_SET);
 
index f82125d9e85a750e0aefd4d9d3ed7db9f7e30ecb..ebbf11b653a4f3042708ae966c952e6ca46545da 100644 (file)
@@ -1340,9 +1340,10 @@ static int wm8350_resume(struct platform_device *pdev)
        return 0;
 }
 
-static void wm8350_hp_jack_handler(struct wm8350 *wm8350, int irq, void *data)
+static irqreturn_t wm8350_hp_jack_handler(int irq, void *data)
 {
        struct wm8350_data *priv = data;
+       struct wm8350 *wm8350 = priv->codec.control_data;
        u16 reg;
        int report;
        int mask;
@@ -1365,7 +1366,7 @@ static void wm8350_hp_jack_handler(struct wm8350 *wm8350, int irq, void *data)
 
        if (!jack->jack) {
                dev_warn(wm8350->dev, "Jack interrupt called with no jack\n");
-               return;
+               return IRQ_NONE;
        }
 
        /* Debounce */
@@ -1378,6 +1379,8 @@ static void wm8350_hp_jack_handler(struct wm8350 *wm8350, int irq, void *data)
                report = 0;
 
        snd_soc_jack_report(jack->jack, report, jack->report);
+
+       return IRQ_HANDLED;
 }
 
 /**
@@ -1421,9 +1424,7 @@ int wm8350_hp_jack_detect(struct snd_soc_codec *codec, enum wm8350_jack which,
        wm8350_set_bits(wm8350, WM8350_JACK_DETECT, ena);
 
        /* Sync status */
-       wm8350_hp_jack_handler(wm8350, irq, priv);
-
-       wm8350_unmask_irq(wm8350, irq);
+       wm8350_hp_jack_handler(irq, priv);
 
        return 0;
 }
@@ -1482,12 +1483,16 @@ static int wm8350_probe(struct platform_device *pdev)
        wm8350_set_bits(wm8350, WM8350_ROUT2_VOLUME,
                        WM8350_OUT2_VU | WM8350_OUT2R_MUTE);
 
-       wm8350_mask_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L);
-       wm8350_mask_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R);
+       /* Make sure jack detect is disabled to start off with */
+       wm8350_clear_bits(wm8350, WM8350_JACK_DETECT,
+                         WM8350_JDL_ENA | WM8350_JDR_ENA);
+
        wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L,
-                           wm8350_hp_jack_handler, priv);
+                           wm8350_hp_jack_handler, 0, "Left jack detect",
+                           priv);
        wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R,
-                           wm8350_hp_jack_handler, priv);
+                           wm8350_hp_jack_handler, 0, "Right jack detect",
+                           priv);
 
        ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
        if (ret < 0) {
@@ -1516,8 +1521,6 @@ static int wm8350_remove(struct platform_device *pdev)
                          WM8350_JDL_ENA | WM8350_JDR_ENA);
        wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA);
 
-       wm8350_mask_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L);
-       wm8350_mask_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R);
        wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L);
        wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R);
 
index 23ec66098bdc45c6c81ca9559fd16dc46f3b5ffb..406999668cab5b4538317898cd5ebf1c21718109 100644 (file)
@@ -237,8 +237,8 @@ lib = lib
 
 export prefix bindir sharedir sysconfdir
 
-CC = gcc
-AR = ar
+CC = $(CROSS_COMPILE)gcc
+AR = $(CROSS_COMPILE)ar
 RM = rm -f
 TAR = tar
 FIND = find
@@ -356,7 +356,9 @@ LIB_H += util/parse-options.h
 LIB_H += util/parse-events.h
 LIB_H += util/quote.h
 LIB_H += util/util.h
+LIB_H += util/header.h
 LIB_H += util/help.h
+LIB_H += util/session.h
 LIB_H += util/strbuf.h
 LIB_H += util/string.h
 LIB_H += util/strlist.h
@@ -405,6 +407,7 @@ LIB_OBJS += util/callchain.o
 LIB_OBJS += util/values.o
 LIB_OBJS += util/debug.o
 LIB_OBJS += util/map.o
+LIB_OBJS += util/session.o
 LIB_OBJS += util/thread.o
 LIB_OBJS += util/trace-event-parse.o
 LIB_OBJS += util/trace-event-read.o
@@ -492,8 +495,10 @@ else
        LIB_OBJS += util/probe-finder.o
 endif
 
+ifndef NO_LIBPERL
 PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null`
 PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
+endif
 
 ifneq ($(shell sh -c "(echo '\#include <EXTERN.h>'; echo '\#include <perl.h>'; echo 'int main(void) { perl_alloc(); return 0; }') | $(CC) -x c - $(PERL_EMBED_CCOPTS) -o /dev/null $(PERL_EMBED_LDOPTS) > /dev/null 2>&1 && echo y"), y)
        BASIC_CFLAGS += -DNO_LIBPERL
index 605a2a959aa839e11e846e88fe47f91bb22d01e0..81cee78181fa28fd2f382144c061e409c439fb3f 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- * builtin-bench-messaging.c
+ * sched-messaging.c
  *
  * messaging: Benchmark for scheduler and IPC mechanisms
  *
@@ -320,10 +320,12 @@ int bench_sched_messaging(int argc, const char **argv,
                       num_groups, num_groups * 2 * num_fds,
                       thread_mode ? "threads" : "processes");
                printf(" %14s: %lu.%03lu [sec]\n", "Total time",
-                      diff.tv_sec, diff.tv_usec/1000);
+                      diff.tv_sec,
+                      (unsigned long) (diff.tv_usec/1000));
                break;
        case BENCH_FORMAT_SIMPLE:
-               printf("%lu.%03lu\n", diff.tv_sec, diff.tv_usec/1000);
+               printf("%lu.%03lu\n", diff.tv_sec,
+                      (unsigned long) (diff.tv_usec/1000));
                break;
        default:
                /* reaching here is something disaster */
index 238185f97977f1d86270cd1ce50d8ab2d9b046ac..4f77c7c27640791e357a130d71639d688c892641 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- * builtin-bench-pipe.c
+ * sched-pipe.c
  *
  * pipe: Benchmark for pipe()
  *
@@ -87,7 +87,8 @@ int bench_sched_pipe(int argc, const char **argv,
        if (pid) {
                retpid = waitpid(pid, &wait_stat, 0);
                assert((retpid == pid) && WIFEXITED(wait_stat));
-               return 0;
+       } else {
+               exit(0);
        }
 
        switch (bench_format) {
@@ -99,7 +100,8 @@ int bench_sched_pipe(int argc, const char **argv,
                result_usec += diff.tv_usec;
 
                printf(" %14s: %lu.%03lu [sec]\n\n", "Total time",
-                      diff.tv_sec, diff.tv_usec/1000);
+                      diff.tv_sec,
+                      (unsigned long) (diff.tv_usec/1000));
 
                printf(" %14lf usecs/op\n",
                       (double)result_usec / (double)loops);
@@ -110,7 +112,8 @@ int bench_sched_pipe(int argc, const char **argv,
 
        case BENCH_FORMAT_SIMPLE:
                printf("%lu.%03lu\n",
-                      diff.tv_sec, diff.tv_usec / 1000);
+                      diff.tv_sec,
+                      (unsigned long) (diff.tv_usec / 1000));
                break;
 
        default:
index 0bf2e8f9af5776538237fa7e842c33e070b4dbe0..21a78d30d53dcf584a27ede521b34ddeb53118a3 100644 (file)
@@ -25,6 +25,7 @@
 #include "util/thread.h"
 #include "util/sort.h"
 #include "util/hist.h"
+#include "util/session.h"
 #include "util/data_map.h"
 
 static char            const *input_name = "perf.data";
@@ -462,21 +463,23 @@ static struct perf_file_handler file_handler = {
 
 static int __cmd_annotate(void)
 {
-       struct perf_header *header;
+       struct perf_session *session = perf_session__new(input_name, O_RDONLY, force);
        struct thread *idle;
        int ret;
 
+       if (session == NULL)
+               return -ENOMEM;
+
        idle = register_idle_thread();
        register_perf_file_handler(&file_handler);
 
-       ret = mmap_dispatch_perf_file(&header, input_name, 0, 0,
-                                     &event__cwdlen, &event__cwd);
+       ret = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd);
        if (ret)
-               return ret;
+               goto out_delete;
 
        if (dump_trace) {
                event__print_totals();
-               return 0;
+               goto out_delete;
        }
 
        if (verbose > 3)
@@ -489,6 +492,8 @@ static int __cmd_annotate(void)
        output__resort(event__total[0]);
 
        find_annotations();
+out_delete:
+       perf_session__delete(session);
 
        return ret;
 }
index e043eb83092aa3576a89016f70e8698e36c97e49..46996774e55967dc1351f9bf731ebc2f0c36cc59 100644 (file)
@@ -31,6 +31,9 @@ struct bench_suite {
        const char *summary;
        int (*fn)(int, const char **, const char *);
 };
+                                               \
+/* sentinel: easy for help */
+#define suite_all { "all", "test all suite (pseudo suite)", NULL }
 
 static struct bench_suite sched_suites[] = {
        { "messaging",
@@ -39,6 +42,7 @@ static struct bench_suite sched_suites[] = {
        { "pipe",
          "Flood of communication over pipe() between two processes",
          bench_sched_pipe      },
+       suite_all,
        { NULL,
          NULL,
          NULL                  }
@@ -48,6 +52,7 @@ static struct bench_suite mem_suites[] = {
        { "memcpy",
          "Simple memory copy in various ways",
          bench_mem_memcpy },
+       suite_all,
        { NULL,
          NULL,
          NULL             }
@@ -66,6 +71,9 @@ static struct bench_subsys subsystems[] = {
        { "mem",
          "memory access performance",
          mem_suites },
+       { "all",                /* sentinel: easy for help */
+         "test all subsystem (pseudo subsystem)",
+         NULL },
        { NULL,
          NULL,
          NULL       }
@@ -75,11 +83,11 @@ static void dump_suites(int subsys_index)
 {
        int i;
 
-       printf("List of available suites for %s...\n\n",
+       printf("List of available suites for %s...\n\n",
               subsystems[subsys_index].name);
 
        for (i = 0; subsystems[subsys_index].suites[i].name; i++)
-               printf("\t%s: %s\n",
+               printf("%14s: %s\n",
                       subsystems[subsys_index].suites[i].name,
                       subsystems[subsys_index].suites[i].summary);
 
@@ -110,10 +118,10 @@ static void print_usage(void)
                printf("\t%s\n", bench_usage[i]);
        printf("\n");
 
-       printf("List of available subsystems...\n\n");
+       printf("List of available subsystems...\n\n");
 
        for (i = 0; subsystems[i].name; i++)
-               printf("\t%s: %s\n",
+               printf("%14s: %s\n",
                       subsystems[i].name, subsystems[i].summary);
        printf("\n");
 }
@@ -131,6 +139,37 @@ static int bench_str2int(char *str)
        return BENCH_FORMAT_UNKNOWN;
 }
 
+static void all_suite(struct bench_subsys *subsys)       /* FROM HERE */
+{
+       int i;
+       const char *argv[2];
+       struct bench_suite *suites = subsys->suites;
+
+       argv[1] = NULL;
+       /*
+        * TODO:
+        * preparing preset parameters for
+        * embedded, ordinary PC, HPC, etc...
+        * will be helpful
+        */
+       for (i = 0; suites[i].fn; i++) {
+               printf("# Running %s/%s benchmark...\n",
+                      subsys->name,
+                      suites[i].name);
+
+               argv[1] = suites[i].name;
+               suites[i].fn(1, argv, NULL);
+               printf("\n");
+       }
+}
+
+static void all_subsystem(void)
+{
+       int i;
+       for (i = 0; subsystems[i].suites; i++)
+               all_suite(&subsystems[i]);
+}
+
 int cmd_bench(int argc, const char **argv, const char *prefix __used)
 {
        int i, j, status = 0;
@@ -155,6 +194,11 @@ int cmd_bench(int argc, const char **argv, const char *prefix __used)
                goto end;
        }
 
+       if (!strcmp(argv[0], "all")) {
+               all_subsystem();
+               goto end;
+       }
+
        for (i = 0; subsystems[i].name; i++) {
                if (strcmp(subsystems[i].name, argv[0]))
                        continue;
@@ -165,6 +209,11 @@ int cmd_bench(int argc, const char **argv, const char *prefix __used)
                        goto end;
                }
 
+               if (!strcmp(argv[1], "all")) {
+                       all_suite(&subsystems[i]);
+                       goto end;
+               }
+
                for (j = 0; subsystems[i].suites[j].name; j++) {
                        if (strcmp(subsystems[i].suites[j].name, argv[1]))
                                continue;
index dcb6143a000204aa7568f876a44bbf6b6a2619bf..bfd16a1594e4abbcca6d0970eb6bc14571c75c6b 100644 (file)
@@ -11,8 +11,8 @@
 #include "util/cache.h"
 #include "util/data_map.h"
 #include "util/debug.h"
-#include "util/header.h"
 #include "util/parse-options.h"
+#include "util/session.h"
 #include "util/symbol.h"
 
 static char const *input_name = "perf.data";
@@ -55,56 +55,17 @@ static int perf_file_section__process_buildids(struct perf_file_section *self,
 static int __cmd_buildid_list(void)
 {
        int err = -1;
-       struct perf_header *header;
-       struct perf_file_header f_header;
-       struct stat input_stat;
-       int input = open(input_name, O_RDONLY);
+       struct perf_session *session = perf_session__new(input_name, O_RDONLY, force);
 
-       if (input < 0) {
-               pr_err("failed to open file: %s", input_name);
-               if (!strcmp(input_name, "perf.data"))
-                       pr_err("  (try 'perf record' first)");
-               pr_err("\n");
-               goto out;
-       }
-
-       err = fstat(input, &input_stat);
-       if (err < 0) {
-               perror("failed to stat file");
-               goto out_close;
-       }
-
-       if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
-               pr_err("file %s not owned by current user or root\n",
-                      input_name);
-               goto out_close;
-       }
-
-       if (!input_stat.st_size) {
-               pr_info("zero-sized file, nothing to do!\n");
-               goto out_close;
-       }
-
-       err = -1;
-       header = perf_header__new();
-       if (header == NULL)
-               goto out_close;
-
-       if (perf_file_header__read(&f_header, header, input) < 0) {
-               pr_warning("incompatible file format");
-               goto out_close;
-       }
+       if (session == NULL)
+               return -1;
 
-       err = perf_header__process_sections(header, input,
+       err = perf_header__process_sections(&session->header, session->fd,
                                         perf_file_section__process_buildids);
+       if (err >= 0)
+               dsos__fprintf_buildid(stdout);
 
-       if (err < 0)
-               goto out_close;
-
-       dsos__fprintf_buildid(stdout);
-out_close:
-       close(input);
-out:
+       perf_session__delete(session);
        return err;
 }
 
index 5f209514f657262ef6d0f29159733136d37f9c90..2071d248591334f8acfe97802ab12e33b3bbbe30 100644 (file)
@@ -6,6 +6,7 @@
 #include "util/symbol.h"
 #include "util/thread.h"
 #include "util/header.h"
+#include "util/session.h"
 
 #include "util/parse-options.h"
 #include "util/trace-event.h"
@@ -20,7 +21,6 @@ typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *);
 
 static char const              *input_name = "perf.data";
 
-static struct perf_header      *header;
 static u64                     sample_type;
 
 static int                     alloc_flag;
@@ -367,11 +367,18 @@ static struct perf_file_handler file_handler = {
 
 static int read_events(void)
 {
+       int err;
+       struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
+
+       if (session == NULL)
+               return -ENOMEM;
+
        register_idle_thread();
        register_perf_file_handler(&file_handler);
 
-       return mmap_dispatch_perf_file(&header, input_name, 0, 0,
-                                      &event__cwdlen, &event__cwd);
+       err = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd);
+       perf_session__delete(session);
+       return err;
 }
 
 static double fragmentation(unsigned long n_req, unsigned long n_alloc)
@@ -403,7 +410,7 @@ static void __print_result(struct rb_root *root, int n_lines, int is_caller)
                if (is_caller) {
                        addr = data->call_site;
                        if (!raw_ip)
-                               sym = thread__find_function(kthread, addr, NULL);
+                               sym = map_groups__find_function(kmaps, addr, NULL);
                } else
                        addr = data->ptr;
 
index 0e519c667e3ac47f8fe9576575f62dc7b1991d83..4decbd14eaed080ac046b8a10c793b721280c1df 100644 (file)
@@ -17,6 +17,7 @@
 #include "util/header.h"
 #include "util/event.h"
 #include "util/debug.h"
+#include "util/session.h"
 #include "util/symbol.h"
 
 #include <unistd.h>
@@ -62,7 +63,7 @@ static int                    nr_cpu                          =      0;
 
 static int                     file_new                        =      1;
 
-struct perf_header             *header                         =   NULL;
+static struct perf_session     *session;
 
 struct mmap_data {
        int                     counter;
@@ -216,12 +217,12 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n
 {
        struct perf_header_attr *h_attr;
 
-       if (nr < header->attrs) {
-               h_attr = header->attr[nr];
+       if (nr < session->header.attrs) {
+               h_attr = session->header.attr[nr];
        } else {
                h_attr = perf_header_attr__new(a);
                if (h_attr != NULL)
-                       if (perf_header__add_attr(header, h_attr) < 0) {
+                       if (perf_header__add_attr(&session->header, h_attr) < 0) {
                                perf_header_attr__delete(h_attr);
                                h_attr = NULL;
                        }
@@ -395,9 +396,9 @@ static void open_counters(int cpu, pid_t pid)
 
 static void atexit_header(void)
 {
-       header->data_size += bytes_written;
+       session->header.data_size += bytes_written;
 
-       perf_header__write(header, output, true);
+       perf_header__write(&session->header, output, true);
 }
 
 static int __cmd_record(int argc, const char **argv)
@@ -440,24 +441,24 @@ static int __cmd_record(int argc, const char **argv)
                exit(-1);
        }
 
-       header = perf_header__new();
-       if (header == NULL) {
+       session = perf_session__new(output_name, O_WRONLY, force);
+       if (session == NULL) {
                pr_err("Not enough memory for reading perf file header\n");
                return -1;
        }
 
        if (!file_new) {
-               err = perf_header__read(header, output);
+               err = perf_header__read(&session->header, output);
                if (err < 0)
                        return err;
        }
 
        if (raw_samples) {
-               perf_header__set_feat(header, HEADER_TRACE_INFO);
+               perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
        } else {
                for (i = 0; i < nr_counters; i++) {
                        if (attrs[i].sample_type & PERF_SAMPLE_RAW) {
-                               perf_header__set_feat(header, HEADER_TRACE_INFO);
+                               perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
                                break;
                        }
                }
@@ -481,7 +482,7 @@ static int __cmd_record(int argc, const char **argv)
        }
 
        if (file_new) {
-               err = perf_header__write(header, output, false);
+               err = perf_header__write(&session->header, output, false);
                if (err < 0)
                        return err;
        }
index 2b9eb3a553edb7a72700dca28cb71f321b0b7edd..e2ec49a9b731eab6bb2de7419680107433b7b697 100644 (file)
@@ -22,6 +22,7 @@
 #include "perf.h"
 #include "util/debug.h"
 #include "util/header.h"
+#include "util/session.h"
 
 #include "util/parse-options.h"
 #include "util/parse-events.h"
@@ -52,7 +53,7 @@ static int            exclude_other = 1;
 
 static char            callchain_default_opt[] = "fractal,0.5";
 
-static struct perf_header *header;
+static struct perf_session *session;
 
 static u64             sample_type;
 
@@ -701,7 +702,7 @@ static int process_read_event(event_t *event)
 {
        struct perf_event_attr *attr;
 
-       attr = perf_header__find_attr(event->read.id, header);
+       attr = perf_header__find_attr(event->read.id, &session->header);
 
        if (show_threads) {
                const char *name = attr ? __event_name(attr->type, attr->config)
@@ -766,6 +767,10 @@ static int __cmd_report(void)
        struct thread *idle;
        int ret;
 
+       session = perf_session__new(input_name, O_RDONLY, force);
+       if (session == NULL)
+               return -ENOMEM;
+
        idle = register_idle_thread();
        thread__comm_adjust(idle);
 
@@ -774,14 +779,14 @@ static int __cmd_report(void)
 
        register_perf_file_handler(&file_handler);
 
-       ret = mmap_dispatch_perf_file(&header, input_name, force,
-                                     full_paths, &event__cwdlen, &event__cwd);
+       ret = perf_session__process_events(session, full_paths,
+                                          &event__cwdlen, &event__cwd);
        if (ret)
-               return ret;
+               goto out_delete;
 
        if (dump_trace) {
                event__print_totals();
-               return 0;
+               goto out_delete;
        }
 
        if (verbose > 3)
@@ -796,7 +801,8 @@ static int __cmd_report(void)
 
        if (show_threads)
                perf_read_values_destroy(&show_threads_values);
-
+out_delete:
+       perf_session__delete(session);
        return ret;
 }
 
index 7cca7c15b40ae1b129a2ed6c0db14752517d1d64..65021fe1361e0ae712614fcf0d966d89fcb8789e 100644 (file)
@@ -6,6 +6,7 @@
 #include "util/symbol.h"
 #include "util/thread.h"
 #include "util/header.h"
+#include "util/session.h"
 
 #include "util/parse-options.h"
 #include "util/trace-event.h"
@@ -21,7 +22,6 @@
 
 static char                    const *input_name = "perf.data";
 
-static struct perf_header      *header;
 static u64                     sample_type;
 
 static char                    default_sort_order[] = "avg, max, switch, runtime";
@@ -1663,11 +1663,18 @@ static struct perf_file_handler file_handler = {
 
 static int read_events(void)
 {
+       int err;
+       struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
+
+       if (session == NULL)
+               return -ENOMEM;
+
        register_idle_thread();
        register_perf_file_handler(&file_handler);
 
-       return mmap_dispatch_perf_file(&header, input_name, 0, 0,
-                                      &event__cwdlen, &event__cwd);
+       err = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd);
+       perf_session__delete(session);
+       return err;
 }
 
 static void print_bad_events(void)
index f472df9561ee8aa972b8c9a540b0c3bf3b5159ed..759dd2b35fdbce539944627043b0922b7b711982 100644 (file)
@@ -1059,15 +1059,17 @@ static struct perf_file_handler file_handler = {
 
 static int __cmd_timechart(void)
 {
-       struct perf_header *header;
+       struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
        int ret;
 
+       if (session == NULL)
+               return -ENOMEM;
+
        register_perf_file_handler(&file_handler);
 
-       ret = mmap_dispatch_perf_file(&header, input_name, 0, 0,
-                                     &event__cwdlen, &event__cwd);
+       ret = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd);
        if (ret)
-               return EXIT_FAILURE;
+               goto out_delete;
 
        process_samples();
 
@@ -1079,8 +1081,9 @@ static int __cmd_timechart(void)
 
        pr_info("Written %2.1f seconds of trace to %s.\n",
                (last_time - first_time) / 1000000000.0, output_name);
-
-       return EXIT_SUCCESS;
+out_delete:
+       perf_session__delete(session);
+       return ret;
 }
 
 static const char * const timechart_usage[] = {
index c2fcc34486f5c7447b6c5030c8144b35b7bd2d68..0756664666f1021289ac3f610bc06ab685ecac12 100644 (file)
@@ -7,6 +7,7 @@
 #include "util/header.h"
 #include "util/exec_cmd.h"
 #include "util/trace-event.h"
+#include "util/session.h"
 
 static char const              *script_name;
 static char const              *generate_script_lang;
@@ -61,7 +62,7 @@ static int cleanup_scripting(void)
 
 static char const              *input_name = "perf.data";
 
-static struct perf_header      *header;
+static struct perf_session     *session;
 static u64                     sample_type;
 
 static int process_sample_event(event_t *event)
@@ -126,11 +127,18 @@ static struct perf_file_handler file_handler = {
 
 static int __cmd_trace(void)
 {
+       int err;
+
+       session = perf_session__new(input_name, O_RDONLY, 0);
+       if (session == NULL)
+               return -ENOMEM;
+
        register_idle_thread();
        register_perf_file_handler(&file_handler);
 
-       return mmap_dispatch_perf_file(&header, input_name,
-                                      0, 0, &event__cwdlen, &event__cwd);
+       err = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd);
+       perf_session__delete(session);
+       return err;
 }
 
 struct script_spec {
@@ -348,11 +356,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
                        return -1;
                }
 
-               header = perf_header__new();
-               if (header == NULL)
-                       return -1;
-
-               perf_header__read(header, input);
+               perf_header__read(&session->header, input);
                err = scripting_ops->generate_script("perf-trace");
                goto out;
        }
index 454d5d55f32d9cb30d8206c6f03bfe1e0b5f61fb..75f941bfba9eb897b0bdd3075a450425536ac74c 100644 (file)
 #define cpu_relax()    asm volatile ("hint @pause" ::: "memory")
 #endif
 
+#ifdef __arm__
+#include "../../arch/arm/include/asm/unistd.h"
+/*
+ * Use the __kuser_memory_barrier helper in the CPU helper page. See
+ * arch/arm/kernel/entry-armv.S in the kernel source for details.
+ */
+#define rmb()          asm volatile("mov r0, #0xffff0fff; mov lr, pc;" \
+                                    "sub pc, r0, #95" ::: "r0", "lr", "cc", \
+                                    "memory")
+#define cpu_relax()    asm volatile("":::"memory")
+#endif
+
 #include <time.h>
 #include <unistd.h>
 #include <sys/types.h>
index 59b65d0bd7c1c175225c25041d4e3c535cd3cc01..6d46dda53a29db2fe73c8ddeb22ffd8f0648b034 100644 (file)
@@ -129,23 +129,16 @@ out:
        return err;
 }
 
-int mmap_dispatch_perf_file(struct perf_header **pheader,
-                           const char *input_name,
-                           int force,
-                           int full_paths,
-                           int *cwdlen,
-                           char **cwd)
+int perf_session__process_events(struct perf_session *self,
+                                int full_paths, int *cwdlen, char **cwd)
 {
        int err;
-       struct perf_header *header;
        unsigned long head, shift;
        unsigned long offset = 0;
-       struct stat input_stat;
        size_t  page_size;
        u64 sample_type;
        event_t *event;
        uint32_t size;
-       int input;
        char *buf;
 
        if (curr_handler == NULL) {
@@ -155,56 +148,19 @@ int mmap_dispatch_perf_file(struct perf_header **pheader,
 
        page_size = getpagesize();
 
-       input = open(input_name, O_RDONLY);
-       if (input < 0) {
-               pr_err("Failed to open file: %s", input_name);
-               if (!strcmp(input_name, "perf.data"))
-                       pr_err("  (try 'perf record' first)");
-               pr_err("\n");
-               return -errno;
-       }
-
-       if (fstat(input, &input_stat) < 0) {
-               pr_err("failed to stat file");
-               err = -errno;
-               goto out_close;
-       }
-
-       err = -EACCES;
-       if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
-               pr_err("file: %s not owned by current user or root\n",
-                       input_name);
-               goto out_close;
-       }
-
-       if (input_stat.st_size == 0) {
-               pr_info("zero-sized file, nothing to do!\n");
-               goto done;
-       }
-
-       err = -ENOMEM;
-       header = perf_header__new();
-       if (header == NULL)
-               goto out_close;
-
-       err = perf_header__read(header, input);
-       if (err < 0)
-               goto out_delete;
-       *pheader = header;
-       head = header->data_offset;
-
-       sample_type = perf_header__sample_type(header);
+       head = self->header.data_offset;
+       sample_type = perf_header__sample_type(&self->header);
 
        err = -EINVAL;
        if (curr_handler->sample_type_check &&
            curr_handler->sample_type_check(sample_type) < 0)
-               goto out_delete;
+               goto out_err;
 
        if (!full_paths) {
                if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
                        pr_err("failed to get the current directory\n");
                        err = -errno;
-                       goto out_delete;
+                       goto out_err;
                }
                *cwd = __cwd;
                *cwdlen = strlen(*cwd);
@@ -219,11 +175,11 @@ int mmap_dispatch_perf_file(struct perf_header **pheader,
 
 remap:
        buf = mmap(NULL, page_size * mmap_window, PROT_READ,
-                  MAP_SHARED, input, offset);
+                  MAP_SHARED, self->fd, offset);
        if (buf == MAP_FAILED) {
                pr_err("failed to mmap file\n");
                err = -errno;
-               goto out_delete;
+               goto out_err;
        }
 
 more:
@@ -273,19 +229,14 @@ more:
 
        head += size;
 
-       if (offset + head >= header->data_offset + header->data_size)
+       if (offset + head >= self->header.data_offset + self->header.data_size)
                goto done;
 
-       if (offset + head < (unsigned long)input_stat.st_size)
+       if (offset + head < self->size)
                goto more;
 
 done:
        err = 0;
-out_close:
-       close(input);
-
+out_err:
        return err;
-out_delete:
-       perf_header__delete(header);
-       goto out_close;
 }
index 258a87bcc4fbfc44c40fb35019b71b0cce0212b7..98c5b823388cd3efe8c84582433230ce273b73c5 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "event.h"
 #include "header.h"
+#include "session.h"
 
 typedef int (*event_type_handler_t)(event_t *);
 
@@ -21,12 +22,8 @@ struct perf_file_handler {
 };
 
 void register_perf_file_handler(struct perf_file_handler *handler);
-int mmap_dispatch_perf_file(struct perf_header **pheader,
-                           const char *input_name,
-                           int force,
-                           int full_paths,
-                           int *cwdlen,
-                           char **cwd);
+int perf_session__process_events(struct perf_session *self,
+                                int full_paths, int *cwdlen, char **cwd);
 int perf_header__read_build_ids(int input, u64 offset, u64 file_size);
 
 #endif
index 4dcecafa85dcbcbc849853562603dbf1d7957191..ba0de90cd3d4ea6163f699233845fea5fb2b6976 100644 (file)
@@ -254,13 +254,14 @@ void thread__find_addr_location(struct thread *self, u8 cpumode,
                                struct addr_location *al,
                                symbol_filter_t filter)
 {
-       struct thread *thread = al->thread = self;
+       struct map_groups *mg = &self->mg;
 
+       al->thread = self;
        al->addr = addr;
 
        if (cpumode & PERF_RECORD_MISC_KERNEL) {
                al->level = 'k';
-               thread = kthread;
+               mg = kmaps;
        } else if (cpumode & PERF_RECORD_MISC_USER)
                al->level = '.';
        else {
@@ -270,7 +271,7 @@ void thread__find_addr_location(struct thread *self, u8 cpumode,
                return;
        }
 try_again:
-       al->map = thread__find_map(thread, type, al->addr);
+       al->map = map_groups__find(mg, type, al->addr);
        if (al->map == NULL) {
                /*
                 * If this is outside of all known maps, and is a negative
@@ -281,8 +282,8 @@ try_again:
                 * "[vdso]" dso, but for now lets use the old trick of looking
                 * in the whole kernel symbol list.
                 */
-               if ((long long)al->addr < 0 && thread != kthread) {
-                       thread = kthread;
+               if ((long long)al->addr < 0 && mg != kmaps) {
+                       mg = kmaps;
                        goto try_again;
                }
                al->sym = NULL;
index c7a78eef8e52cc60345c84b9a174e44cff9d7615..51a96c2effdea662c4a77e5b5a2ed3cde1e61b64 100644 (file)
@@ -103,10 +103,11 @@ void event__print_totals(void);
 
 enum map_type {
        MAP__FUNCTION = 0,
-
-       MAP__NR_TYPES,
+       MAP__VARIABLE,
 };
 
+#define MAP__NR_TYPES (MAP__VARIABLE + 1)
+
 struct map {
        union {
                struct rb_node  rb_node;
@@ -150,6 +151,8 @@ int map__overlap(struct map *l, struct map *r);
 size_t map__fprintf(struct map *self, FILE *fp);
 struct symbol *map__find_symbol(struct map *self, u64 addr,
                                symbol_filter_t filter);
+struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
+                                       symbol_filter_t filter);
 void map__fixup_start(struct map *self);
 void map__fixup_end(struct map *self);
 
index 59a9c0b3033e12352ad0754a0f3cfcb5aaeac3c5..f2e8d87151116c94a78868ba580e56be24382264 100644 (file)
@@ -58,35 +58,19 @@ int perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
        return 0;
 }
 
-/*
- * Create new perf.data header:
- */
-struct perf_header *perf_header__new(void)
+int perf_header__init(struct perf_header *self)
 {
-       struct perf_header *self = zalloc(sizeof(*self));
-
-       if (self != NULL) {
-               self->size = 1;
-               self->attr = malloc(sizeof(void *));
-
-               if (self->attr == NULL) {
-                       free(self);
-                       self = NULL;
-               }
-       }
-
-       return self;
+       self->size = 1;
+       self->attr = malloc(sizeof(void *));
+       return self->attr == NULL ? -ENOMEM : 0;
 }
 
-void perf_header__delete(struct perf_header *self)
+void perf_header__exit(struct perf_header *self)
 {
        int i;
-
        for (i = 0; i < self->attrs; ++i)
-               perf_header_attr__delete(self->attr[i]);
-
+                perf_header_attr__delete(self->attr[i]);
        free(self->attr);
-       free(self);
 }
 
 int perf_header__add_attr(struct perf_header *self,
index d1dbe2b79c42bfcbf9a3e90e965076b6a5afc075..d118d05d3abe772f1feeb0fb1d425d75de687df0 100644 (file)
@@ -55,8 +55,8 @@ struct perf_header {
        DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
 };
 
-struct perf_header *perf_header__new(void);
-void perf_header__delete(struct perf_header *self);
+int perf_header__init(struct perf_header *self);
+void perf_header__exit(struct perf_header *self);
 
 int perf_header__read(struct perf_header *self, int fd);
 int perf_header__write(struct perf_header *self, int fd, bool at_exit);
index 69f94fe9db20a059e4e00f687bd109a543c7d0e0..76bdca640a9b5fcde2f7206f39940dc23e4750e8 100644 (file)
@@ -104,43 +104,64 @@ void map__fixup_end(struct map *self)
 
 #define DSO__DELETED "(deleted)"
 
-struct symbol *map__find_symbol(struct map *self, u64 addr,
-                               symbol_filter_t filter)
+static int map__load(struct map *self, symbol_filter_t filter)
 {
-       if (!dso__loaded(self->dso, self->type)) {
-               int nr = dso__load(self->dso, self, filter);
-
-               if (nr < 0) {
-                       if (self->dso->has_build_id) {
-                               char sbuild_id[BUILD_ID_SIZE * 2 + 1];
-
-                               build_id__sprintf(self->dso->build_id,
-                                                 sizeof(self->dso->build_id),
-                                                 sbuild_id);
-                               pr_warning("%s with build id %s not found",
-                                          self->dso->long_name, sbuild_id);
-                       } else
-                               pr_warning("Failed to open %s",
-                                          self->dso->long_name);
-                       pr_warning(", continuing without symbols\n");
-                       return NULL;
-               } else if (nr == 0) {
-                       const char *name = self->dso->long_name;
-                       const size_t len = strlen(name);
-                       const size_t real_len = len - sizeof(DSO__DELETED);
-
-                       if (len > sizeof(DSO__DELETED) &&
-                           strcmp(name + real_len + 1, DSO__DELETED) == 0) {
-                               pr_warning("%.*s was updated, restart the long running apps that use it!\n",
-                                          (int)real_len, name);
-                       } else {
-                               pr_warning("no symbols found in %s, maybe install a debug package?\n", name);
-                       }
-                       return NULL;
+       const char *name = self->dso->long_name;
+       int nr = dso__load(self->dso, self, filter);
+
+       if (nr < 0) {
+               if (self->dso->has_build_id) {
+                       char sbuild_id[BUILD_ID_SIZE * 2 + 1];
+
+                       build_id__sprintf(self->dso->build_id,
+                                         sizeof(self->dso->build_id),
+                                         sbuild_id);
+                       pr_warning("%s with build id %s not found",
+                                  name, sbuild_id);
+               } else
+                       pr_warning("Failed to open %s", name);
+
+               pr_warning(", continuing without symbols\n");
+               return -1;
+       } else if (nr == 0) {
+               const size_t len = strlen(name);
+               const size_t real_len = len - sizeof(DSO__DELETED);
+
+               if (len > sizeof(DSO__DELETED) &&
+                   strcmp(name + real_len + 1, DSO__DELETED) == 0) {
+                       pr_warning("%.*s was updated, restart the long "
+                                  "running apps that use it!\n",
+                                  (int)real_len, name);
+               } else {
+                       pr_warning("no symbols found in %s, maybe install "
+                                  "a debug package?\n", name);
                }
+
+               return -1;
        }
 
-       return self->dso->find_symbol(self->dso, self->type, addr);
+       return 0;
+}
+
+struct symbol *map__find_symbol(struct map *self, u64 addr,
+                               symbol_filter_t filter)
+{
+       if (!dso__loaded(self->dso, self->type) && map__load(self, filter) < 0)
+               return NULL;
+
+       return dso__find_symbol(self->dso, self->type, addr);
+}
+
+struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
+                                       symbol_filter_t filter)
+{
+       if (!dso__loaded(self->dso, self->type) && map__load(self, filter) < 0)
+               return NULL;
+
+       if (!dso__sorted_by_name(self->dso, self->type))
+               dso__sort_by_name(self->dso, self->type);
+
+       return dso__find_symbol_by_name(self->dso, self->type, name);
 }
 
 struct map *map__clone(struct map *self)
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
new file mode 100644 (file)
index 0000000..707ce1c
--- /dev/null
@@ -0,0 +1,80 @@
+#include <linux/kernel.h>
+
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "session.h"
+#include "util.h"
+
+static int perf_session__open(struct perf_session *self, bool force)
+{
+       struct stat input_stat;
+
+       self->fd = open(self->filename, O_RDONLY);
+       if (self->fd < 0) {
+               pr_err("failed to open file: %s", self->filename);
+               if (!strcmp(self->filename, "perf.data"))
+                       pr_err("  (try 'perf record' first)");
+               pr_err("\n");
+               return -errno;
+       }
+
+       if (fstat(self->fd, &input_stat) < 0)
+               goto out_close;
+
+       if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
+               pr_err("file %s not owned by current user or root\n",
+                      self->filename);
+               goto out_close;
+       }
+
+       if (!input_stat.st_size) {
+               pr_info("zero-sized file (%s), nothing to do!\n",
+                       self->filename);
+               goto out_close;
+       }
+
+       if (perf_header__read(&self->header, self->fd) < 0) {
+               pr_err("incompatible file format");
+               goto out_close;
+       }
+
+       self->size = input_stat.st_size;
+       return 0;
+
+out_close:
+       close(self->fd);
+       self->fd = -1;
+       return -1;
+}
+
+struct perf_session *perf_session__new(const char *filename, int mode, bool force)
+{
+       size_t len = strlen(filename) + 1;
+       struct perf_session *self = zalloc(sizeof(*self) + len);
+
+       if (self == NULL)
+               goto out;
+
+       if (perf_header__init(&self->header) < 0)
+               goto out_delete;
+
+       memcpy(self->filename, filename, len);
+
+       if (mode == O_RDONLY && perf_session__open(self, force) < 0) {
+               perf_session__delete(self);
+               self = NULL;
+       }
+out:
+       return self;
+out_delete:
+       free(self);
+       return NULL;
+}
+
+void perf_session__delete(struct perf_session *self)
+{
+       perf_header__exit(&self->header);
+       close(self->fd);
+       free(self);
+}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
new file mode 100644 (file)
index 0000000..f3699c8
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef __PERF_SESSION_H
+#define __PERF_SESSION_H
+
+#include "header.h"
+
+struct perf_session {
+       struct perf_header      header;
+       unsigned long           size;
+       int                     fd;
+       char filename[0];
+};
+
+struct perf_session *perf_session__new(const char *filename, int mode, bool force);
+void perf_session__delete(struct perf_session *self);
+
+#endif /* __PERF_SESSION_H */
index e7508ad3450f7200ee9c8a5eec594d91d143b399..d3d9fed74f1dbcb56fc1ba66aa5cbc09e53e426c 100644 (file)
@@ -29,11 +29,9 @@ enum dso_origin {
 };
 
 static void dsos__add(struct list_head *head, struct dso *dso);
-static struct map *thread__find_map_by_name(struct thread *self, char *name);
 static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
-struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr);
 static int dso__load_kernel_sym(struct dso *self, struct map *map,
-                               struct thread *thread, symbol_filter_t filter);
+                               struct map_groups *mg, symbol_filter_t filter);
 unsigned int symbol__priv_size;
 static int vmlinux_path__nr_entries;
 static char **vmlinux_path;
@@ -43,19 +41,41 @@ static struct symbol_conf symbol_conf__defaults = {
        .try_vmlinux_path = true,
 };
 
-static struct thread kthread_mem;
-struct thread *kthread = &kthread_mem;
+static struct map_groups kmaps_mem;
+struct map_groups *kmaps = &kmaps_mem;
 
 bool dso__loaded(const struct dso *self, enum map_type type)
 {
        return self->loaded & (1 << type);
 }
 
+bool dso__sorted_by_name(const struct dso *self, enum map_type type)
+{
+       return self->sorted_by_name & (1 << type);
+}
+
 static void dso__set_loaded(struct dso *self, enum map_type type)
 {
        self->loaded |= (1 << type);
 }
 
+static void dso__set_sorted_by_name(struct dso *self, enum map_type type)
+{
+       self->sorted_by_name |= (1 << type);
+}
+
+static bool symbol_type__is_a(char symbol_type, enum map_type map_type)
+{
+       switch (map_type) {
+       case MAP__FUNCTION:
+               return symbol_type == 'T' || symbol_type == 'W';
+       case MAP__VARIABLE:
+               return symbol_type == 'D' || symbol_type == 'd';
+       default:
+               return false;
+       }
+}
+
 static void symbols__fixup_end(struct rb_root *self)
 {
        struct rb_node *nd, *prevnd = rb_first(self);
@@ -79,7 +99,7 @@ static void symbols__fixup_end(struct rb_root *self)
                curr->end = roundup(curr->start, 4096);
 }
 
-static void __thread__fixup_maps_end(struct thread *self, enum map_type type)
+static void __map_groups__fixup_end(struct map_groups *self, enum map_type type)
 {
        struct map *prev, *curr;
        struct rb_node *nd, *prevnd = rb_first(&self->maps[type]);
@@ -102,11 +122,11 @@ static void __thread__fixup_maps_end(struct thread *self, enum map_type type)
        curr->end = ~0UL;
 }
 
-static void thread__fixup_maps_end(struct thread *self)
+static void map_groups__fixup_end(struct map_groups *self)
 {
        int i;
        for (i = 0; i < MAP__NR_TYPES; ++i)
-               __thread__fixup_maps_end(self, i);
+               __map_groups__fixup_end(self, i);
 }
 
 static struct symbol *symbol__new(u64 start, u64 len, const char *name)
@@ -164,11 +184,11 @@ struct dso *dso__new(const char *name)
                dso__set_long_name(self, self->name);
                self->short_name = self->name;
                for (i = 0; i < MAP__NR_TYPES; ++i)
-                       self->symbols[i] = RB_ROOT;
-               self->find_symbol = dso__find_symbol;
+                       self->symbols[i] = self->symbol_names[i] = RB_ROOT;
                self->slen_calculated = 0;
                self->origin = DSO__ORIG_NOT_FOUND;
                self->loaded = 0;
+               self->sorted_by_name = 0;
                self->has_build_id = 0;
        }
 
@@ -246,11 +266,85 @@ static struct symbol *symbols__find(struct rb_root *self, u64 ip)
        return NULL;
 }
 
-struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr)
+struct symbol_name_rb_node {
+       struct rb_node  rb_node;
+       struct symbol   sym;
+};
+
+static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym)
+{
+       struct rb_node **p = &self->rb_node;
+       struct rb_node *parent = NULL;
+       struct symbol_name_rb_node *symn = ((void *)sym) - sizeof(*parent), *s;
+
+       while (*p != NULL) {
+               parent = *p;
+               s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
+               if (strcmp(sym->name, s->sym.name) < 0)
+                       p = &(*p)->rb_left;
+               else
+                       p = &(*p)->rb_right;
+       }
+       rb_link_node(&symn->rb_node, parent, p);
+       rb_insert_color(&symn->rb_node, self);
+}
+
+static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source)
+{
+       struct rb_node *nd;
+
+       for (nd = rb_first(source); nd; nd = rb_next(nd)) {
+               struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
+               symbols__insert_by_name(self, pos);
+       }
+}
+
+static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name)
+{
+       struct rb_node *n;
+
+       if (self == NULL)
+               return NULL;
+
+       n = self->rb_node;
+
+       while (n) {
+               struct symbol_name_rb_node *s;
+               int cmp;
+
+               s = rb_entry(n, struct symbol_name_rb_node, rb_node);
+               cmp = strcmp(name, s->sym.name);
+
+               if (cmp < 0)
+                       n = n->rb_left;
+               else if (cmp > 0)
+                       n = n->rb_right;
+               else
+                       return &s->sym;
+       }
+
+       return NULL;
+}
+
+struct symbol *dso__find_symbol(struct dso *self,
+                               enum map_type type, u64 addr)
 {
        return symbols__find(&self->symbols[type], addr);
 }
 
+struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
+                                       const char *name)
+{
+       return symbols__find_by_name(&self->symbol_names[type], name);
+}
+
+void dso__sort_by_name(struct dso *self, enum map_type type)
+{
+       dso__set_sorted_by_name(self, type);
+       return symbols__sort_by_name(&self->symbol_names[type],
+                                    &self->symbols[type]);
+}
+
 int build_id__sprintf(u8 *self, int len, char *bf)
 {
        char *bid = bf;
@@ -327,10 +421,7 @@ static int dso__load_all_kallsyms(struct dso *self, struct map *map)
                        continue;
 
                symbol_type = toupper(line[len]);
-               /*
-                * We're interested only in code ('T'ext)
-                */
-               if (symbol_type != 'T' && symbol_type != 'W')
+               if (!symbol_type__is_a(symbol_type, map->type))
                        continue;
 
                symbol_name = line + len + 2;
@@ -364,8 +455,8 @@ out_failure:
  * kernel range is broken in several maps, named [kernel].N, as we don't have
  * the original ELF section names vmlinux have.
  */
-static int dso__split_kallsyms(struct dso *self, struct map *map, struct thread *thread,
-                              symbol_filter_t filter)
+static int dso__split_kallsyms(struct dso *self, struct map *map,
+                              struct map_groups *mg, symbol_filter_t filter)
 {
        struct map *curr_map = map;
        struct symbol *pos;
@@ -382,13 +473,13 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, struct thread
 
                module = strchr(pos->name, '\t');
                if (module) {
-                       if (!thread->use_modules)
+                       if (!mg->use_modules)
                                goto discard_symbol;
 
                        *module++ = '\0';
 
                        if (strcmp(self->name, module)) {
-                               curr_map = thread__find_map_by_name(thread, module);
+                               curr_map = map_groups__find_by_name(mg, map->type, module);
                                if (curr_map == NULL) {
                                        pr_debug("/proc/{kallsyms,modules} "
                                                 "inconsistency!\n");
@@ -419,7 +510,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, struct thread
                        }
 
                        curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
-                       __thread__insert_map(thread, curr_map);
+                       map_groups__insert(mg, curr_map);
                        ++kernel_range;
                }
 
@@ -440,7 +531,7 @@ discard_symbol:             rb_erase(&pos->rb_node, root);
 
 
 static int dso__load_kallsyms(struct dso *self, struct map *map,
-                             struct thread *thread, symbol_filter_t filter)
+                             struct map_groups *mg, symbol_filter_t filter)
 {
        if (dso__load_all_kallsyms(self, map) < 0)
                return -1;
@@ -448,13 +539,13 @@ static int dso__load_kallsyms(struct dso *self, struct map *map,
        symbols__fixup_end(&self->symbols[map->type]);
        self->origin = DSO__ORIG_KERNEL;
 
-       return dso__split_kallsyms(self, map, thread, filter);
+       return dso__split_kallsyms(self, map, mg, filter);
 }
 
 size_t kernel_maps__fprintf(FILE *fp)
 {
        size_t printed = fprintf(fp, "Kernel maps:\n");
-       printed += thread__fprintf_maps(kthread, fp);
+       printed += map_groups__fprintf_maps(kmaps, fp);
        return printed + fprintf(fp, "END kernel maps\n");
 }
 
@@ -544,6 +635,13 @@ static inline int elf_sym__is_function(const GElf_Sym *sym)
               sym->st_shndx != SHN_UNDEF;
 }
 
+static inline bool elf_sym__is_object(const GElf_Sym *sym)
+{
+       return elf_sym__type(sym) == STT_OBJECT &&
+               sym->st_name != 0 &&
+               sym->st_shndx != SHN_UNDEF;
+}
+
 static inline int elf_sym__is_label(const GElf_Sym *sym)
 {
        return elf_sym__type(sym) == STT_NOTYPE &&
@@ -564,6 +662,12 @@ static inline int elf_sec__is_text(const GElf_Shdr *shdr,
        return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
 }
 
+static inline bool elf_sec__is_data(const GElf_Shdr *shdr,
+                                   const Elf_Data *secstrs)
+{
+       return strstr(elf_sec__name(shdr, secstrs), "data") != NULL;
+}
+
 static inline const char *elf_sym__name(const GElf_Sym *sym,
                                        const Elf_Data *symstrs)
 {
@@ -744,8 +848,32 @@ out:
        return 0;
 }
 
+static bool elf_sym__is_a(GElf_Sym *self, enum map_type type)
+{
+       switch (type) {
+       case MAP__FUNCTION:
+               return elf_sym__is_function(self);
+       case MAP__VARIABLE:
+               return elf_sym__is_object(self);
+       default:
+               return false;
+       }
+}
+
+static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type)
+{
+       switch (type) {
+       case MAP__FUNCTION:
+               return elf_sec__is_text(self, secstrs);
+       case MAP__VARIABLE:
+               return elf_sec__is_data(self, secstrs);
+       default:
+               return false;
+       }
+}
+
 static int dso__load_sym(struct dso *self, struct map *map,
-                        struct thread *thread, const char *name, int fd,
+                        struct map_groups *mg, const char *name, int fd,
                         symbol_filter_t filter, int kernel, int kmodule)
 {
        struct map *curr_map = map;
@@ -818,7 +946,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
                int is_label = elf_sym__is_label(&sym);
                const char *section_name;
 
-               if (!is_label && !elf_sym__is_function(&sym))
+               if (!is_label && !elf_sym__is_a(&sym, map->type))
                        continue;
 
                sec = elf_getscn(elf, sym.st_shndx);
@@ -827,7 +955,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
 
                gelf_getshdr(sec, &shdr);
 
-               if (is_label && !elf_sec__is_text(&shdr, secstrs))
+               if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
                        continue;
 
                elf_name = elf_sym__name(&sym, symstrs);
@@ -849,7 +977,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
                        snprintf(dso_name, sizeof(dso_name),
                                 "%s%s", self->short_name, section_name);
 
-                       curr_map = thread__find_map_by_name(thread, dso_name);
+                       curr_map = map_groups__find_by_name(mg, map->type, dso_name);
                        if (curr_map == NULL) {
                                u64 start = sym.st_value;
 
@@ -868,7 +996,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
                                curr_map->map_ip = identity__map_ip;
                                curr_map->unmap_ip = identity__map_ip;
                                curr_dso->origin = DSO__ORIG_KERNEL;
-                               __thread__insert_map(kthread, curr_map);
+                               map_groups__insert(kmaps, curr_map);
                                dsos__add(&dsos__kernel, curr_dso);
                        } else
                                curr_dso = curr_map->dso;
@@ -1094,7 +1222,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
        dso__set_loaded(self, map->type);
 
        if (self->kernel)
-               return dso__load_kernel_sym(self, map, kthread, filter);
+               return dso__load_kernel_sym(self, map, kmaps, filter);
 
        name = malloc(size);
        if (!name)
@@ -1180,11 +1308,12 @@ out:
        return ret;
 }
 
-static struct map *thread__find_map_by_name(struct thread *self, char *name)
+struct map *map_groups__find_by_name(struct map_groups *self,
+                                    enum map_type type, const char *name)
 {
        struct rb_node *nd;
 
-       for (nd = rb_first(&self->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) {
+       for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
                struct map *map = rb_entry(nd, struct map, rb_node);
 
                if (map->dso && strcmp(map->dso->name, name) == 0)
@@ -1228,7 +1357,7 @@ static int dsos__set_modules_path_dir(char *dirname)
                                 (int)(dot - dent->d_name), dent->d_name);
 
                        strxfrchar(dso_name, '-', '_');
-                       map = thread__find_map_by_name(kthread, dso_name);
+                       map = map_groups__find_by_name(kmaps, MAP__FUNCTION, dso_name);
                        if (map == NULL)
                                continue;
 
@@ -1281,7 +1410,7 @@ static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
        return self;
 }
 
-static int thread__create_module_maps(struct thread *self)
+static int map_groups__create_module_maps(struct map_groups *self)
 {
        char *line = NULL;
        size_t n;
@@ -1338,7 +1467,7 @@ static int thread__create_module_maps(struct thread *self)
                        dso->has_build_id = true;
 
                dso->origin = DSO__ORIG_KMODULE;
-               __thread__insert_map(self, map);
+               map_groups__insert(self, map);
                dsos__add(&dsos__kernel, dso);
        }
 
@@ -1353,7 +1482,8 @@ out_failure:
        return -1;
 }
 
-static int dso__load_vmlinux(struct dso *self, struct map *map, struct thread *thread,
+static int dso__load_vmlinux(struct dso *self, struct map *map,
+                            struct map_groups *mg,
                             const char *vmlinux, symbol_filter_t filter)
 {
        int err = -1, fd;
@@ -1387,14 +1517,14 @@ static int dso__load_vmlinux(struct dso *self, struct map *map, struct thread *t
                return -1;
 
        dso__set_loaded(self, map->type);
-       err = dso__load_sym(self, map, thread, self->long_name, fd, filter, 1, 0);
+       err = dso__load_sym(self, map, mg, self->long_name, fd, filter, 1, 0);
        close(fd);
 
        return err;
 }
 
 static int dso__load_kernel_sym(struct dso *self, struct map *map,
-                               struct thread *thread, symbol_filter_t filter)
+                               struct map_groups *mg, symbol_filter_t filter)
 {
        int err;
        bool is_kallsyms;
@@ -1404,7 +1534,7 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
                pr_debug("Looking at the vmlinux_path (%d entries long)\n",
                         vmlinux_path__nr_entries);
                for (i = 0; i < vmlinux_path__nr_entries; ++i) {
-                       err = dso__load_vmlinux(self, map, thread,
+                       err = dso__load_vmlinux(self, map, mg,
                                                vmlinux_path[i], filter);
                        if (err > 0) {
                                pr_debug("Using %s for symbols\n",
@@ -1420,12 +1550,12 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
        if (is_kallsyms)
                goto do_kallsyms;
 
-       err = dso__load_vmlinux(self, map, thread, self->long_name, filter);
+       err = dso__load_vmlinux(self, map, mg, self->long_name, filter);
        if (err <= 0) {
                pr_info("The file %s cannot be used, "
                        "trying to use /proc/kallsyms...", self->long_name);
 do_kallsyms:
-               err = dso__load_kallsyms(self, map, thread, filter);
+               err = dso__load_kallsyms(self, map, mg, filter);
                if (err > 0 && !is_kallsyms)
                         dso__set_long_name(self, strdup("[kernel.kallsyms]"));
        }
@@ -1508,42 +1638,59 @@ size_t dsos__fprintf_buildid(FILE *fp)
                __dsos__fprintf_buildid(&dsos__user, fp));
 }
 
-static int thread__create_kernel_map(struct thread *self, const char *vmlinux)
+static struct dso *dsos__create_kernel( const char *vmlinux)
 {
-       struct map *kmap;
        struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]");
 
        if (kernel == NULL)
-               return -1;
-
-       kmap = map__new2(0, kernel, MAP__FUNCTION);
-       if (kmap == NULL)
-               goto out_delete_kernel_dso;
+               return NULL;
 
-       kmap->map_ip       = kmap->unmap_ip = identity__map_ip;
        kernel->short_name = "[kernel]";
        kernel->kernel     = 1;
 
        vdso = dso__new("[vdso]");
        if (vdso == NULL)
-               goto out_delete_kernel_map;
+               goto out_delete_kernel_dso;
        dso__set_loaded(vdso, MAP__FUNCTION);
 
        if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id,
                                 sizeof(kernel->build_id)) == 0)
                kernel->has_build_id = true;
 
-       __thread__insert_map(self, kmap);
        dsos__add(&dsos__kernel, kernel);
        dsos__add(&dsos__user, vdso);
 
-       return 0;
+       return kernel;
 
-out_delete_kernel_map:
-       map__delete(kmap);
 out_delete_kernel_dso:
        dso__delete(kernel);
-       return -1;
+       return NULL;
+}
+
+static int map_groups__create_kernel_maps(struct map_groups *self, const char *vmlinux)
+{
+       struct map *functions, *variables;
+       struct dso *kernel = dsos__create_kernel(vmlinux);
+
+       if (kernel == NULL)
+               return -1;
+
+       functions = map__new2(0, kernel, MAP__FUNCTION);
+       if (functions == NULL)
+               return -1;
+
+       variables = map__new2(0, kernel, MAP__VARIABLE);
+       if (variables == NULL) {
+               map__delete(functions);
+               return -1;
+       }
+
+       functions->map_ip = functions->unmap_ip =
+               variables->map_ip = variables->unmap_ip = identity__map_ip;
+       map_groups__insert(self, functions);
+       map_groups__insert(self, variables);
+
+       return 0;
 }
 
 static void vmlinux_path__exit(void)
@@ -1607,23 +1754,26 @@ int symbol__init(struct symbol_conf *conf)
 
        elf_version(EV_CURRENT);
        symbol__priv_size = pconf->priv_size;
-       thread__init(kthread, 0);
+       if (pconf->sort_by_name)
+               symbol__priv_size += (sizeof(struct symbol_name_rb_node) -
+                                     sizeof(struct symbol));
+       map_groups__init(kmaps);
 
        if (pconf->try_vmlinux_path && vmlinux_path__init() < 0)
                return -1;
 
-       if (thread__create_kernel_map(kthread, pconf->vmlinux_name) < 0) {
+       if (map_groups__create_kernel_maps(kmaps, pconf->vmlinux_name) < 0) {
                vmlinux_path__exit();
                return -1;
        }
 
-       kthread->use_modules = pconf->use_modules;
-       if (pconf->use_modules && thread__create_module_maps(kthread) < 0)
+       kmaps->use_modules = pconf->use_modules;
+       if (pconf->use_modules && map_groups__create_module_maps(kmaps) < 0)
                pr_debug("Failed to load list of modules in use, "
                         "continuing...\n");
        /*
         * Now that we have all the maps created, just set the ->end of them:
         */
-       thread__fixup_maps_end(kthread);
+       map_groups__fixup_end(kmaps);
        return 0;
 }
index 17003efa0b39ab072f6656109cddd434fe248d9a..cf99f88adf39c52d2010e8b6e0c580307dbc69fa 100644 (file)
@@ -52,7 +52,8 @@ struct symbol {
 struct symbol_conf {
        unsigned short  priv_size;
        bool            try_vmlinux_path,
-                       use_modules;
+                       use_modules,
+                       sort_by_name;
        const char      *vmlinux_name;
 };
 
@@ -74,13 +75,13 @@ struct addr_location {
 struct dso {
        struct list_head node;
        struct rb_root   symbols[MAP__NR_TYPES];
-       struct symbol    *(*find_symbol)(struct dso *self,
-                                        enum map_type type, u64 addr);
+       struct rb_root   symbol_names[MAP__NR_TYPES];
        u8               adjust_symbols:1;
        u8               slen_calculated:1;
        u8               has_build_id:1;
        u8               kernel:1;
        unsigned char    origin;
+       u8               sorted_by_name;
        u8               loaded;
        u8               build_id[BUILD_ID_SIZE];
        u16              long_name_len;
@@ -93,6 +94,9 @@ struct dso *dso__new(const char *name);
 void dso__delete(struct dso *self);
 
 bool dso__loaded(const struct dso *self, enum map_type type);
+bool dso__sorted_by_name(const struct dso *self, enum map_type type);
+
+void dso__sort_by_name(struct dso *self, enum map_type type);
 
 struct dso *dsos__findnew(const char *name);
 int dso__load(struct dso *self, struct map *map, symbol_filter_t filter);
@@ -103,6 +107,9 @@ size_t dso__fprintf_buildid(struct dso *self, FILE *fp);
 size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp);
 char dso__symtab_origin(const struct dso *self);
 void dso__set_build_id(struct dso *self, void *build_id);
+struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr);
+struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
+                                       const char *name);
 
 int filename__read_build_id(const char *filename, void *bf, size_t size);
 int sysfs__read_build_id(const char *filename, void *bf, size_t size);
@@ -113,8 +120,8 @@ size_t kernel_maps__fprintf(FILE *fp);
 
 int symbol__init(struct symbol_conf *conf);
 
-struct thread;
-struct thread *kthread;
+struct map_groups;
+struct map_groups *kmaps;
 extern struct list_head dsos__user, dsos__kernel;
 extern struct dso *vdso;
 #endif /* __PERF_SYMBOL */
index 603f5610861b841cc1a526dc1f1566a0c943d56f..b68a00ea41210cbb69a80d41794700d0bfaccb97 100644 (file)
@@ -9,11 +9,9 @@
 static struct rb_root threads;
 static struct thread *last_match;
 
-void thread__init(struct thread *self, pid_t pid)
+void map_groups__init(struct map_groups *self)
 {
        int i;
-       self->pid = pid;
-       self->comm = NULL;
        for (i = 0; i < MAP__NR_TYPES; ++i) {
                self->maps[i] = RB_ROOT;
                INIT_LIST_HEAD(&self->removed_maps[i]);
@@ -25,7 +23,8 @@ static struct thread *thread__new(pid_t pid)
        struct thread *self = zalloc(sizeof(*self));
 
        if (self != NULL) {
-               thread__init(self, pid);
+               map_groups__init(&self->mg);
+               self->pid = pid;
                self->comm = malloc(32);
                if (self->comm)
                        snprintf(self->comm, 32, ":%d", self->pid);
@@ -55,10 +54,11 @@ int thread__comm_len(struct thread *self)
 
 static const char *map_type__name[MAP__NR_TYPES] = {
        [MAP__FUNCTION] = "Functions",
+       [MAP__VARIABLE] = "Variables",
 };
 
-static size_t __thread__fprintf_maps(struct thread *self,
-                                    enum map_type type, FILE *fp)
+static size_t __map_groups__fprintf_maps(struct map_groups *self,
+                                        enum map_type type, FILE *fp)
 {
        size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
        struct rb_node *nd;
@@ -76,16 +76,16 @@ static size_t __thread__fprintf_maps(struct thread *self,
        return printed;
 }
 
-size_t thread__fprintf_maps(struct thread *self, FILE *fp)
+size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp)
 {
        size_t printed = 0, i;
        for (i = 0; i < MAP__NR_TYPES; ++i)
-               printed += __thread__fprintf_maps(self, i, fp);
+               printed += __map_groups__fprintf_maps(self, i, fp);
        return printed;
 }
 
-static size_t __thread__fprintf_removed_maps(struct thread *self,
-                                            enum map_type type, FILE *fp)
+static size_t __map_groups__fprintf_removed_maps(struct map_groups *self,
+                                                enum map_type type, FILE *fp)
 {
        struct map *pos;
        size_t printed = 0;
@@ -101,20 +101,25 @@ static size_t __thread__fprintf_removed_maps(struct thread *self,
        return printed;
 }
 
-static size_t thread__fprintf_removed_maps(struct thread *self, FILE *fp)
+static size_t map_groups__fprintf_removed_maps(struct map_groups *self, FILE *fp)
 {
        size_t printed = 0, i;
        for (i = 0; i < MAP__NR_TYPES; ++i)
-               printed += __thread__fprintf_removed_maps(self, i, fp);
+               printed += __map_groups__fprintf_removed_maps(self, i, fp);
        return printed;
 }
 
-static size_t thread__fprintf(struct thread *self, FILE *fp)
+static size_t map_groups__fprintf(struct map_groups *self, FILE *fp)
 {
-       size_t printed = fprintf(fp, "Thread %d %s\n", self->pid, self->comm);
-       printed += thread__fprintf_removed_maps(self, fp);
+       size_t printed = map_groups__fprintf_maps(self, fp);
        printed += fprintf(fp, "Removed maps:\n");
-       return printed + thread__fprintf_removed_maps(self, fp);
+       return printed + map_groups__fprintf_removed_maps(self, fp);
+}
+
+static size_t thread__fprintf(struct thread *self, FILE *fp)
+{
+       return fprintf(fp, "Thread %d %s\n", self->pid, self->comm) +
+              map_groups__fprintf(&self->mg, fp);
 }
 
 struct thread *threads__findnew(pid_t pid)
@@ -168,7 +173,8 @@ struct thread *register_idle_thread(void)
        return thread;
 }
 
-static void thread__remove_overlappings(struct thread *self, struct map *map)
+static void map_groups__remove_overlappings(struct map_groups *self,
+                                           struct map *map)
 {
        struct rb_root *root = &self->maps[map->type];
        struct rb_node *next = rb_first(root);
@@ -238,12 +244,15 @@ struct map *maps__find(struct rb_root *maps, u64 ip)
 
 void thread__insert_map(struct thread *self, struct map *map)
 {
-       thread__remove_overlappings(self, map);
-       maps__insert(&self->maps[map->type], map);
+       map_groups__remove_overlappings(&self->mg, map);
+       map_groups__insert(&self->mg, map);
 }
 
-static int thread__clone_maps(struct thread *self, struct thread *parent,
-                             enum map_type type)
+/*
+ * XXX This should not really _copy_ te maps, but refcount them.
+ */
+static int map_groups__clone(struct map_groups *self,
+                            struct map_groups *parent, enum map_type type)
 {
        struct rb_node *nd;
        for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) {
@@ -251,7 +260,7 @@ static int thread__clone_maps(struct thread *self, struct thread *parent,
                struct map *new = map__clone(map);
                if (new == NULL)
                        return -ENOMEM;
-               thread__insert_map(self, new);
+               map_groups__insert(self, new);
        }
        return 0;
 }
@@ -267,7 +276,7 @@ int thread__fork(struct thread *self, struct thread *parent)
                return -ENOMEM;
 
        for (i = 0; i < MAP__NR_TYPES; ++i)
-               if (thread__clone_maps(self, parent, i) < 0)
+               if (map_groups__clone(&self->mg, &parent->mg, i) < 0)
                        return -ENOMEM;
        return 0;
 }
@@ -286,11 +295,11 @@ size_t threads__fprintf(FILE *fp)
        return ret;
 }
 
-struct symbol *thread__find_symbol(struct thread *self,
-                                  enum map_type type, u64 addr,
-                                  symbol_filter_t filter)
+struct symbol *map_groups__find_symbol(struct map_groups *self,
+                                      enum map_type type, u64 addr,
+                                      symbol_filter_t filter)
 {
-       struct map *map = thread__find_map(self, type, addr);
+       struct map *map = map_groups__find(self, type, addr);
 
        if (map != NULL)
                return map__find_symbol(map, map->map_ip(map, addr), filter);
index 686d6e914d9e3711bfb1ea8e53e6b275715f2837..1751802a09ba41aef3fb1e985d94110aff516a12 100644 (file)
@@ -5,52 +5,66 @@
 #include <unistd.h>
 #include "symbol.h"
 
-struct thread {
-       struct rb_node          rb_node;
+struct map_groups {
        struct rb_root          maps[MAP__NR_TYPES];
        struct list_head        removed_maps[MAP__NR_TYPES];
-       pid_t                   pid;
        bool                    use_modules;
+};
+
+struct thread {
+       struct rb_node          rb_node;
+       struct map_groups       mg;
+       pid_t                   pid;
        char                    shortname[3];
        char                    *comm;
        int                     comm_len;
 };
 
-void thread__init(struct thread *self, pid_t pid);
+void map_groups__init(struct map_groups *self);
 int thread__set_comm(struct thread *self, const char *comm);
 int thread__comm_len(struct thread *self);
 struct thread *threads__findnew(pid_t pid);
 struct thread *register_idle_thread(void);
 void thread__insert_map(struct thread *self, struct map *map);
 int thread__fork(struct thread *self, struct thread *parent);
-size_t thread__fprintf_maps(struct thread *self, FILE *fp);
+size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp);
 size_t threads__fprintf(FILE *fp);
 
 void maps__insert(struct rb_root *maps, struct map *map);
 struct map *maps__find(struct rb_root *maps, u64 addr);
 
-static inline struct map *thread__find_map(struct thread *self,
+static inline void map_groups__insert(struct map_groups *self, struct map *map)
+{
+        maps__insert(&self->maps[map->type], map);
+}
+
+static inline struct map *map_groups__find(struct map_groups *self,
                                           enum map_type type, u64 addr)
 {
-       return self ? maps__find(&self->maps[type], addr) : NULL;
+       return maps__find(&self->maps[type], addr);
 }
 
-static inline void __thread__insert_map(struct thread *self, struct map *map)
+static inline struct map *thread__find_map(struct thread *self,
+                                          enum map_type type, u64 addr)
 {
-        maps__insert(&self->maps[map->type], map);
+       return self ? map_groups__find(&self->mg, type, addr) : NULL;
 }
 
 void thread__find_addr_location(struct thread *self, u8 cpumode,
                                enum map_type type, u64 addr,
                                struct addr_location *al,
                                symbol_filter_t filter);
-struct symbol *thread__find_symbol(struct thread *self,
-                                  enum map_type type, u64 addr,
-                                  symbol_filter_t filter);
+struct symbol *map_groups__find_symbol(struct map_groups *self,
+                                      enum map_type type, u64 addr,
+                                      symbol_filter_t filter);
 
 static inline struct symbol *
-thread__find_function(struct thread *self, u64 addr, symbol_filter_t filter)
+map_groups__find_function(struct map_groups *self, u64 addr,
+                         symbol_filter_t filter)
 {
-       return thread__find_symbol(self, MAP__FUNCTION, addr, filter);
+       return map_groups__find_symbol(self, MAP__FUNCTION, addr, filter);
 }
+
+struct map *map_groups__find_by_name(struct map_groups *self,
+                                    enum map_type type, const char *name);
 #endif /* __PERF_THREAD_H */
This page took 0.954324 seconds and 5 git commands to generate.