]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge branch 'akpm'
authorStephen Rothwell <sfr@canb.auug.org.au>
Mon, 15 Aug 2011 04:53:30 +0000 (14:53 +1000)
committerStephen Rothwell <sfr@canb.auug.org.au>
Mon, 15 Aug 2011 04:53:32 +0000 (14:53 +1000)
141 files changed:
Documentation/DocBook/debugobjects.tmpl
Documentation/trace/postprocess/trace-vmscan-postprocess.pl
MAINTAINERS
arch/arm/include/asm/processor.h
arch/arm/mach-ux500/mbox-db5500.c
arch/ia64/include/asm/processor.h
arch/parisc/Kconfig
arch/parisc/Kconfig.debug
arch/parisc/include/asm/processor.h
arch/parisc/kernel/process.c
arch/powerpc/include/asm/systbl.h
arch/powerpc/include/asm/unistd.h
arch/s390/Kconfig
arch/s390/Kconfig.debug
arch/s390/lib/Makefile
arch/sparc/kernel/process_32.c
arch/sparc/kernel/process_64.c
arch/sparc/lib/Makefile
arch/sparc/lib/usercopy.c [deleted file]
arch/tile/Kconfig
arch/tile/include/asm/uaccess.h
arch/tile/lib/uaccess.c
arch/unicore32/include/asm/processor.h
arch/x86/Kconfig
arch/x86/Kconfig.debug
arch/x86/ia32/ia32entry.S
arch/x86/include/asm/irq_vectors.h
arch/x86/include/asm/uaccess_64.h
arch/x86/include/asm/unistd_32.h
arch/x86/include/asm/unistd_64.h
arch/x86/kernel/apic/apic.c
arch/x86/kernel/cpu/mcheck/therm_throt.c
arch/x86/kernel/cpu/mcheck/threshold.c
arch/x86/kernel/e820.c
arch/x86/kernel/irq.c
arch/x86/kernel/irq_work.c
arch/x86/kernel/smp.c
arch/x86/kernel/syscall_table_32.S
arch/x86/kernel/time.c
arch/x86/kernel/traps.c
arch/x86/lib/usercopy_32.c
arch/x86/mm/mmap.c
arch/x86/mm/tlb.c
arch/x86/platform/Makefile
arch/x86/platform/geode/Makefile [new file with mode: 0644]
arch/x86/platform/geode/alix.c [new file with mode: 0644]
arch/x86/platform/iris/iris.c
drivers/block/brd.c
drivers/block/floppy.c
drivers/char/hpet.c
drivers/firmware/dmi_scan.c
drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c
drivers/hwmon/hwmon.c
drivers/hwmon/ibmaem.c
drivers/idle/intel_idle.c
drivers/iommu/dmar.c
drivers/iommu/intel-iommu.c
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/leds-alix2.c [deleted file]
drivers/leds/leds-renesas-tpu.c [new file with mode: 0644]
drivers/misc/lis3lv02d/lis3lv02d.c
drivers/misc/lis3lv02d/lis3lv02d.h
drivers/misc/lis3lv02d/lis3lv02d_i2c.c
drivers/misc/lis3lv02d/lis3lv02d_spi.c
drivers/platform/x86/Kconfig
drivers/platform/x86/acerhdf.c
drivers/platform/x86/hp_accel.c
drivers/pps/clients/Kconfig
drivers/pps/clients/Makefile
drivers/pps/clients/pps-gpio.c [new file with mode: 0644]
drivers/pps/clients/pps-ktimer.c
drivers/pps/clients/pps_parport.c
drivers/pps/kapi.c
drivers/rtc/class.c
drivers/scsi/aacraid/commctrl.c
drivers/scsi/megaraid.c
drivers/scsi/osd/osd_uld.c
drivers/scsi/sd.c
drivers/scsi/sg.c
drivers/video/fbmem.c
drivers/w1/slaves/w1_ds2760.c
drivers/w1/slaves/w1_ds2780.c
fs/aio.c
fs/btrfs/inode.c
fs/compat.c
fs/ext4/ext4.h
fs/ext4/ialloc.c
fs/ocfs2/ocfs2.h
fs/ocfs2/quota_local.c
fs/read_write.c
include/linux/compat.h
include/linux/debugobjects.h
include/linux/dmar.h
include/linux/fs.h
include/linux/hpet.h
include/linux/jiffies.h
include/linux/leds-renesas-tpu.h [new file with mode: 0644]
include/linux/magic.h
include/linux/memcontrol.h
include/linux/mmzone.h
include/linux/pps-gpio.h [new file with mode: 0644]
include/linux/swap.h
include/linux/syscalls.h
include/linux/sysctl.h
include/linux/writeback.h
include/scsi/scsi_netlink.h
include/trace/events/irq_vectors.h [new file with mode: 0644]
include/trace/events/vmscan.h
init/do_mounts.c
ipc/msgutil.c
ipc/shm.c
ipc/util.c
ipc/util.h
kernel/audit.c
kernel/kprobes.c
kernel/sys_ni.c
kernel/sysctl.c
kernel/time.c
kernel/timer.c
lib/Kconfig.debug
lib/Makefile
lib/crc32.c
lib/crc32defs.h
lib/debugobjects.c
lib/gen_crc32table.c
lib/radix-tree.c
lib/usercopy.c [moved from arch/s390/lib/usercopy.c with 100% similarity]
mm/Makefile
mm/compaction.c
mm/memcontrol.c
mm/mempolicy.c
mm/migrate.c
mm/mincore.c
mm/oom_kill.c
mm/page-writeback.c
mm/process_vm_access.c [new file with mode: 0644]
mm/vmscan.c
security/keys/compat.c
security/keys/keyctl.c
security/selinux/selinuxfs.c

index 08ff908aa7a239732fce68cc1b06e507626f216a..24979f691e3e88dd1ab82b3b00633e683445093f 100644 (file)
@@ -96,6 +96,7 @@
        <listitem><para>debug_object_deactivate</para></listitem>
        <listitem><para>debug_object_destroy</para></listitem>
        <listitem><para>debug_object_free</para></listitem>
+       <listitem><para>debug_object_assert_init</para></listitem>
       </itemizedlist>
       Each of these functions takes the address of the real object and
       a pointer to the object type specific debug description
        debug checks.
       </para>
     </sect1>
+
+    <sect1 id="debug_object_assert_init">
+      <title>debug_object_assert_init</title>
+      <para>
+       This function is called to assert that an object has been
+       initialized.
+      </para>
+      <para>
+       When the real object is not tracked by debugobjects, it calls
+       fixup_assert_init of the object type description structure
+       provided by the caller, with the hardcoded object state
+       ODEBUG_NOT_AVAILABLE. The fixup function can correct the problem
+       by calling debug_object_init and other specific initializing
+       functions.
+      </para>
+      <para>
+       When the real object is already tracked by debugobjects it is
+       ignored.
+      </para>
+    </sect1>
   </chapter>
   <chapter id="fixupfunctions">
     <title>Fixup functions</title>
        statistics.
       </para>
     </sect1>
+    <sect1 id="fixup_assert_init">
+      <title>fixup_assert_init</title>
+      <para>
+       This function is called from the debug code whenever a problem
+       in debug_object_assert_init is detected.
+      </para>
+      <para>
+       Called from debug_object_assert_init() with a hardcoded state
+       ODEBUG_STATE_NOTAVAILABLE when the object is not found in the
+       debug bucket.
+      </para>
+      <para>
+       The function returns 1 when the fixup was successful,
+       otherwise 0. The return value is used to update the
+       statistics.
+      </para>
+      <para>
+       Note, this function should make sure debug_object_init() is
+       called before returning.
+      </para>
+      <para>
+       The handling of statically initialized objects is a special
+       case. The fixup function should check if this is a legitimate
+       case of a statically initialized object or not. In this case only
+       debug_object_init() should be called to make the object known to
+       the tracker. Then the function should return 0 because this is not
+       a real fixup.
+      </para>
+    </sect1>
   </chapter>
   <chapter id="bugs">
     <title>Known Bugs And Assumptions</title>
index 12cecc83cd91c658c71524bba59762b83f810829..4a37c4759cd231f72a8b5f253deec9fdec334886 100644 (file)
@@ -379,10 +379,10 @@ EVENT_PROCESS:
 
                        # To closer match vmstat scanning statistics, only count isolate_both
                        # and isolate_inactive as scanning. isolate_active is rotation
-                       # isolate_inactive == 0
-                       # isolate_active   == 1
-                       # isolate_both     == 2
-                       if ($isolate_mode != 1) {
+                       # isolate_inactive == 1
+                       # isolate_active   == 2
+                       # isolate_both     == 3
+                       if ($isolate_mode != 2) {
                                $perprocesspid{$process_pid}->{HIGH_NR_SCANNED} += $nr_scanned;
                        }
                        $perprocesspid{$process_pid}->{HIGH_NR_CONTIG_DIRTY} += $nr_contig_dirty;
index 7b5b5c3940172fff02658615c4c525d043a744d0..2b31f9ec004ffb2d9744e126193fd33a8f36fa99 100644 (file)
@@ -3958,6 +3958,7 @@ M:        Eric Piel <eric.piel@tremplin-utc.net>
 S:     Maintained
 F:     Documentation/misc-devices/lis3lv02d
 F:     drivers/misc/lis3lv02d/
+F:     drivers/platform/x86/hp_accel.c
 
 LLC (802.2)
 M:     Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
index b2d9df5667af937476baf5e64ded8520ea3fd5d4..3962caf485c09776f7f493e9e05ef1841190b4ae 100644 (file)
@@ -55,7 +55,6 @@ struct thread_struct {
 #define start_thread(regs,pc,sp)                                       \
 ({                                                                     \
        unsigned long *stack = (unsigned long *)sp;                     \
-       set_fs(USER_DS);                                                \
        memset(regs->uregs, 0, sizeof(regs->uregs));                    \
        if (current->personality & ADDR_LIMIT_32BIT)                    \
                regs->ARM_cpsr = USR_MODE;                              \
index 2b2d51caf9d8b9f4db2e62c1eaa7a596b3313546..0127490218cdfc4bc00b107be2816a84703d6a4f 100644 (file)
@@ -168,7 +168,7 @@ static ssize_t mbox_read_fifo(struct device *dev,
        return sprintf(buf, "0x%X\n", mbox_value);
 }
 
-static DEVICE_ATTR(fifo, S_IWUGO | S_IRUGO, mbox_read_fifo, mbox_write_fifo);
+static DEVICE_ATTR(fifo, S_IWUSR | S_IRUGO, mbox_read_fifo, mbox_write_fifo);
 
 static int mbox_show(struct seq_file *s, void *data)
 {
index d9f397fae03eb7e89712aa7cedef3b8d11082b4e..691be0b95c1e0fb280721cde45e9d1f88d08af77 100644 (file)
@@ -309,7 +309,6 @@ struct thread_struct {
 }
 
 #define start_thread(regs,new_ip,new_sp) do {                                                  \
-       set_fs(USER_DS);                                                                        \
        regs->cr_ipsr = ((regs->cr_ipsr | (IA64_PSR_BITS_TO_SET | IA64_PSR_CPL))                \
                         & ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_RI | IA64_PSR_IS));              \
        regs->cr_iip = new_ip;                                                                  \
index e077b0bf56ca51910df1775acd66f319afdae13a..5dcb59ff848d0017cfe4f2a01131dd8a18cd5111 100644 (file)
@@ -7,6 +7,7 @@ config PARISC
        select HAVE_FUNCTION_TRACE_MCOUNT_TEST if 64BIT
        select RTC_CLASS
        select RTC_DRV_GENERIC
+       select ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS
        select INIT_ALL_POSSIBLE
        select BUG
        select HAVE_IRQ_WORK
index 7305ac8f7f5ba7438ac2207ada7aaeb60b419d36..bc989e522a045c17ca4514478b7cb5ef9d77fc4d 100644 (file)
@@ -12,18 +12,4 @@ config DEBUG_RODATA
          portion of the kernel code won't be covered by a TLB anymore.
          If in doubt, say "N".
 
-config DEBUG_STRICT_USER_COPY_CHECKS
-       bool "Strict copy size checks"
-       depends on DEBUG_KERNEL && !TRACE_BRANCH_PROFILING
-       ---help---
-         Enabling this option turns a certain set of sanity checks for user
-         copy operations into compile time failures.
-
-         The copy_from_user() etc checks are there to help test if there
-         are sufficient security checks on the length argument of
-         the copy operation, by having gcc prove that the argument is
-         within bounds.
-
-         If unsure, or if you run an older (pre 4.4) gcc, say N.
-
 endmenu
index 9ce66e9d1c2b845275c41aaaf290a5fb5e123ba1..7213ec9e594cd4de25b912c17693dca742f46192 100644 (file)
@@ -196,7 +196,6 @@ typedef unsigned int elf_caddr_t;
        /* offset pc for priv. level */                 \
        pc |= 3;                                        \
                                                        \
-       set_fs(USER_DS);                                \
        regs->iasq[0] = spaceid;                        \
        regs->iasq[1] = spaceid;                        \
        regs->iaoq[0] = pc;                             \
@@ -299,7 +298,6 @@ on downward growing arches, it looks like this:
        elf_addr_t pc = (elf_addr_t)new_pc | 3;         \
        elf_caddr_t *argv = (elf_caddr_t *)bprm->exec + 1;      \
                                                        \
-       set_fs(USER_DS);                                \
        regs->iasq[0] = spaceid;                        \
        regs->iasq[1] = spaceid;                        \
        regs->iaoq[0] = pc;                             \
index 4b4b9181a1a0aef8df25667f4a0229bb275e8d7f..62c60b87d0395d66b02a929095fe37bbb33b849b 100644 (file)
@@ -192,7 +192,6 @@ void flush_thread(void)
        /* Only needs to handle fpu stuff or perf monitors.
        ** REVISIT: several arches implement a "lazy fpu state".
        */
-       set_fs(USER_DS);
 }
 
 void release_thread(struct task_struct *dead_task)
index f6736b7da463508e2b9777e851d2bdd2c597fec8..525db4b590c783ca171ad941d705907cd74796d8 100644 (file)
@@ -354,3 +354,5 @@ COMPAT_SYS_SPU(clock_adjtime)
 SYSCALL_SPU(syncfs)
 COMPAT_SYS_SPU(sendmmsg)
 SYSCALL_SPU(setns)
+COMPAT_SYS(process_vm_readv)
+COMPAT_SYS(process_vm_writev)
index b8b3f599362b70167ab8db7c49038ad08f2b02f2..d3d1b5efd7eb1204405fde26c701e7c52b925fd9 100644 (file)
 #define __NR_syncfs            348
 #define __NR_sendmmsg          349
 #define __NR_setns             350
+#define __NR_process_vm_readv  351
+#define __NR_process_vm_writev 352
 
 #ifdef __KERNEL__
 
-#define __NR_syscalls          351
+#define __NR_syscalls          353
 
 #define __NR__exit __NR_exit
 #define NR_syscalls    __NR_syscalls
index ed5cb5af52816940d45c6610e3e2e0d8c1d60a82..6851fbb9ab31f6323a0b9151cc853691ab47639b 100644 (file)
@@ -119,6 +119,7 @@ config S390
        select ARCH_INLINE_WRITE_UNLOCK_BH
        select ARCH_INLINE_WRITE_UNLOCK_IRQ
        select ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE
+       select ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS
 
 config SCHED_OMIT_FRAME_POINTER
        def_bool y
index d76cef3fef37bac6f3df5ad6d336a30cdfc8233f..aa1796cc237cd72f79c9dad9df95ab80fc8c82cb 100644 (file)
@@ -17,20 +17,6 @@ config STRICT_DEVMEM
 
          If you are unsure, say Y.
 
-config DEBUG_STRICT_USER_COPY_CHECKS
-       def_bool n
-       prompt "Strict user copy size checks"
-       ---help---
-         Enabling this option turns a certain set of sanity checks for user
-         copy operations into compile time warnings.
-
-         The copy_from_user() etc checks are there to help test if there
-         are sufficient security checks on the length argument of
-         the copy operation, by having gcc prove that the argument is
-         within bounds.
-
-         If unsure, or if you run an older (pre 4.4) gcc, say N.
-
 config DEBUG_SET_MODULE_RONX
        def_bool y
        depends on MODULES
index 761ab8b56afc4cb13080cfc59461fd9bf68a26a9..97975ec7a27471253a8da274af72d14a16e9f171 100644 (file)
@@ -3,7 +3,6 @@
 #
 
 lib-y += delay.o string.o uaccess_std.o uaccess_pt.o
-obj-y += usercopy.o
 obj-$(CONFIG_32BIT) += div64.o qrnnd.o ucmpdi2.o
 lib-$(CONFIG_64BIT) += uaccess_mvcos.o
 lib-$(CONFIG_SMP) += spinlock.o
index c8cc461ff75f040a974179aa7383ba501dde017a..f793742eec2b075395f9e71c4af50bac780dbe25 100644 (file)
@@ -380,8 +380,7 @@ void flush_thread(void)
 #endif
        }
 
-       /* Now, this task is no longer a kernel thread. */
-       current->thread.current_ds = USER_DS;
+       /* This task is no longer a kernel thread. */
        if (current->thread.flags & SPARC_FLAG_KTHREAD) {
                current->thread.flags &= ~SPARC_FLAG_KTHREAD;
 
index 0049e434c2f7243c96bb0e26046c3a206a79eed6..3739a06a76cbfdbd93a0dde7bf0494e6b8e74285 100644 (file)
@@ -368,9 +368,6 @@ void flush_thread(void)
 
        /* Clear FPU register state. */
        t->fpsaved[0] = 0;
-       
-       if (get_thread_current_ds() != ASI_AIUS)
-               set_fs(USER_DS);
 }
 
 /* It's a bit more tricky when 64-bit tasks are involved... */
index a3fc4375a150e9cd637202eefc5d80598db17dce..ddc551cb815ae4856c56e581a93b884a47df55e1 100644 (file)
@@ -43,4 +43,3 @@ obj-y                 += iomap.o
 obj-$(CONFIG_SPARC32) += atomic32.o
 obj-y                 += ksyms.o
 obj-$(CONFIG_SPARC64) += PeeCeeI.o
-obj-y                 += usercopy.o
diff --git a/arch/sparc/lib/usercopy.c b/arch/sparc/lib/usercopy.c
deleted file mode 100644 (file)
index 14b363f..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#include <linux/module.h>
-#include <linux/bug.h>
-
-void copy_from_user_overflow(void)
-{
-       WARN(1, "Buffer overflow detected!\n");
-}
-EXPORT_SYMBOL(copy_from_user_overflow);
index b30f71ac0d0657f24d6a37f13c7ad802d9f36708..99ee890d0aa197bf0956787f381e5ac0354ac7a5 100644 (file)
@@ -7,6 +7,7 @@ config TILE
        select GENERIC_FIND_FIRST_BIT
        select USE_GENERIC_SMP_HELPERS
        select CC_OPTIMIZE_FOR_SIZE
+       select ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_PROBE
        select GENERIC_PENDING_IRQ if SMP
@@ -97,13 +98,6 @@ config STRICT_DEVMEM
 config SMP
        def_bool y
 
-# Allow checking for compile-time determined overflow errors in
-# copy_from_user().  There are still unprovable places in the
-# generic code as of 2.6.34, so this option is not really compatible
-# with -Werror, which is more useful in general.
-config DEBUG_COPY_FROM_USER
-       def_bool n
-
 config HVC_TILE
        select HVC_DRIVER
        def_bool y
index ef34d2caa5b1b6205775da2dfe352274569a0e73..9a540be3149e47b79317e5941e04b33becfe6f9c 100644 (file)
@@ -353,7 +353,12 @@ _copy_from_user(void *to, const void __user *from, unsigned long n)
        return n;
 }
 
-#ifdef CONFIG_DEBUG_COPY_FROM_USER
+#ifdef CONFIG_DEBUG_STRICT_USER_COPY_CHECKS
+/*
+ * There are still unprovable places in the generic code as of 2.6.34, so this
+ * option is not really compatible with -Werror, which is more useful in
+ * general.
+ */
 extern void copy_from_user_overflow(void)
        __compiletime_warning("copy_from_user() size is not provably correct");
 
index f8d398c9ee7f3e174b70d94648db32d7500b2e80..030abe3ee4f1da38380cd592a7405fdefd346c36 100644 (file)
@@ -22,11 +22,3 @@ int __range_ok(unsigned long addr, unsigned long size)
                 is_arch_mappable_range(addr, size));
 }
 EXPORT_SYMBOL(__range_ok);
-
-#ifdef CONFIG_DEBUG_COPY_FROM_USER
-void copy_from_user_overflow(void)
-{
-       WARN(1, "Buffer overflow detected!\n");
-}
-EXPORT_SYMBOL(copy_from_user_overflow);
-#endif
index e11cb07865782c81b82e4dd90d1977b8f4495245..f0d780a51f9b5dec74a5310fe0f1fd2c4fdc7b28 100644 (file)
@@ -53,7 +53,6 @@ struct thread_struct {
 #define start_thread(regs, pc, sp)                                     \
 ({                                                                     \
        unsigned long *stack = (unsigned long *)sp;                     \
-       set_fs(USER_DS);                                                \
        memset(regs->uregs, 0, sizeof(regs->uregs));                    \
        regs->UCreg_asr = USER_MODE;                                    \
        regs->UCreg_pc = pc & ~1;       /* pc */                        \
index f1833e34b16b01045db3bb346f3d462e74f445a0..ff6d4e7d0b3eafd3fdcf84001aaef3a4e1929a52 100644 (file)
@@ -64,6 +64,7 @@ config X86
        select HAVE_TEXT_POKE_SMP
        select HAVE_GENERIC_HARDIRQS
        select HAVE_SPARSE_IRQ
+       select ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS
        select GENERIC_FIND_FIRST_BIT
        select GENERIC_IRQ_PROBE
        select GENERIC_PENDING_IRQ if SMP
@@ -2073,6 +2074,20 @@ config OLPC_XO15_SCI
           - AC adapter status updates
           - Battery status updates
 
+config ALIX
+       bool "PCEngines ALIX System Support (LED setup)"
+       select GPIOLIB
+       ---help---
+         This option enables system support for the PCEngines ALIX.
+         At present this just sets up LEDs for GPIO control on
+         ALIX2/3/6 boards.  However, other system specific setup should
+         get added here.
+
+         Note: You must still enable the drivers for GPIO and LED support
+         (GPIO_CS5535 & LEDS_GPIO) to actually use the LEDs
+
+         Note: You have to set alix.force=1 for boards with Award BIOS.
+
 endif # X86_32
 
 config AMD_NB
index c0f8a5c889107bf80ab45eaf33468e5120ee6a56..2b00959c10610c678b0a969af4db3f1acb70420b 100644 (file)
@@ -270,18 +270,4 @@ config OPTIMIZE_INLINING
 
          If unsure, say N.
 
-config DEBUG_STRICT_USER_COPY_CHECKS
-       bool "Strict copy size checks"
-       depends on DEBUG_KERNEL && !TRACE_BRANCH_PROFILING
-       ---help---
-         Enabling this option turns a certain set of sanity checks for user
-         copy operations into compile time failures.
-
-         The copy_from_user() etc checks are there to help test if there
-         are sufficient security checks on the length argument of
-         the copy operation, by having gcc prove that the argument is
-         within bounds.
-
-         If unsure, or if you run an older (pre 4.4) gcc, say N.
-
 endmenu
index a0e866d233eeb833ef9740e1247962d298cc5971..6a177c529161c7c93c79ba80ac39383524bf6e84 100644 (file)
@@ -850,4 +850,6 @@ ia32_sys_call_table:
        .quad sys_syncfs
        .quad compat_sys_sendmmsg       /* 345 */
        .quad sys_setns
+       .quad compat_sys_process_vm_readv
+       .quad compat_sys_process_vm_writev
 ia32_syscall_end:
index 7e50f06393aae8869eb5d5e0ab7cf00de1a911d9..3857b04ff38c136c2c315804880653821944eab2 100644 (file)
@@ -177,4 +177,54 @@ static inline int invalid_vm86_irq(int irq)
 # define NR_IRQS                       NR_IRQS_LEGACY
 #endif
 
+#define irq_vector_name(sirq) { sirq, #sirq }
+#define invalidate_tlb_vector_name(i) { INVALIDATE_TLB_VECTOR_END-31+i, \
+                                       "INVALIDATE_TLB_VECTOR" }
+
+#define irq_vector_name_table                                          \
+                       irq_vector_name(NMI_VECTOR),                    \
+                       irq_vector_name(LOCAL_TIMER_VECTOR),            \
+                       irq_vector_name(ERROR_APIC_VECTOR),             \
+                       irq_vector_name(RESCHEDULE_VECTOR),             \
+                       irq_vector_name(CALL_FUNCTION_VECTOR),          \
+                       irq_vector_name(CALL_FUNCTION_SINGLE_VECTOR),   \
+                       irq_vector_name(THERMAL_APIC_VECTOR),           \
+                       irq_vector_name(THRESHOLD_APIC_VECTOR),         \
+                       irq_vector_name(REBOOT_VECTOR),                 \
+                       irq_vector_name(SPURIOUS_APIC_VECTOR),          \
+                       irq_vector_name(IRQ_WORK_VECTOR),               \
+                       irq_vector_name(X86_PLATFORM_IPI_VECTOR),       \
+                       invalidate_tlb_vector_name(0),                  \
+                       invalidate_tlb_vector_name(1),                  \
+                       invalidate_tlb_vector_name(2),                  \
+                       invalidate_tlb_vector_name(3),                  \
+                       invalidate_tlb_vector_name(4),                  \
+                       invalidate_tlb_vector_name(5),                  \
+                       invalidate_tlb_vector_name(6),                  \
+                       invalidate_tlb_vector_name(7),                  \
+                       invalidate_tlb_vector_name(8),                  \
+                       invalidate_tlb_vector_name(9),                  \
+                       invalidate_tlb_vector_name(10),                 \
+                       invalidate_tlb_vector_name(11),                 \
+                       invalidate_tlb_vector_name(12),                 \
+                       invalidate_tlb_vector_name(13),                 \
+                       invalidate_tlb_vector_name(14),                 \
+                       invalidate_tlb_vector_name(15),                 \
+                       invalidate_tlb_vector_name(16),                 \
+                       invalidate_tlb_vector_name(17),                 \
+                       invalidate_tlb_vector_name(18),                 \
+                       invalidate_tlb_vector_name(19),                 \
+                       invalidate_tlb_vector_name(20),                 \
+                       invalidate_tlb_vector_name(21),                 \
+                       invalidate_tlb_vector_name(22),                 \
+                       invalidate_tlb_vector_name(23),                 \
+                       invalidate_tlb_vector_name(24),                 \
+                       invalidate_tlb_vector_name(25),                 \
+                       invalidate_tlb_vector_name(26),                 \
+                       invalidate_tlb_vector_name(27),                 \
+                       invalidate_tlb_vector_name(28),                 \
+                       invalidate_tlb_vector_name(29),                 \
+                       invalidate_tlb_vector_name(30),                 \
+                       invalidate_tlb_vector_name(31)
+
 #endif /* _ASM_X86_IRQ_VECTORS_H */
index 1c66d30971adedaac940770d701e141ae464e1f4..6ca53e5077776dd43bb67508a6407d7e1e006e7e 100644 (file)
@@ -43,6 +43,14 @@ _copy_from_user(void *to, const void __user *from, unsigned len);
 __must_check unsigned long
 copy_in_user(void __user *to, const void __user *from, unsigned len);
 
+extern void copy_from_user_overflow(void)
+#ifdef CONFIG_DEBUG_STRICT_USER_COPY_CHECKS
+       __compiletime_error("copy_from_user() buffer size is not provably correct")
+#else
+       __compiletime_warning("copy_from_user() buffer size is not provably correct")
+#endif
+;
+
 static inline unsigned long __must_check copy_from_user(void *to,
                                          const void __user *from,
                                          unsigned long n)
@@ -52,10 +60,8 @@ static inline unsigned long __must_check copy_from_user(void *to,
        might_fault();
        if (likely(sz == -1 || sz >= n))
                n = _copy_from_user(to, from, n);
-#ifdef CONFIG_DEBUG_VM
        else
-               WARN(1, "Buffer overflow detected!\n");
-#endif
+               copy_from_user_overflow();
        return n;
 }
 
index 593485b38ab38cc501e3f975209aabfb3f710106..599c77d38f332f06fdf1e34f7449e2b7b5c81203 100644 (file)
 #define __NR_syncfs             344
 #define __NR_sendmmsg          345
 #define __NR_setns             346
+#define __NR_process_vm_readv  347
+#define __NR_process_vm_writev 348
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 347
+#define NR_syscalls 349
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
index d92641cc7accd79aa30b382314a92cee2a93827d..f9fff6a1a68bfdc307f3609787f8b99d66a208b3 100644 (file)
@@ -683,6 +683,10 @@ __SYSCALL(__NR_sendmmsg, sys_sendmmsg)
 __SYSCALL(__NR_setns, sys_setns)
 #define __NR_getcpu                            309
 __SYSCALL(__NR_getcpu, sys_getcpu)
+#define __NR_process_vm_readv                  310
+__SYSCALL(__NR_process_vm_readv, sys_process_vm_readv)
+#define __NR_process_vm_writev                 311
+__SYSCALL(__NR_process_vm_writev, sys_process_vm_writev)
 
 #ifndef __NO_STUBS
 #define __ARCH_WANT_OLD_READDIR
index 52fa56399a5021664eca08743d9cd8eec1108b7e..0fe559f3639be5d9dc35e16a86ecd434bf582cef 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/dmi.h>
 #include <linux/smp.h>
 #include <linux/mm.h>
+#include <trace/events/irq_vectors.h>
 
 #include <asm/perf_event.h>
 #include <asm/x86_init.h>
@@ -859,7 +860,9 @@ void __irq_entry smp_apic_timer_interrupt(struct pt_regs *regs)
         */
        exit_idle();
        irq_enter();
+       trace_irq_vector_entry(LOCAL_TIMER_VECTOR);
        local_apic_timer_interrupt();
+       trace_irq_vector_exit(LOCAL_TIMER_VECTOR);
        irq_exit();
 
        set_irq_regs(old_regs);
@@ -1793,6 +1796,7 @@ void smp_spurious_interrupt(struct pt_regs *regs)
 
        exit_idle();
        irq_enter();
+       trace_irq_vector_entry(SPURIOUS_APIC_VECTOR);
        /*
         * Check if this really is a spurious interrupt and ACK it
         * if it is a vectored one.  Just in case...
@@ -1807,6 +1811,7 @@ void smp_spurious_interrupt(struct pt_regs *regs)
        /* see sw-dev-man vol 3, chapter 7.4.13.5 */
        pr_info("spurious APIC interrupt on CPU#%d, "
                "should never happen.\n", smp_processor_id());
+       trace_irq_vector_exit(SPURIOUS_APIC_VECTOR);
        irq_exit();
 }
 
@@ -1830,6 +1835,7 @@ void smp_error_interrupt(struct pt_regs *regs)
 
        exit_idle();
        irq_enter();
+       trace_irq_vector_entry(ERROR_APIC_VECTOR);
        /* First tickle the hardware, only then report what went on. -- REW */
        v0 = apic_read(APIC_ESR);
        apic_write(APIC_ESR, 0);
@@ -1850,6 +1856,7 @@ void smp_error_interrupt(struct pt_regs *regs)
 
        apic_printk(APIC_DEBUG, KERN_CONT "\n");
 
+       trace_irq_vector_exit(ERROR_APIC_VECTOR);
        irq_exit();
 }
 
index 787e06c84ea6a8cf6e097e15c4b13c2db87dbb7a..6b7edb53f00a0c84c865ad2894121742ef655e04 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/init.h>
 #include <linux/smp.h>
 #include <linux/cpu.h>
+#include <trace/events/irq_vectors.h>
 
 #include <asm/processor.h>
 #include <asm/system.h>
@@ -399,8 +400,10 @@ asmlinkage void smp_thermal_interrupt(struct pt_regs *regs)
 {
        exit_idle();
        irq_enter();
+       trace_irq_vector_entry(THERMAL_APIC_VECTOR);
        inc_irq_stat(irq_thermal_count);
        smp_thermal_vector();
+       trace_irq_vector_exit(THERMAL_APIC_VECTOR);
        irq_exit();
        /* Ack only at the end to avoid potential reentry */
        ack_APIC_irq();
index d746df2909c9fe306d20f1e5288cc476c5777209..ffde17bdd85adb1979964a60c60986cf5c722cc6 100644 (file)
@@ -3,6 +3,7 @@
  */
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
+#include <trace/events/irq_vectors.h>
 
 #include <asm/irq_vectors.h>
 #include <asm/apic.h>
@@ -21,8 +22,10 @@ asmlinkage void smp_threshold_interrupt(void)
 {
        exit_idle();
        irq_enter();
+       trace_irq_vector_entry(THRESHOLD_APIC_VECTOR);
        inc_irq_stat(irq_threshold_count);
        mce_threshold_vector();
+       trace_irq_vector_exit(THRESHOLD_APIC_VECTOR);
        irq_exit();
        /* Ack only at the end to avoid potential reentry */
        ack_APIC_irq();
index 303a0e48f076feb3feb522d4052ac4b958995d42..f655f802260d69bbf3d80ffaeb9b30e32fe51124 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/acpi.h>
 #include <linux/firmware-map.h>
 #include <linux/memblock.h>
+#include <linux/sort.h>
 
 #include <asm/e820.h>
 #include <asm/proto.h>
@@ -227,22 +228,38 @@ void __init e820_print_map(char *who)
  *        ____________________33__
  *        ______________________4_
  */
+struct change_member {
+       struct e820entry *pbios; /* pointer to original bios entry */
+       unsigned long long addr; /* address for this change point */
+};
+
+static int __init cpcompare(const void *a, const void *b)
+{
+       struct change_member * const *app = a, * const *bpp = b;
+       const struct change_member *ap = *app, *bp = *bpp;
+
+       /*
+        * Inputs are pointers to two elements of change_point[].  If their
+        * addresses are unequal, their difference dominates.  If the addresses
+        * are equal, then consider one that represents the end of its region
+        * to be greater than one that does not.
+        */
+       if (ap->addr != bp->addr)
+               return ap->addr > bp->addr ? 1 : -1;
+
+       return (ap->addr != ap->pbios->addr) - (bp->addr != bp->pbios->addr);
+}
 
 int __init sanitize_e820_map(struct e820entry *biosmap, int max_nr_map,
                             u32 *pnr_map)
 {
-       struct change_member {
-               struct e820entry *pbios; /* pointer to original bios entry */
-               unsigned long long addr; /* address for this change point */
-       };
        static struct change_member change_point_list[2*E820_X_MAX] __initdata;
        static struct change_member *change_point[2*E820_X_MAX] __initdata;
        static struct e820entry *overlap_list[E820_X_MAX] __initdata;
        static struct e820entry new_bios[E820_X_MAX] __initdata;
-       struct change_member *change_tmp;
        unsigned long current_type, last_type;
        unsigned long long last_addr;
-       int chgidx, still_changing;
+       int chgidx;
        int overlap_entries;
        int new_bios_entry;
        int old_nr, new_nr, chg_nr;
@@ -279,35 +296,7 @@ int __init sanitize_e820_map(struct e820entry *biosmap, int max_nr_map,
        chg_nr = chgidx;
 
        /* sort change-point list by memory addresses (low -> high) */
-       still_changing = 1;
-       while (still_changing)  {
-               still_changing = 0;
-               for (i = 1; i < chg_nr; i++)  {
-                       unsigned long long curaddr, lastaddr;
-                       unsigned long long curpbaddr, lastpbaddr;
-
-                       curaddr = change_point[i]->addr;
-                       lastaddr = change_point[i - 1]->addr;
-                       curpbaddr = change_point[i]->pbios->addr;
-                       lastpbaddr = change_point[i - 1]->pbios->addr;
-
-                       /*
-                        * swap entries, when:
-                        *
-                        * curaddr > lastaddr or
-                        * curaddr == lastaddr and curaddr == curpbaddr and
-                        * lastaddr != lastpbaddr
-                        */
-                       if (curaddr < lastaddr ||
-                           (curaddr == lastaddr && curaddr == curpbaddr &&
-                            lastaddr != lastpbaddr)) {
-                               change_tmp = change_point[i];
-                               change_point[i] = change_point[i-1];
-                               change_point[i-1] = change_tmp;
-                               still_changing = 1;
-                       }
-               }
-       }
+       sort(change_point, chg_nr, sizeof *change_point, cpcompare, 0);
 
        /* create a new bios memory map, removing overlaps */
        overlap_entries = 0;     /* number of entries in the overlap table */
index 429e0c92924eede7d925c92836ac25505de86007..64aad37c0ff09df3999e8ce808ab1a58006952a3 100644 (file)
@@ -18,6 +18,9 @@
 #include <asm/mce.h>
 #include <asm/hw_irq.h>
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/irq_vectors.h>
+
 atomic_t irq_err_count;
 
 /* Function pointer for generic interrupt vector handling */
@@ -212,12 +215,13 @@ void smp_x86_platform_ipi(struct pt_regs *regs)
        exit_idle();
 
        irq_enter();
-
+       trace_irq_vector_entry(X86_PLATFORM_IPI_VECTOR);
        inc_irq_stat(x86_platform_ipis);
 
        if (x86_platform_ipi_callback)
                x86_platform_ipi_callback();
 
+       trace_irq_vector_exit(X86_PLATFORM_IPI_VECTOR);
        irq_exit();
 
        set_irq_regs(old_regs);
index ca8f703a1e70bdaf219bdcdd215ac2e1724bfda6..107754c8d8ec7436ab33df49d5f9d214ee68decc 100644 (file)
@@ -8,13 +8,16 @@
 #include <linux/irq_work.h>
 #include <linux/hardirq.h>
 #include <asm/apic.h>
+#include <trace/events/irq_vectors.h>
 
 void smp_irq_work_interrupt(struct pt_regs *regs)
 {
        irq_enter();
        ack_APIC_irq();
+       trace_irq_vector_entry(IRQ_WORK_VECTOR);
        inc_irq_stat(apic_irq_work_irqs);
        irq_work_run();
+       trace_irq_vector_exit(IRQ_WORK_VECTOR);
        irq_exit();
 }
 
index 16204dc1548427d8895b6ce7da1436d81ecfe431..17c5d01868e0c13120eb23ebdb0a75d9419aa821 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/interrupt.h>
 #include <linux/cpu.h>
 #include <linux/gfp.h>
+#include <trace/events/irq_vectors.h>
 
 #include <asm/mtrr.h>
 #include <asm/tlbflush.h>
@@ -200,8 +201,10 @@ static void native_stop_other_cpus(int wait)
 void smp_reschedule_interrupt(struct pt_regs *regs)
 {
        ack_APIC_irq();
+       trace_irq_vector_entry(RESCHEDULE_VECTOR);
        inc_irq_stat(irq_resched_count);
        scheduler_ipi();
+       trace_irq_vector_exit(RESCHEDULE_VECTOR);
        /*
         * KVM uses this interrupt to force a cpu out of guest mode
         */
@@ -211,8 +214,10 @@ void smp_call_function_interrupt(struct pt_regs *regs)
 {
        ack_APIC_irq();
        irq_enter();
+       trace_irq_vector_entry(CALL_FUNCTION_VECTOR);
        generic_smp_call_function_interrupt();
        inc_irq_stat(irq_call_count);
+       trace_irq_vector_exit(CALL_FUNCTION_VECTOR);
        irq_exit();
 }
 
@@ -220,8 +225,10 @@ void smp_call_function_single_interrupt(struct pt_regs *regs)
 {
        ack_APIC_irq();
        irq_enter();
+       trace_irq_vector_entry(CALL_FUNCTION_SINGLE_VECTOR);
        generic_smp_call_function_single_interrupt();
        inc_irq_stat(irq_call_count);
+       trace_irq_vector_exit(CALL_FUNCTION_SINGLE_VECTOR);
        irq_exit();
 }
 
index fbb0a045a1a23bc9bdc2f9dd23c6c9673e2e13f7..ca0fe4d1fe28a0c086979dcff83c4a3f4b9cf845 100644 (file)
@@ -346,3 +346,5 @@ ENTRY(sys_call_table)
        .long sys_syncfs
        .long sys_sendmmsg              /* 345 */
        .long sys_setns
+       .long sys_process_vm_readv
+       .long sys_process_vm_writev
index dd5fbf4101fc393a3edad3bb3a569a1ed63269fa..25046df137f24653e810ed63220482106a965ad4 100644 (file)
@@ -52,6 +52,13 @@ unsigned long profile_pc(struct pt_regs *regs)
 }
 EXPORT_SYMBOL(profile_pc);
 
+static irqreturn_t timer_interrupt(int irq, void *dev_id);
+static struct irqaction irq0  = {
+       .handler = timer_interrupt,
+       .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_IRQPOLL | IRQF_TIMER,
+       .name = "timer"
+};
+
 /*
  * Default timer interrupt handler for PIT/HPET
  */
@@ -60,7 +67,9 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
        /* Keep nmi watchdog up to date */
        inc_irq_stat(irq0_irqs);
 
+       trace_irq_handler_entry(irq, &irq0);
        global_clock_event->event_handler(global_clock_event);
+       trace_irq_handler_exit(irq, &irq0, 1);
 
        /* MCA bus quirk: Acknowledge irq0 by setting bit 7 in port 0x61 */
        if (MCA_bus)
@@ -69,12 +78,6 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static struct irqaction irq0  = {
-       .handler = timer_interrupt,
-       .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_IRQPOLL | IRQF_TIMER,
-       .name = "timer"
-};
-
 void __init setup_default_timer_irq(void)
 {
        setup_irq(0, &irq0);
index 6913369c234c93db814848b264464bc1452572e3..1286877967e9409a91ecb04a719a86cee2b9badb 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/mm.h>
 #include <linux/smp.h>
 #include <linux/io.h>
+#include <trace/events/irq_vectors.h>
 
 #ifdef CONFIG_EISA
 #include <linux/ioport.h>
@@ -434,12 +435,14 @@ dotraplinkage notrace __kprobes void
 do_nmi(struct pt_regs *regs, long error_code)
 {
        nmi_enter();
+       trace_irq_vector_entry(NMI_VECTOR);
 
        inc_irq_stat(__nmi_count);
 
        if (!ignore_nmis)
                default_do_nmi(regs);
 
+       trace_irq_vector_exit(NMI_VECTOR);
        nmi_exit();
 }
 
index e218d5df85ff23445c277c2fe89d611dcab433ae..8498684e45b0d0864b490a2673daffdc0db01241 100644 (file)
@@ -883,9 +883,3 @@ _copy_from_user(void *to, const void __user *from, unsigned long n)
        return n;
 }
 EXPORT_SYMBOL(_copy_from_user);
-
-void copy_from_user_overflow(void)
-{
-       WARN(1, "Buffer overflow detected!\n");
-}
-EXPORT_SYMBOL(copy_from_user_overflow);
index 4b5ba85eb5c95ebb705f8ce420acbff85c052f47..845df6835f9ff5fc216ab01857100d41eba77fbf 100644 (file)
@@ -75,9 +75,9 @@ static unsigned long mmap_rnd(void)
        */
        if (current->flags & PF_RANDOMIZE) {
                if (mmap_is_ia32())
-                       rnd = (long)get_random_int() % (1<<8);
+                       rnd = get_random_int() % (1<<8);
                else
-                       rnd = (long)(get_random_int() % (1<<28));
+                       rnd = get_random_int() % (1<<28);
        }
        return rnd << PAGE_SHIFT;
 }
index d6c0418c3e4711795158b52e57b2fa337848d03c..bf9475d97307d80291028243e8e9bd611ce4b7da 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/smp.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <trace/events/irq_vectors.h>
 #include <linux/cpu.h>
 
 #include <asm/tlbflush.h>
@@ -141,6 +142,7 @@ void smp_invalidate_interrupt(struct pt_regs *regs)
        sender = ~regs->orig_ax - INVALIDATE_TLB_VECTOR_START;
        f = &flush_state[sender];
 
+       trace_irq_vector_entry(INVALIDATE_TLB_VECTOR_START + sender);
        if (!cpumask_test_cpu(cpu, to_cpumask(f->flush_cpumask)))
                goto out;
                /*
@@ -167,6 +169,7 @@ out:
        cpumask_clear_cpu(cpu, to_cpumask(f->flush_cpumask));
        smp_mb__after_clear_bit();
        inc_irq_stat(irq_tlb_count);
+       trace_irq_vector_exit(INVALIDATE_TLB_VECTOR_START + sender);
 }
 
 static void flush_tlb_others_ipi(const struct cpumask *cpumask,
index 021eee91c0562503dbb68c5bea490674d9db8618..8d874396cb29044b15ccf8634259e239cc9f957b 100644 (file)
@@ -1,6 +1,7 @@
 # Platform specific code goes here
 obj-y  += ce4100/
 obj-y  += efi/
+obj-y  += geode/
 obj-y  += iris/
 obj-y  += mrst/
 obj-y  += olpc/
diff --git a/arch/x86/platform/geode/Makefile b/arch/x86/platform/geode/Makefile
new file mode 100644 (file)
index 0000000..07c9cd0
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_ALIX)             += alix.o
diff --git a/arch/x86/platform/geode/alix.c b/arch/x86/platform/geode/alix.c
new file mode 100644 (file)
index 0000000..ca19736
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * System Specific setup for PCEngines ALIX.
+ * At the moment this means setup of GPIO control of LEDs
+ * on Alix.2/3/6 boards.
+ *
+ *
+ * Copyright (C) 2008 Constantin Baranov <const@mimas.ru>
+ * Copyright (C) 2011 Ed Wildgoose <kernel@wildgooses.com>
+ *
+ * TODO: There are large similarities with leds-net5501.c
+ * by Alessandro Zummo <a.zummo@towertech.it>
+ * In the future leds-net5501.c should be migrated over to platform
+ *
+ * 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/io.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#include <asm/geode.h>
+
+static int force = 0;
+module_param(force, bool, 0444);
+/* FIXME: Award bios is not automatically detected as Alix platform */
+MODULE_PARM_DESC(force, "Force detection as ALIX.2/ALIX.3 platform");
+
+static struct gpio_led alix_leds[] = {
+       {
+               .name = "alix:1",
+               .gpio = 6,
+               .default_trigger = "default-on",
+               .active_low = 1,
+       },
+       {
+               .name = "alix:2",
+               .gpio = 25,
+               .default_trigger = "default-off",
+               .active_low = 1,
+       },
+       {
+               .name = "alix:3",
+               .gpio = 27,
+               .default_trigger = "default-off",
+               .active_low = 1,
+       },
+};
+
+static struct gpio_led_platform_data alix_leds_data = {
+       .num_leds = ARRAY_SIZE(alix_leds),
+       .leds = alix_leds,
+};
+
+static struct platform_device alix_leds_dev = {
+       .name = "leds-gpio",
+       .id = -1,
+       .dev.platform_data = &alix_leds_data,
+};
+
+static void __init register_alix(void)
+{
+       /* Setup LED control through leds-gpio driver */
+       platform_device_register(&alix_leds_dev);
+}
+
+static int __init alix_present(unsigned long bios_phys,
+                               const char *alix_sig,
+                               size_t alix_sig_len)
+{
+       const size_t bios_len = 0x00010000;
+       const char *bios_virt;
+       const char *scan_end;
+       const char *p;
+       char name[64];
+
+       if (force) {
+               printk(KERN_NOTICE "%s: forced to skip BIOS test, "
+                      "assume system is ALIX.2/ALIX.3\n",
+                      KBUILD_MODNAME);
+               return 1;
+       }
+
+       bios_virt = phys_to_virt(bios_phys);
+       scan_end = bios_virt + bios_len - (alix_sig_len + 2);
+       for (p = bios_virt; p < scan_end; p++) {
+               const char *tail;
+               char *a;
+
+               if (memcmp(p, alix_sig, alix_sig_len) != 0)
+                       continue;
+
+               memcpy(name, p, sizeof(name));
+
+               /* remove the first \0 character from string */
+               a = strchr(name, '\0');
+               if (a)
+                       *a = ' ';
+
+               /* cut the string at a newline */
+               a = strchr(name, '\r');
+               if (a)
+                       *a = '\0';
+
+               tail = p + alix_sig_len;
+               if ((tail[0] == '2' || tail[0] == '3')) {
+                       printk(KERN_INFO
+                              "%s: system is recognized as \"%s\"\n",
+                              KBUILD_MODNAME, name);
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+static int __init alix_init(void)
+{
+       const char tinybios_sig[] = "PC Engines ALIX.";
+       const char coreboot_sig[] = "PC Engines\0ALIX.";
+
+       if (!is_geode())
+               return 0;
+
+       if (alix_present(0xf0000, tinybios_sig, sizeof(tinybios_sig) - 1) ||
+           alix_present(0x500, coreboot_sig, sizeof(coreboot_sig) - 1))
+               register_alix();
+
+       return 0;
+}
+
+module_init(alix_init);
+
+MODULE_AUTHOR("Ed Wildgoose <kernel@wildgooses.com>");
+MODULE_DESCRIPTION("PCEngines ALIX System Setup");
+MODULE_LICENSE("GPL");
index 1ba7f5ed8c9b9e0675b612d358659be9d57dd82a..f1900223aca7e003a48d474f9808a7add8def92a 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <linux/moduleparam.h>
 #include <linux/module.h>
+#include <linux/platform_device.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/delay.h>
@@ -62,29 +63,75 @@ static void iris_power_off(void)
  * by reading its input port and seeing whether the read value is
  * meaningful.
  */
-static int iris_init(void)
+static int iris_probe(struct platform_device *pdev)
 {
-       unsigned char status;
-       if (force != 1) {
-               printk(KERN_ERR "The force parameter has not been set to 1 so the Iris poweroff handler will not be installed.\n");
-               return -ENODEV;
-       }
-       status = inb(IRIS_GIO_INPUT);
+       unsigned char status = inb(IRIS_GIO_INPUT);
        if (status == IRIS_GIO_NODEV) {
-               printk(KERN_ERR "This machine does not seem to be an Iris. Power_off handler not installed.\n");
+               printk(KERN_ERR "This machine does not seem to be an Iris. "
+                       "Power off handler not installed.\n");
                return -ENODEV;
        }
        old_pm_power_off = pm_power_off;
        pm_power_off = &iris_power_off;
        printk(KERN_INFO "Iris power_off handler installed.\n");
-
        return 0;
 }
 
-static void iris_exit(void)
+static int iris_remove(struct platform_device *pdev)
 {
        pm_power_off = old_pm_power_off;
        printk(KERN_INFO "Iris power_off handler uninstalled.\n");
+       return 0;
+}
+
+static struct platform_driver iris_driver = {
+       .driver         = {
+               .name   = "iris",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = iris_probe,
+       .remove         = iris_remove,
+};
+
+static struct resource iris_resources[] = {
+       {
+               .start  = IRIS_GIO_BASE,
+               .end    = IRIS_GIO_OUTPUT,
+               .flags  = IORESOURCE_IO,
+               .name   = "address"
+       }
+};
+
+static struct platform_device *iris_device;
+
+static int iris_init(void)
+{
+       int ret;
+       if (force != 1) {
+               printk(KERN_ERR "The force parameter has not been set to 1."
+                       " The Iris poweroff handler will not be installed.\n");
+               return -ENODEV;
+       }
+       ret = platform_driver_register(&iris_driver);
+       if (ret < 0) {
+               printk(KERN_ERR "Failed to register iris platform driver: %d\n",
+                       ret);
+               return ret;
+       }
+       iris_device = platform_device_register_simple("iris", (-1),
+                               iris_resources, ARRAY_SIZE(iris_resources));
+       if (IS_ERR(iris_device)) {
+               printk(KERN_ERR "Failed to register iris platform device\n");
+               platform_driver_unregister(&iris_driver);
+               return PTR_ERR(iris_device);
+       }
+       return 0;
+}
+
+static void iris_exit(void)
+{
+       platform_device_unregister(iris_device);
+       platform_driver_unregister(&iris_driver);
 }
 
 module_init(iris_init);
index dba1c32e1ddfc48229d93d014fedaa9c370e92e3..a9587ee5136d75d5d48a5f635b13611168d001a9 100644 (file)
@@ -360,7 +360,7 @@ static int brd_make_request(struct request_queue *q, struct bio *bio)
 out:
        bio_endio(bio, err);
 
-       return 0;
+       return err;
 }
 
 #ifdef CONFIG_BLK_DEV_XIP
index 98de8f4186762680a0ea1ccd2d0cf907c1314b40..9955a53733b29c4501e9200d6870d2d771c23312 100644 (file)
@@ -4250,7 +4250,7 @@ static int __init floppy_init(void)
        use_virtual_dma = can_use_virtual_dma & 1;
        fdc_state[0].address = FDC1;
        if (fdc_state[0].address == -1) {
-               del_timer(&fd_timeout);
+               del_timer_sync(&fd_timeout);
                err = -ENODEV;
                goto out_unreg_region;
        }
@@ -4261,7 +4261,7 @@ static int __init floppy_init(void)
        fdc = 0;                /* reset fdc in case of unexpected interrupt */
        err = floppy_grab_irq_and_dma();
        if (err) {
-               del_timer(&fd_timeout);
+               del_timer_sync(&fd_timeout);
                err = -EBUSY;
                goto out_unreg_region;
        }
@@ -4318,7 +4318,7 @@ static int __init floppy_init(void)
                user_reset_fdc(-1, FD_RESET_ALWAYS, false);
        }
        fdc = 0;
-       del_timer(&fd_timeout);
+       del_timer_sync(&fd_timeout);
        current_drive = 0;
        initialized = true;
        if (have_no_fdc) {
@@ -4368,7 +4368,7 @@ out_unreg_blkdev:
        unregister_blkdev(FLOPPY_MAJOR, "fd");
 out_put_disk:
        while (dr--) {
-               del_timer(&motor_off_timer[dr]);
+               del_timer_sync(&motor_off_timer[dr]);
                if (disks[dr]->queue)
                        blk_cleanup_queue(disks[dr]->queue);
                put_disk(disks[dr]);
index 0833896cf6f2aeb98721441619a9fdeae0ae54bb..c9aeb7fce8782c96987a743e19f73c45289827b3 100644 (file)
@@ -263,16 +263,40 @@ static void hpet_timer_set_irq(struct hpet_dev *devp)
 
 static int hpet_open(struct inode *inode, struct file *file)
 {
-       struct hpet_dev *devp;
        struct hpets *hpetp;
-       int i;
 
        if (file->f_mode & FMODE_WRITE)
                return -EINVAL;
 
+       hpetp = hpets;
+       /* starting with timer-neutral instance */
+       file->private_data = &hpetp->hp_dev[hpetp->hp_ntimer];
+
+       return 0;
+}
+
+static int hpet_alloc_timer(struct file *file)
+{
+       struct hpet_dev *devp;
+       struct hpets *hpetp;
+       int i;
+
+       /* once acquired, will remain */
+       devp = file->private_data;
+       if (devp->hd_timer)
+               return 0;
+
        mutex_lock(&hpet_mutex);
        spin_lock_irq(&hpet_lock);
 
+       /* check for race acquiring */
+       devp = file->private_data;
+       if (devp->hd_timer) {
+               spin_unlock_irq(&hpet_lock);
+               mutex_unlock(&hpet_mutex);
+               return 0;
+       }
+
        for (devp = NULL, hpetp = hpets; hpetp && !devp; hpetp = hpetp->hp_next)
                for (i = 0; i < hpetp->hp_ntimer; i++)
                        if (hpetp->hp_dev[i].hd_flags & HPET_OPEN)
@@ -402,6 +426,11 @@ static int hpet_mmap(struct file *file, struct vm_area_struct *vma)
 static int hpet_fasync(int fd, struct file *file, int on)
 {
        struct hpet_dev *devp;
+       int r;
+
+       r = hpet_alloc_timer(file);
+       if (r < 0)
+               return r;
 
        devp = file->private_data;
 
@@ -420,6 +449,9 @@ static int hpet_release(struct inode *inode, struct file *file)
        devp = file->private_data;
        timer = devp->hd_timer;
 
+       if (!timer)
+               goto out;
+
        spin_lock_irq(&hpet_lock);
 
        writeq((readq(&timer->hpet_config) & ~Tn_INT_ENB_CNF_MASK),
@@ -444,7 +476,7 @@ static int hpet_release(struct inode *inode, struct file *file)
 
        if (irq)
                free_irq(irq, devp);
-
+out:
        file->private_data = NULL;
        return 0;
 }
@@ -593,6 +625,9 @@ hpet_ioctl_common(struct hpet_dev *devp, int cmd, unsigned long arg,
                break;
        case HPET_IE_ON:
                return hpet_ioctl_ieon(devp);
+       case HPET_ALLOC_TIMER:
+               /* nothing to do */
+               return 0;
        default:
                return -EINVAL;
        }
@@ -859,7 +894,11 @@ int hpet_alloc(struct hpet_data *hdp)
                return 0;
        }
 
-       siz = sizeof(struct hpets) + ((hdp->hd_nirqs - 1) *
+       /*
+        * last hpet_dev will have null timer pointer, gives timer-neutral
+        * representation of block
+        */
+       siz = sizeof(struct hpets) + ((hdp->hd_nirqs) *
                                      sizeof(struct hpet_dev));
 
        hpetp = kzalloc(siz, GFP_KERNEL);
@@ -925,13 +964,16 @@ int hpet_alloc(struct hpet_data *hdp)
                writeq(mcfg, &hpet->hpet_config);
        }
 
-       for (i = 0, devp = hpetp->hp_dev; i < hpetp->hp_ntimer; i++, devp++) {
+       for (i = 0, devp = hpetp->hp_dev; i < hpetp->hp_ntimer + 1;
+            i++, devp++) {
                struct hpet_timer __iomem *timer;
 
-               timer = &hpet->hpet_timers[devp - hpetp->hp_dev];
-
                devp->hd_hpets = hpetp;
                devp->hd_hpet = hpet;
+               if (i == hpetp->hp_ntimer)
+                       continue;
+
+               timer = &hpet->hpet_timers[devp - hpetp->hp_dev];
                devp->hd_timer = timer;
 
                /*
index bcb1126e3d00b2357a0c5748edbd8b1b470c0423..153980be4ee64462f12a97563c0143fc59b3eb82 100644 (file)
@@ -585,14 +585,12 @@ int dmi_name_in_serial(const char *str)
 }
 
 /**
- *     dmi_name_in_vendors - Check if string is anywhere in the DMI vendor information.
+ *     dmi_name_in_vendors - Check if string is in the DMI system or board vendor name
  *     @str:   Case sensitive Name
  */
 int dmi_name_in_vendors(const char *str)
 {
-       static int fields[] = { DMI_BIOS_VENDOR, DMI_BIOS_VERSION, DMI_SYS_VENDOR,
-                               DMI_PRODUCT_NAME, DMI_PRODUCT_VERSION, DMI_BOARD_VENDOR,
-                               DMI_BOARD_NAME, DMI_BOARD_VERSION, DMI_NONE };
+       static int fields[] = { DMI_SYS_VENDOR, DMI_BOARD_VENDOR, DMI_NONE };
        int i;
        for (i = 0; fields[i] != DMI_NONE; i++) {
                int f = fields[i];
index ac6e0d1bd629c17b57a1dce297c5a04e67f1f402..d51577bc1766cc0f12f23ccc6a4247a6c8e8df51 100644 (file)
@@ -37,7 +37,6 @@
 #include <linux/kernel.h>
 
 struct vmwgfx_gmrid_man {
-       spinlock_t lock;
        struct ida gmr_ida;
        uint32_t max_gmr_ids;
 };
@@ -49,34 +48,20 @@ static int vmw_gmrid_man_get_node(struct ttm_mem_type_manager *man,
 {
        struct vmwgfx_gmrid_man *gman =
                (struct vmwgfx_gmrid_man *)man->priv;
-       int ret;
        int id;
 
        mem->mm_node = NULL;
 
-       do {
-               if (unlikely(ida_pre_get(&gman->gmr_ida, GFP_KERNEL) == 0))
-                       return -ENOMEM;
-
-               spin_lock(&gman->lock);
-               ret = ida_get_new(&gman->gmr_ida, &id);
-
-               if (unlikely(ret == 0 && id >= gman->max_gmr_ids)) {
-                       ida_remove(&gman->gmr_ida, id);
-                       spin_unlock(&gman->lock);
+       id = ida_simple_get(&gman->gmr_ida, 0, gman->max_gmr_ids, GFP_KERNEL);
+       if (id < 0) {
+               if (id == -ENOSPC)
                        return 0;
-               }
-
-               spin_unlock(&gman->lock);
-
-       } while (ret == -EAGAIN);
-
-       if (likely(ret == 0)) {
-               mem->mm_node = gman;
-               mem->start = id;
+               return id;
        }
+       mem->mm_node = gman;
+       mem->start = id;
 
-       return ret;
+       return 0;
 }
 
 static void vmw_gmrid_man_put_node(struct ttm_mem_type_manager *man,
@@ -86,9 +71,7 @@ static void vmw_gmrid_man_put_node(struct ttm_mem_type_manager *man,
                (struct vmwgfx_gmrid_man *)man->priv;
 
        if (mem->mm_node) {
-               spin_lock(&gman->lock);
-               ida_remove(&gman->gmr_ida, mem->start);
-               spin_unlock(&gman->lock);
+               ida_simple_remove(&gman->gmr_ida, mem->start);
                mem->mm_node = NULL;
        }
 }
@@ -102,7 +85,6 @@ static int vmw_gmrid_man_init(struct ttm_mem_type_manager *man,
        if (unlikely(gman == NULL))
                return -ENOMEM;
 
-       spin_lock_init(&gman->lock);
        ida_init(&gman->gmr_ida);
        gman->max_gmr_ids = p_size;
        man->priv = (void *) gman;
index a61e7815a2a9153f7ad82e8dc2ff49273763c19a..6460487e41b50f8c99b96ea61c09a566cf0aa170 100644 (file)
@@ -27,8 +27,7 @@
 
 static struct class *hwmon_class;
 
-static DEFINE_IDR(hwmon_idr);
-static DEFINE_SPINLOCK(idr_lock);
+static DEFINE_IDA(hwmon_ida);
 
 /**
  * hwmon_device_register - register w/ hwmon
@@ -42,30 +41,17 @@ static DEFINE_SPINLOCK(idr_lock);
 struct device *hwmon_device_register(struct device *dev)
 {
        struct device *hwdev;
-       int id, err;
-
-again:
-       if (unlikely(idr_pre_get(&hwmon_idr, GFP_KERNEL) == 0))
-               return ERR_PTR(-ENOMEM);
-
-       spin_lock(&idr_lock);
-       err = idr_get_new(&hwmon_idr, NULL, &id);
-       spin_unlock(&idr_lock);
+       int id;
 
-       if (unlikely(err == -EAGAIN))
-               goto again;
-       else if (unlikely(err))
-               return ERR_PTR(err);
+       id = ida_simple_get(&hwmon_ida, 0, 0, GFP_KERNEL);
+       if (id < 0)
+               return ERR_PTR(id);
 
-       id = id & MAX_ID_MASK;
        hwdev = device_create(hwmon_class, dev, MKDEV(0, 0), NULL,
                              HWMON_ID_FORMAT, id);
 
-       if (IS_ERR(hwdev)) {
-               spin_lock(&idr_lock);
-               idr_remove(&hwmon_idr, id);
-               spin_unlock(&idr_lock);
-       }
+       if (IS_ERR(hwdev))
+               ida_simple_remove(&hwmon_ida, id);
 
        return hwdev;
 }
@@ -81,9 +67,7 @@ void hwmon_device_unregister(struct device *dev)
 
        if (likely(sscanf(dev_name(dev), HWMON_ID_FORMAT, &id) == 1)) {
                device_unregister(dev);
-               spin_lock(&idr_lock);
-               idr_remove(&hwmon_idr, id);
-               spin_unlock(&idr_lock);
+               ida_simple_remove(&hwmon_ida, id);
        } else
                dev_dbg(dev->parent,
                        "hwmon_device_unregister() failed: bad class ID!\n");
index c316294c48b47ba848f5844270e0394d13e2be87..783d0c17b762dc504babef2e5a039c033b3d8f77 100644 (file)
@@ -88,8 +88,7 @@
 #define AEM_MIN_POWER_INTERVAL 200
 #define UJ_PER_MJ              1000L
 
-static DEFINE_IDR(aem_idr);
-static DEFINE_SPINLOCK(aem_idr_lock);
+static DEFINE_IDA(aem_ida);
 
 static struct platform_driver aem_driver = {
        .driver = {
@@ -356,38 +355,6 @@ static void aem_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data)
        complete(&data->read_complete);
 }
 
-/* ID functions */
-
-/* Obtain an id */
-static int aem_idr_get(int *id)
-{
-       int i, err;
-
-again:
-       if (unlikely(!idr_pre_get(&aem_idr, GFP_KERNEL)))
-               return -ENOMEM;
-
-       spin_lock(&aem_idr_lock);
-       err = idr_get_new(&aem_idr, NULL, &i);
-       spin_unlock(&aem_idr_lock);
-
-       if (unlikely(err == -EAGAIN))
-               goto again;
-       else if (unlikely(err))
-               return err;
-
-       *id = i & MAX_ID_MASK;
-       return 0;
-}
-
-/* Release an object ID */
-static void aem_idr_put(int id)
-{
-       spin_lock(&aem_idr_lock);
-       idr_remove(&aem_idr, id);
-       spin_unlock(&aem_idr_lock);
-}
-
 /* Sensor support functions */
 
 /* Read a sensor value */
@@ -530,7 +497,7 @@ static void aem_delete(struct aem_data *data)
        ipmi_destroy_user(data->ipmi.user);
        platform_set_drvdata(data->pdev, NULL);
        platform_device_unregister(data->pdev);
-       aem_idr_put(data->id);
+       ida_simple_remove(&aem_ida, data->id);
        kfree(data);
 }
 
@@ -587,7 +554,8 @@ static int aem_init_aem1_inst(struct aem_ipmi_data *probe, u8 module_handle)
                data->power_period[i] = AEM_DEFAULT_POWER_INTERVAL;
 
        /* Create sub-device for this fw instance */
-       if (aem_idr_get(&data->id))
+       data->id = ida_simple_get(&aem_ida, 0, 0, GFP_KERNEL);
+       if (data->id < 0)
                goto id_err;
 
        data->pdev = platform_device_alloc(DRVNAME, data->id);
@@ -638,7 +606,7 @@ ipmi_err:
        platform_set_drvdata(data->pdev, NULL);
        platform_device_unregister(data->pdev);
 dev_err:
-       aem_idr_put(data->id);
+       ida_simple_remove(&aem_ida, data->id);
 id_err:
        kfree(data);
 
@@ -720,7 +688,8 @@ static int aem_init_aem2_inst(struct aem_ipmi_data *probe,
                data->power_period[i] = AEM_DEFAULT_POWER_INTERVAL;
 
        /* Create sub-device for this fw instance */
-       if (aem_idr_get(&data->id))
+       data->id = ida_simple_get(&aem_ida, 0, 0, GFP_KERNEL);
+       if (data->id < 0)
                goto id_err;
 
        data->pdev = platform_device_alloc(DRVNAME, data->id);
@@ -771,7 +740,7 @@ ipmi_err:
        platform_set_drvdata(data->pdev, NULL);
        platform_device_unregister(data->pdev);
 dev_err:
-       aem_idr_put(data->id);
+       ida_simple_remove(&aem_ida, data->id);
 id_err:
        kfree(data);
 
index 18767f8ab090a409c512db7ba29bf4b8d56cb2f2..86e1850e1380a72f9cc0a44e7a5700e7b94e2d21 100644 (file)
@@ -271,33 +271,42 @@ static void __setup_broadcast_timer(void *arg)
        clockevents_notify(reason, &cpu);
 }
 
-static int setup_broadcast_cpuhp_notify(struct notifier_block *n,
+static void auto_demotion_disable(void *dummy)
+{
+       unsigned long long msr_bits;
+
+       rdmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr_bits);
+       msr_bits &= ~auto_demotion_disable_flags;
+       wrmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr_bits);
+}
+
+static void __intel_idle_notify_handler(void *arg)
+{
+       if (auto_demotion_disable_flags)
+               auto_demotion_disable(NULL);
+
+       if (lapic_timer_reliable_states != LAPIC_TIMER_ALWAYS_RELIABLE)
+               __setup_broadcast_timer((void *)true);
+}
+
+static int setup_intelidle_cpuhp_notify(struct notifier_block *n,
                unsigned long action, void *hcpu)
 {
        int hotcpu = (unsigned long)hcpu;
 
        switch (action & 0xf) {
        case CPU_ONLINE:
-               smp_call_function_single(hotcpu, __setup_broadcast_timer,
-                       (void *)true, 1);
+               smp_call_function_single(hotcpu, __intel_idle_notify_handler,
+                       NULL, 1);
                break;
        }
        return NOTIFY_OK;
 }
 
-static struct notifier_block setup_broadcast_notifier = {
-       .notifier_call = setup_broadcast_cpuhp_notify,
+static struct notifier_block setup_intelidle_notifier = {
+       .notifier_call = setup_intelidle_cpuhp_notify,
 };
 
-static void auto_demotion_disable(void *dummy)
-{
-       unsigned long long msr_bits;
-
-       rdmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr_bits);
-       msr_bits &= ~auto_demotion_disable_flags;
-       wrmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr_bits);
-}
-
 /*
  * intel_idle_probe()
  */
@@ -367,10 +376,8 @@ static int intel_idle_probe(void)
 
        if (boot_cpu_has(X86_FEATURE_ARAT))     /* Always Reliable APIC Timer */
                lapic_timer_reliable_states = LAPIC_TIMER_ALWAYS_RELIABLE;
-       else {
-               smp_call_function(__setup_broadcast_timer, (void *)true, 1);
-               register_cpu_notifier(&setup_broadcast_notifier);
-       }
+       else
+               on_each_cpu(__setup_broadcast_timer, (void *)true, 1);
 
        pr_debug(PREFIX "v" INTEL_IDLE_VERSION
                " model 0x%X\n", boot_cpu_data.x86_model);
@@ -460,7 +467,7 @@ static int intel_idle_cpuidle_devices_init(void)
                }
        }
        if (auto_demotion_disable_flags)
-               smp_call_function(auto_demotion_disable, NULL, 1);
+               on_each_cpu(auto_demotion_disable, NULL, 1);
 
        return 0;
 }
@@ -491,6 +498,10 @@ static int __init intel_idle_init(void)
                return retval;
        }
 
+       if (auto_demotion_disable_flags || lapic_timer_reliable_states !=
+           LAPIC_TIMER_ALWAYS_RELIABLE)
+               register_cpu_notifier(&setup_intelidle_notifier);
+
        return 0;
 }
 
@@ -499,10 +510,12 @@ static void __exit intel_idle_exit(void)
        intel_idle_cpuidle_devices_uninit();
        cpuidle_unregister_driver(&intel_idle_driver);
 
-       if (lapic_timer_reliable_states != LAPIC_TIMER_ALWAYS_RELIABLE) {
-               smp_call_function(__setup_broadcast_timer, (void *)false, 1);
-               unregister_cpu_notifier(&setup_broadcast_notifier);
-       }
+       if (lapic_timer_reliable_states != LAPIC_TIMER_ALWAYS_RELIABLE)
+               on_each_cpu(__setup_broadcast_timer, (void *)false, 1);
+
+       if (auto_demotion_disable_flags || lapic_timer_reliable_states !=
+           LAPIC_TIMER_ALWAYS_RELIABLE)
+               unregister_cpu_notifier(&setup_intelidle_notifier);
 
        return;
 }
index 3dc9befa5aec06343691474420ad203963119bdb..f0db877d71e6043133a373f7776a27292f10676c 100644 (file)
@@ -263,7 +263,7 @@ rmrr_parse_dev(struct dmar_rmrr_unit *rmrru)
        return ret;
 }
 
-static LIST_HEAD(dmar_atsr_units);
+LIST_HEAD(dmar_atsr_units);
 
 static int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr)
 {
@@ -277,6 +277,7 @@ static int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr)
 
        atsru->hdr = hdr;
        atsru->include_all = atsr->flags & 0x1;
+       atsru->segment = atsr->segment;
 
        list_add(&atsru->list, &dmar_atsr_units);
 
@@ -308,14 +309,12 @@ int dmar_find_matched_atsr_unit(struct pci_dev *dev)
 {
        int i;
        struct pci_bus *bus;
-       struct acpi_dmar_atsr *atsr;
        struct dmar_atsr_unit *atsru;
 
        dev = pci_physfn(dev);
 
        list_for_each_entry(atsru, &dmar_atsr_units, list) {
-               atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
-               if (atsr->segment == pci_domain_nr(dev->bus))
+               if (atsru->segment == pci_domain_nr(dev->bus))
                        goto found;
        }
 
index c621c98c99da00886931b3aed1b8364c7de6b958..1d85ed6615ab2c8e0ebf5f63811feb1c2be70d15 100644 (file)
@@ -633,6 +633,157 @@ static struct intel_iommu *device_to_iommu(int segment, u8 bus, u8 devfn)
        return NULL;
 }
 
+#ifdef CONFIG_HOTPLUG
+struct dev_dmaru {
+       struct list_head list;
+       void *dmaru;
+       int index;
+       int segment;
+       unsigned char bus;
+       unsigned int devfn;
+};
+
+static int
+save_dev_dmaru(int segment, unsigned char bus, unsigned int devfn,
+                void *dmaru, int index, struct list_head *lh)
+{
+       struct dev_dmaru *m;
+
+       m = kzalloc(sizeof(*m), GFP_KERNEL);
+       if (!m)
+               return -ENOMEM;
+
+       m->segment = segment;
+       m->bus     = bus;
+       m->devfn   = devfn;
+       m->dmaru   = dmaru;
+       m->index   = index;
+
+       list_add(&m->list, lh);
+
+       return 0;
+}
+
+static void
+*get_dev_dmaru(int segment, unsigned char bus, unsigned int devfn,
+               int *index, struct list_head *lh)
+{
+       struct dev_dmaru *m;
+       void *dmaru = NULL;
+
+       list_for_each_entry(m, lh, list) {
+               if (m->segment == segment &&
+                   m->bus == bus && m->devfn == devfn) {
+                       *index = m->index;
+                       dmaru  = m->dmaru;
+                       list_del(&m->list);
+                       kfree(m);
+                       break;
+               }
+       }
+
+       return dmaru;
+}
+
+static LIST_HEAD(saved_dev_drhd_list);
+
+static void remove_dev_from_drhd(struct pci_dev *dev)
+{
+       struct dmar_drhd_unit *drhd = NULL;
+       int segment = pci_domain_nr(dev->bus);
+       int i;
+
+       for_each_drhd_unit(drhd) {
+               if (drhd->ignored)
+                       continue;
+               if (segment != drhd->segment)
+                       continue;
+
+               for (i = 0; i < drhd->devices_cnt; i++) {
+                       if (drhd->devices[i] == dev) {
+                               /* save it at first if it is in drhd */
+                               save_dev_dmaru(segment, dev->bus->number,
+                                               dev->devfn, drhd, i,
+                                               &saved_dev_drhd_list);
+                               /* always remove it */
+                               drhd->devices[i] = NULL;
+                               return;
+                       }
+               }
+       }
+}
+
+static void restore_dev_to_drhd(struct pci_dev *dev)
+{
+       struct dmar_drhd_unit *drhd = NULL;
+       int i;
+
+       /* find the stored drhd */
+       drhd = get_dev_dmaru(pci_domain_nr(dev->bus), dev->bus->number,
+                                dev->devfn, &i, &saved_dev_drhd_list);
+       /* restore that into drhd */
+       if (drhd)
+               drhd->devices[i] = dev;
+}
+#else
+static void remove_dev_from_drhd(struct pci_dev *dev)
+{
+}
+
+static void restore_dev_to_drhd(struct pci_dev *dev)
+{
+}
+#endif
+
+#if defined(CONFIG_DMAR) && defined(CONFIG_HOTPLUG)
+static LIST_HEAD(saved_dev_atsr_list);
+
+static void remove_dev_from_atsr(struct pci_dev *dev)
+{
+       struct dmar_atsr_unit *atsr = NULL;
+       int segment = pci_domain_nr(dev->bus);
+       int i;
+
+       for_each_atsr_unit(atsr) {
+               if (segment != atsr->segment)
+                       continue;
+
+               for (i = 0; i < atsr->devices_cnt; i++) {
+                       if (atsr->devices[i] == dev) {
+                               /* save it at first if it is in drhd */
+                               save_dev_dmaru(segment, dev->bus->number,
+                                               dev->devfn, atsr, i,
+                                               &saved_dev_atsr_list);
+                               /* always remove it */
+                               atsr->devices[i] = NULL;
+                               return;
+                       }
+               }
+       }
+}
+
+static void restore_dev_to_atsr(struct pci_dev *dev)
+{
+       struct dmar_atsr_unit *atsr = NULL;
+       int i;
+
+       /* find the stored atsr */
+       atsr = get_dev_dmaru(pci_domain_nr(dev->bus), dev->bus->number,
+                                dev->devfn, &i, &saved_dev_atsr_list);
+       /* restore that into atsr */
+       if (atsr)
+               atsr->devices[i] = dev;
+}
+#else
+static void remove_dev_from_atsr(struct pci_dev *dev)
+{
+}
+
+static void restore_dev_to_atsr(struct pci_dev *dev)
+{
+}
+#endif
+
 static void domain_flush_cache(struct dmar_domain *domain,
                               void *addr, int size)
 {
@@ -3403,20 +3554,36 @@ static int device_notifier(struct notifier_block *nb,
        struct pci_dev *pdev = to_pci_dev(dev);
        struct dmar_domain *domain;
 
-       if (iommu_no_mapping(dev))
+       if (unlikely(dev->bus != &pci_bus_type))
                return 0;
 
-       domain = find_domain(pdev);
-       if (!domain)
-               return 0;
+       switch (action) {
+       case BUS_NOTIFY_UNBOUND_DRIVER:
+               if (iommu_no_mapping(dev))
+                       goto out;
+
+               if (iommu_pass_through)
+                       goto out;
+
+               domain = find_domain(pdev);
+               if (!domain)
+                       goto out;
 
-       if (action == BUS_NOTIFY_UNBOUND_DRIVER && !iommu_pass_through) {
                domain_remove_one_dev_info(domain, pdev);
 
                if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) &&
                    !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) &&
                    list_empty(&domain->devices))
                        domain_exit(domain);
+out:
+               remove_dev_from_drhd(pdev);
+               remove_dev_from_atsr(pdev);
+
+               break;
+       case BUS_NOTIFY_ADD_DEVICE:
+               restore_dev_to_drhd(pdev);
+               restore_dev_to_atsr(pdev);
+               break;
        }
 
        return 0;
index b591e726a6fa53982b6e22c515d0ad980a6697df..b3e767414f777cae48ba8da1d6d45a7167c52c28 100644 (file)
@@ -113,14 +113,6 @@ config LEDS_WRAP
        help
          This option enables support for the PCEngines WRAP programmable LEDs.
 
-config LEDS_ALIX2
-       tristate "LED Support for ALIX.2 and ALIX.3 series"
-       depends on LEDS_CLASS
-       depends on X86 && !GPIO_CS5535 && !CS5535_GPIO
-       help
-         This option enables support for the PCEngines ALIX.2 and ALIX.3 LEDs.
-         You have to set leds-alix2.force=1 for boards with Award BIOS.
-
 config LEDS_COBALT_QUBE
        tristate "LED Support for the Cobalt Qube series front LED"
        depends on LEDS_CLASS
@@ -383,6 +375,18 @@ config LEDS_ASIC3
          cannot be used. This driver supports hardware blinking with an on+off
          period from 62ms to 125s. Say Y to enable LEDs on the HP iPAQ hx4700.
 
+config LEDS_RENESAS_TPU
+       bool "LED support for Renesas TPU"
+       depends on LEDS_CLASS && HAVE_CLK && GENERIC_GPIO
+       help
+         This option enables build of the LED TPU platform driver,
+         suitable to drive any TPU channel on newer Renesas SoCs.
+         The driver controls the GPIO pin connected to the LED via
+         the GPIO framework and expects the LED to be connected to
+         a pin that can be driven in both GPIO mode and using TPU
+         pin function. The latter to support brightness control.
+         Brightness control is supported but hardware blinking is not.
+
 config LEDS_TRIGGERS
        bool "LED Trigger support"
        depends on LEDS_CLASS
index bbfd2e367dc0e8a6b917c2c94b092bfa66bea35e..e4f6bf568880d284cc4743e4cb6231b450d57296 100644 (file)
@@ -16,7 +16,6 @@ obj-$(CONFIG_LEDS_AMS_DELTA)          += leds-ams-delta.o
 obj-$(CONFIG_LEDS_NET48XX)             += leds-net48xx.o
 obj-$(CONFIG_LEDS_NET5501)             += leds-net5501.o
 obj-$(CONFIG_LEDS_WRAP)                        += leds-wrap.o
-obj-$(CONFIG_LEDS_ALIX2)               += leds-alix2.o
 obj-$(CONFIG_LEDS_COBALT_QUBE)         += leds-cobalt-qube.o
 obj-$(CONFIG_LEDS_COBALT_RAQ)          += leds-cobalt-raq.o
 obj-$(CONFIG_LEDS_SUNFIRE)             += leds-sunfire.o
@@ -43,6 +42,7 @@ obj-$(CONFIG_LEDS_MC13783)            += leds-mc13783.o
 obj-$(CONFIG_LEDS_NS2)                 += leds-ns2.o
 obj-$(CONFIG_LEDS_NETXBIG)             += leds-netxbig.o
 obj-$(CONFIG_LEDS_ASIC3)               += leds-asic3.o
+obj-$(CONFIG_LEDS_RENESAS_TPU)         += leds-renesas-tpu.o
 
 # LED SPI Drivers
 obj-$(CONFIG_LEDS_DAC124S085)          += leds-dac124s085.o
diff --git a/drivers/leds/leds-alix2.c b/drivers/leds/leds-alix2.c
deleted file mode 100644 (file)
index f59ffad..0000000
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * LEDs driver for PCEngines ALIX.2 and ALIX.3
- *
- * Copyright (C) 2008 Constantin Baranov <const@mimas.ru>
- */
-
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/leds.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/string.h>
-#include <linux/pci.h>
-
-static int force = 0;
-module_param(force, bool, 0444);
-MODULE_PARM_DESC(force, "Assume system has ALIX.2/ALIX.3 style LEDs");
-
-#define MSR_LBAR_GPIO          0x5140000C
-#define CS5535_GPIO_SIZE       256
-
-static u32 gpio_base;
-
-static struct pci_device_id divil_pci[] = {
-       { PCI_DEVICE(PCI_VENDOR_ID_NS,  PCI_DEVICE_ID_NS_CS5535_ISA) },
-       { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) },
-       { } /* NULL entry */
-};
-MODULE_DEVICE_TABLE(pci, divil_pci);
-
-struct alix_led {
-       struct led_classdev cdev;
-       unsigned short port;
-       unsigned int on_value;
-       unsigned int off_value;
-};
-
-static void alix_led_set(struct led_classdev *led_cdev,
-                        enum led_brightness brightness)
-{
-       struct alix_led *led_dev =
-               container_of(led_cdev, struct alix_led, cdev);
-
-       if (brightness)
-               outl(led_dev->on_value, gpio_base + led_dev->port);
-       else
-               outl(led_dev->off_value, gpio_base + led_dev->port);
-}
-
-static struct alix_led alix_leds[] = {
-       {
-               .cdev = {
-                       .name = "alix:1",
-                       .brightness_set = alix_led_set,
-               },
-               .port = 0x00,
-               .on_value = 1 << 22,
-               .off_value = 1 << 6,
-       },
-       {
-               .cdev = {
-                       .name = "alix:2",
-                       .brightness_set = alix_led_set,
-               },
-               .port = 0x80,
-               .on_value = 1 << 25,
-               .off_value = 1 << 9,
-       },
-       {
-               .cdev = {
-                       .name = "alix:3",
-                       .brightness_set = alix_led_set,
-               },
-               .port = 0x80,
-               .on_value = 1 << 27,
-               .off_value = 1 << 11,
-       },
-};
-
-static int __init alix_led_probe(struct platform_device *pdev)
-{
-       int i;
-       int ret;
-
-       for (i = 0; i < ARRAY_SIZE(alix_leds); i++) {
-               alix_leds[i].cdev.flags |= LED_CORE_SUSPENDRESUME;
-               ret = led_classdev_register(&pdev->dev, &alix_leds[i].cdev);
-               if (ret < 0)
-                       goto fail;
-       }
-       return 0;
-
-fail:
-       while (--i >= 0)
-               led_classdev_unregister(&alix_leds[i].cdev);
-       return ret;
-}
-
-static int alix_led_remove(struct platform_device *pdev)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(alix_leds); i++)
-               led_classdev_unregister(&alix_leds[i].cdev);
-       return 0;
-}
-
-static struct platform_driver alix_led_driver = {
-       .remove = alix_led_remove,
-       .driver = {
-               .name = KBUILD_MODNAME,
-               .owner = THIS_MODULE,
-       },
-};
-
-static int __init alix_present(unsigned long bios_phys,
-                               const char *alix_sig,
-                               size_t alix_sig_len)
-{
-       const size_t bios_len = 0x00010000;
-       const char *bios_virt;
-       const char *scan_end;
-       const char *p;
-       char name[64];
-
-       if (force) {
-               printk(KERN_NOTICE "%s: forced to skip BIOS test, "
-                      "assume system has ALIX.2 style LEDs\n",
-                      KBUILD_MODNAME);
-               return 1;
-       }
-
-       bios_virt = phys_to_virt(bios_phys);
-       scan_end = bios_virt + bios_len - (alix_sig_len + 2);
-       for (p = bios_virt; p < scan_end; p++) {
-               const char *tail;
-               char *a;
-
-               if (memcmp(p, alix_sig, alix_sig_len) != 0)
-                       continue;
-
-               memcpy(name, p, sizeof(name));
-
-               /* remove the first \0 character from string */
-               a = strchr(name, '\0');
-               if (a)
-                       *a = ' ';
-
-               /* cut the string at a newline */
-               a = strchr(name, '\r');
-               if (a)
-                       *a = '\0';
-
-               tail = p + alix_sig_len;
-               if ((tail[0] == '2' || tail[0] == '3')) {
-                       printk(KERN_INFO
-                              "%s: system is recognized as \"%s\"\n",
-                              KBUILD_MODNAME, name);
-                       return 1;
-               }
-       }
-
-       return 0;
-}
-
-static struct platform_device *pdev;
-
-static int __init alix_pci_led_init(void)
-{
-       u32 low, hi;
-
-       if (pci_dev_present(divil_pci) == 0) {
-               printk(KERN_WARNING KBUILD_MODNAME": DIVIL not found\n");
-               return -ENODEV;
-       }
-
-       /* Grab the GPIO I/O range */
-       rdmsr(MSR_LBAR_GPIO, low, hi);
-
-       /* Check the mask and whether GPIO is enabled (sanity check) */
-       if (hi != 0x0000f001) {
-               printk(KERN_WARNING KBUILD_MODNAME": GPIO not enabled\n");
-               return -ENODEV;
-       }
-
-       /* Mask off the IO base address */
-       gpio_base = low & 0x0000ff00;
-
-       if (!request_region(gpio_base, CS5535_GPIO_SIZE, KBUILD_MODNAME)) {
-               printk(KERN_ERR KBUILD_MODNAME": can't allocate I/O for GPIO\n");
-               return -ENODEV;
-       }
-
-       /* Set GPIO function to output */
-       outl(1 << 6, gpio_base + 0x04);
-       outl(1 << 9, gpio_base + 0x84);
-       outl(1 << 11, gpio_base + 0x84);
-
-       return 0;
-}
-
-static int __init alix_led_init(void)
-{
-       int ret = -ENODEV;
-       const char tinybios_sig[] = "PC Engines ALIX.";
-       const char coreboot_sig[] = "PC Engines\0ALIX.";
-
-       if (alix_present(0xf0000, tinybios_sig, sizeof(tinybios_sig) - 1) ||
-           alix_present(0x500, coreboot_sig, sizeof(coreboot_sig) - 1))
-               ret = alix_pci_led_init();
-
-       if (ret < 0)
-               return ret;
-
-       pdev = platform_device_register_simple(KBUILD_MODNAME, -1, NULL, 0);
-       if (!IS_ERR(pdev)) {
-               ret = platform_driver_probe(&alix_led_driver, alix_led_probe);
-               if (ret)
-                       platform_device_unregister(pdev);
-       } else
-               ret = PTR_ERR(pdev);
-
-       return ret;
-}
-
-static void __exit alix_led_exit(void)
-{
-       platform_device_unregister(pdev);
-       platform_driver_unregister(&alix_led_driver);
-       release_region(gpio_base, CS5535_GPIO_SIZE);
-}
-
-module_init(alix_led_init);
-module_exit(alix_led_exit);
-
-MODULE_AUTHOR("Constantin Baranov <const@mimas.ru>");
-MODULE_DESCRIPTION("PCEngines ALIX.2 and ALIX.3 LED driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/leds/leds-renesas-tpu.c b/drivers/leds/leds-renesas-tpu.c
new file mode 100644 (file)
index 0000000..5bfb40e
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * LED control using Renesas TPU
+ *
+ *  Copyright (C) 2011 Magnus Damm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/printk.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/leds.h>
+#include <linux/leds-renesas-tpu.h>
+#include <linux/gpio.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+
+enum r_tpu_pin { R_TPU_PIN_UNUSED, R_TPU_PIN_GPIO, R_TPU_PIN_GPIO_FN };
+enum r_tpu_timer { R_TPU_TIMER_UNUSED, R_TPU_TIMER_ON };
+
+struct r_tpu_priv {
+       struct led_classdev ldev;
+       void __iomem *mapbase;
+       struct clk *clk;
+       struct platform_device *pdev;
+       enum r_tpu_pin pin_state;
+       enum r_tpu_timer timer_state;
+       unsigned long min_rate;
+       unsigned int refresh_rate;
+};
+
+static DEFINE_SPINLOCK(r_tpu_lock);
+
+#define TSTR -1 /* Timer start register (shared register) */
+#define TCR  0 /* Timer control register (+0x00) */
+#define TMDR 1 /* Timer mode register (+0x04) */
+#define TIOR 2 /* Timer I/O control register (+0x08) */
+#define TIER 3 /* Timer interrupt enable register (+0x0c) */
+#define TSR  4 /* Timer status register (+0x10) */
+#define TCNT 5 /* Timer counter (+0x14) */
+#define TGRA 6 /* Timer general register A (+0x18) */
+#define TGRB 7 /* Timer general register B (+0x1c) */
+#define TGRC 8 /* Timer general register C (+0x20) */
+#define TGRD 9 /* Timer general register D (+0x24) */
+
+static inline unsigned short r_tpu_read(struct r_tpu_priv *p, int reg_nr)
+{
+       struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data;
+       void __iomem *base = p->mapbase;
+       unsigned long offs = reg_nr << 2;
+
+       if (reg_nr == TSTR)
+               return ioread16(base - cfg->channel_offset);
+
+       return ioread16(base + offs);
+}
+
+static inline void r_tpu_write(struct r_tpu_priv *p, int reg_nr,
+                              unsigned short value)
+{
+       struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data;
+       void __iomem *base = p->mapbase;
+       unsigned long offs = reg_nr << 2;
+
+       if (reg_nr == TSTR) {
+               iowrite16(value, base - cfg->channel_offset);
+               return;
+       }
+
+       iowrite16(value, base + offs);
+}
+
+static void r_tpu_start_stop_ch(struct r_tpu_priv *p, int start)
+{
+       struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data;
+       unsigned long flags, value;
+
+       /* start stop register shared by multiple timer channels */
+       spin_lock_irqsave(&r_tpu_lock, flags);
+       value = r_tpu_read(p, TSTR);
+
+       if (start)
+               value |= 1 << cfg->timer_bit;
+       else
+               value &= ~(1 << cfg->timer_bit);
+
+       r_tpu_write(p, TSTR, value);
+       spin_unlock_irqrestore(&r_tpu_lock, flags);
+}
+
+static int r_tpu_enable(struct r_tpu_priv *p, enum led_brightness brightness)
+{
+       struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data;
+       int prescaler[] = { 1, 4, 16, 64 };
+       int k, ret;
+       unsigned long rate, tmp;
+
+       if (p->timer_state == R_TPU_TIMER_ON)
+               return 0;
+
+       /* wake up device and enable clock */
+       pm_runtime_get_sync(&p->pdev->dev);
+       ret = clk_enable(p->clk);
+       if (ret) {
+               dev_err(&p->pdev->dev, "cannot enable clock\n");
+               return ret;
+       }
+
+       /* make sure channel is disabled */
+       r_tpu_start_stop_ch(p, 0);
+
+       /* get clock rate after enabling it */
+       rate = clk_get_rate(p->clk);
+
+       /* pick the lowest acceptable rate */
+       for (k = 0; k < ARRAY_SIZE(prescaler); k++)
+               if ((rate / prescaler[k]) < p->min_rate)
+                       break;
+
+       if (!k) {
+               dev_err(&p->pdev->dev, "clock rate mismatch\n");
+               goto err0;
+       }
+       dev_dbg(&p->pdev->dev, "rate = %lu, prescaler %u\n",
+               rate, prescaler[k - 1]);
+
+       /* clear TCNT on TGRB match, count on rising edge, set prescaler */
+       r_tpu_write(p, TCR, 0x0040 | (k - 1));
+
+       /* output 0 until TGRA, output 1 until TGRB */
+       r_tpu_write(p, TIOR, 0x0002);
+
+       rate /= prescaler[k - 1] * p->refresh_rate;
+       r_tpu_write(p, TGRB, rate);
+       dev_dbg(&p->pdev->dev, "TRGB = 0x%04lx\n", rate);
+
+       tmp = (cfg->max_brightness - brightness) * rate;
+       r_tpu_write(p, TGRA, tmp / cfg->max_brightness);
+       dev_dbg(&p->pdev->dev, "TRGA = 0x%04lx\n", tmp / cfg->max_brightness);
+
+       /* PWM mode */
+       r_tpu_write(p, TMDR, 0x0002);
+
+       /* enable channel */
+       r_tpu_start_stop_ch(p, 1);
+
+       p->timer_state = R_TPU_TIMER_ON;
+       return 0;
+ err0:
+       clk_disable(p->clk);
+       pm_runtime_put_sync(&p->pdev->dev);
+       return -ENOTSUPP;
+}
+
+static void r_tpu_disable(struct r_tpu_priv *p)
+{
+       if (p->timer_state == R_TPU_TIMER_UNUSED)
+               return;
+
+       /* disable channel */
+       r_tpu_start_stop_ch(p, 0);
+
+       /* stop clock and mark device as idle */
+       clk_disable(p->clk);
+       pm_runtime_put_sync(&p->pdev->dev);
+
+       p->timer_state = R_TPU_TIMER_UNUSED;
+}
+
+static void r_tpu_set_pin(struct r_tpu_priv *p, enum r_tpu_pin new_state,
+                         enum led_brightness brightness)
+{
+       struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data;
+
+       if (p->pin_state == new_state) {
+               if (p->pin_state == R_TPU_PIN_GPIO)
+                       gpio_set_value(cfg->pin_gpio, brightness);
+               return;
+       }
+
+       if (p->pin_state == R_TPU_PIN_GPIO)
+               gpio_free(cfg->pin_gpio);
+
+       if (p->pin_state == R_TPU_PIN_GPIO_FN)
+               gpio_free(cfg->pin_gpio_fn);
+
+       if (new_state == R_TPU_PIN_GPIO) {
+               gpio_request(cfg->pin_gpio, cfg->name);
+               gpio_direction_output(cfg->pin_gpio, !!brightness);
+       }
+       if (new_state == R_TPU_PIN_GPIO_FN)
+               gpio_request(cfg->pin_gpio_fn, cfg->name);
+
+       p->pin_state = new_state;
+}
+
+static void r_tpu_set_brightness(struct led_classdev *ldev,
+                                enum led_brightness brightness)
+{
+       struct r_tpu_priv *p = container_of(ldev, struct r_tpu_priv, ldev);
+
+       r_tpu_disable(p);
+
+       /* off and maximum are handled as GPIO pins, in between PWM */
+       if ((brightness == 0) || (brightness == ldev->max_brightness))
+               r_tpu_set_pin(p, R_TPU_PIN_GPIO, brightness);
+       else {
+               r_tpu_set_pin(p, R_TPU_PIN_GPIO_FN, 0);
+               r_tpu_enable(p, brightness);
+       }
+}
+
+static int __devinit r_tpu_probe(struct platform_device *pdev)
+{
+       struct led_renesas_tpu_config *cfg = pdev->dev.platform_data;
+       struct r_tpu_priv *p;
+       struct resource *res;
+       int ret = -ENXIO;
+
+       if (!cfg) {
+               dev_err(&pdev->dev, "missing platform data\n");
+               goto err0;
+       }
+
+       p = kzalloc(sizeof(*p), GFP_KERNEL);
+       if (p == NULL) {
+               dev_err(&pdev->dev, "failed to allocate driver data\n");
+               ret = -ENOMEM;
+               goto err0;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "failed to get I/O memory\n");
+               goto err1;
+       }
+
+       /* map memory, let mapbase point to our channel */
+       p->mapbase = ioremap_nocache(res->start, resource_size(res));
+       if (p->mapbase == NULL) {
+               dev_err(&pdev->dev, "failed to remap I/O memory\n");
+               goto err1;
+       }
+
+       /* get hold of clock */
+       p->clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(p->clk)) {
+               dev_err(&pdev->dev, "cannot get clock\n");
+               ret = PTR_ERR(p->clk);
+               goto err2;
+       }
+
+       p->pdev = pdev;
+       p->pin_state = R_TPU_PIN_UNUSED;
+       p->timer_state = R_TPU_TIMER_UNUSED;
+       p->refresh_rate = cfg->refresh_rate ? cfg->refresh_rate : 100;
+       r_tpu_set_pin(p, R_TPU_PIN_GPIO, LED_OFF);
+       platform_set_drvdata(pdev, p);
+
+
+       p->ldev.name = cfg->name;
+       p->ldev.brightness = LED_OFF;
+       p->ldev.max_brightness = cfg->max_brightness;
+       p->ldev.brightness_set = r_tpu_set_brightness;
+       p->ldev.flags |= LED_CORE_SUSPENDRESUME;
+       ret = led_classdev_register(&pdev->dev, &p->ldev);
+       if (ret < 0)
+               goto err3;
+
+       /* max_brightness may be updated by the LED core code */
+       p->min_rate = p->ldev.max_brightness * p->refresh_rate;
+
+       pm_runtime_enable(&pdev->dev);
+       return 0;
+
+ err3:
+       r_tpu_set_pin(p, R_TPU_PIN_UNUSED, LED_OFF);
+       clk_put(p->clk);
+ err2:
+       iounmap(p->mapbase);
+ err1:
+       kfree(p);
+ err0:
+       return ret;
+}
+
+static int __devexit r_tpu_remove(struct platform_device *pdev)
+{
+       struct r_tpu_priv *p = platform_get_drvdata(pdev);
+
+       r_tpu_set_brightness(&p->ldev, LED_OFF);
+       led_classdev_unregister(&p->ldev);
+       r_tpu_disable(p);
+       r_tpu_set_pin(p, R_TPU_PIN_UNUSED, LED_OFF);
+
+       pm_runtime_disable(&pdev->dev);
+       clk_put(p->clk);
+
+       iounmap(p->mapbase);
+       kfree(p);
+       return 0;
+}
+
+static struct platform_driver r_tpu_device_driver = {
+       .probe          = r_tpu_probe,
+       .remove         = __devexit_p(r_tpu_remove),
+       .driver         = {
+               .name   = "leds-renesas-tpu",
+       }
+};
+
+static int __init r_tpu_init(void)
+{
+       return platform_driver_register(&r_tpu_device_driver);
+}
+
+static void __exit r_tpu_exit(void)
+{
+       platform_driver_unregister(&r_tpu_device_driver);
+}
+
+module_init(r_tpu_init);
+module_exit(r_tpu_exit);
+
+MODULE_AUTHOR("Magnus Damm");
+MODULE_DESCRIPTION("Renesas TPU LED Driver");
+MODULE_LICENSE("GPL v2");
index b928bc14e97b5765c3f815050fc441a3c4bf8787..e67dceab552b3d11ac7f472ffd939b0cd42d5342 100644 (file)
@@ -163,7 +163,7 @@ static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z)
        int i;
 
        if (lis3->blkread) {
-               if (lis3_dev.whoami == WAI_12B) {
+               if (lis3->whoami == WAI_12B) {
                        u16 data[3];
                        lis3->blkread(lis3, OUTX_L, 6, (u8 *)data);
                        for (i = 0; i < 3; i++)
@@ -195,18 +195,30 @@ static int lis3_8_rates[2] = {100, 400};
 static int lis3_3dc_rates[16] = {0, 1, 10, 25, 50, 100, 200, 400, 1600, 5000};
 
 /* ODR is Output Data Rate */
-static int lis3lv02d_get_odr(void)
+static int lis3lv02d_get_odr(struct lis3lv02d *lis3)
 {
        u8 ctrl;
        int shift;
 
-       lis3_dev.read(&lis3_dev, CTRL_REG1, &ctrl);
-       ctrl &= lis3_dev.odr_mask;
-       shift = ffs(lis3_dev.odr_mask) - 1;
-       return lis3_dev.odrs[(ctrl >> shift)];
+       lis3->read(&lis3, CTRL_REG1, &ctrl);
+       ctrl &= lis3->odr_mask;
+       shift = ffs(lis3->odr_mask) - 1;
+       return lis3->odrs[(ctrl >> shift)];
 }
 
-static int lis3lv02d_set_odr(int rate)
+static int lis3lv02d_get_pwron_wait(struct lis3lv02d *lis3)
+{
+       int div = lis3lv02d_get_odr(lis3);
+
+       if (WARN_ONCE(div == 0, "device returned spurious data"))
+               return -ENXIO;
+
+       /* LIS3 power on delay is quite long */
+       msleep(lis3->pwron_delay / div);
+       return 0;
+}
+
+static int lis3lv02d_set_odr(struct lis3lv02d *lis3, int rate)
 {
        u8 ctrl;
        int i, len, shift;
@@ -214,14 +226,14 @@ static int lis3lv02d_set_odr(int rate)
        if (!rate)
                return -EINVAL;
 
-       lis3_dev.read(&lis3_dev, CTRL_REG1, &ctrl);
-       ctrl &= ~lis3_dev.odr_mask;
-       len = 1 << hweight_long(lis3_dev.odr_mask); /* # of possible values */
-       shift = ffs(lis3_dev.odr_mask) - 1;
+       lis3->read(lis3, CTRL_REG1, &ctrl);
+       ctrl &= ~lis3->odr_mask;
+       len = 1 << hweight_long(lis3->odr_mask); /* # of possible values */
+       shift = ffs(lis3->odr_mask) - 1;
 
        for (i = 0; i < len; i++)
-               if (lis3_dev.odrs[i] == rate) {
-                       lis3_dev.write(&lis3_dev, CTRL_REG1,
+               if (lis3->odrs[i] == rate) {
+                       lis3->write(lis3, CTRL_REG1,
                                        ctrl | (i << shift));
                        return 0;
                }
@@ -240,12 +252,12 @@ static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3])
        mutex_lock(&lis3->mutex);
 
        irq_cfg = lis3->irq_cfg;
-       if (lis3_dev.whoami == WAI_8B) {
+       if (lis3->whoami == WAI_8B) {
                lis3->data_ready_count[IRQ_LINE0] = 0;
                lis3->data_ready_count[IRQ_LINE1] = 0;
 
                /* Change interrupt cfg to data ready for selftest */
-               atomic_inc(&lis3_dev.wake_thread);
+               atomic_inc(&lis3->wake_thread);
                lis3->irq_cfg = LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY;
                lis3->read(lis3, CTRL_REG3, &ctrl_reg_data);
                lis3->write(lis3, CTRL_REG3, (ctrl_reg_data &
@@ -253,12 +265,12 @@ static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3])
                                (LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY));
        }
 
-       if (lis3_dev.whoami == WAI_3DC) {
+       if (lis3->whoami == WAI_3DC) {
                ctlreg = CTRL_REG4;
                selftest = CTRL4_ST0;
        } else {
                ctlreg = CTRL_REG1;
-               if (lis3_dev.whoami == WAI_12B)
+               if (lis3->whoami == WAI_12B)
                        selftest = CTRL1_ST;
                else
                        selftest = CTRL1_STP;
@@ -266,7 +278,9 @@ static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3])
 
        lis3->read(lis3, ctlreg, &reg);
        lis3->write(lis3, ctlreg, (reg | selftest));
-       msleep(lis3->pwron_delay / lis3lv02d_get_odr());
+       ret = lis3lv02d_get_pwron_wait(lis3);
+       if (ret)
+               goto fail;
 
        /* Read directly to avoid axis remap */
        x = lis3->read_data(lis3, OUTX);
@@ -275,7 +289,9 @@ static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3])
 
        /* back to normal settings */
        lis3->write(lis3, ctlreg, reg);
-       msleep(lis3->pwron_delay / lis3lv02d_get_odr());
+       ret = lis3lv02d_get_pwron_wait(lis3);
+       if (ret)
+               goto fail;
 
        results[0] = x - lis3->read_data(lis3, OUTX);
        results[1] = y - lis3->read_data(lis3, OUTY);
@@ -283,9 +299,9 @@ static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3])
 
        ret = 0;
 
-       if (lis3_dev.whoami == WAI_8B) {
+       if (lis3->whoami == WAI_8B) {
                /* Restore original interrupt configuration */
-               atomic_dec(&lis3_dev.wake_thread);
+               atomic_dec(&lis3->wake_thread);
                lis3->write(lis3, CTRL_REG3, ctrl_reg_data);
                lis3->irq_cfg = irq_cfg;
 
@@ -363,8 +379,9 @@ void lis3lv02d_poweroff(struct lis3lv02d *lis3)
 }
 EXPORT_SYMBOL_GPL(lis3lv02d_poweroff);
 
-void lis3lv02d_poweron(struct lis3lv02d *lis3)
+int lis3lv02d_poweron(struct lis3lv02d *lis3)
 {
+       int err;
        u8 reg;
 
        lis3->init(lis3);
@@ -382,35 +399,41 @@ void lis3lv02d_poweron(struct lis3lv02d *lis3)
                reg |= CTRL2_BOOT_8B;
        lis3->write(lis3, CTRL_REG2, reg);
 
-       /* LIS3 power on delay is quite long */
-       msleep(lis3->pwron_delay / lis3lv02d_get_odr());
+       err = lis3lv02d_get_pwron_wait(lis3);
+       if (err)
+               return err;
 
        if (lis3->reg_ctrl)
                lis3_context_restore(lis3);
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(lis3lv02d_poweron);
 
 
 static void lis3lv02d_joystick_poll(struct input_polled_dev *pidev)
 {
+       struct lis3lv02d *lis3 = pidev->private;
        int x, y, z;
 
-       mutex_lock(&lis3_dev.mutex);
-       lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
+       mutex_lock(&lis3->mutex);
+       lis3lv02d_get_xyz(lis3, &x, &y, &z);
        input_report_abs(pidev->input, ABS_X, x);
        input_report_abs(pidev->input, ABS_Y, y);
        input_report_abs(pidev->input, ABS_Z, z);
        input_sync(pidev->input);
-       mutex_unlock(&lis3_dev.mutex);
+       mutex_unlock(&lis3->mutex);
 }
 
 static void lis3lv02d_joystick_open(struct input_polled_dev *pidev)
 {
-       if (lis3_dev.pm_dev)
-               pm_runtime_get_sync(lis3_dev.pm_dev);
+       struct lis3lv02d *lis3 = pidev->private;
 
-       if (lis3_dev.pdata && lis3_dev.whoami == WAI_8B && lis3_dev.idev)
-               atomic_set(&lis3_dev.wake_thread, 1);
+       if (lis3->pm_dev)
+               pm_runtime_get_sync(lis3->pm_dev);
+
+       if (lis3->pdata && lis3->whoami == WAI_8B && lis3->idev)
+               atomic_set(&lis3->wake_thread, 1);
        /*
         * Update coordinates for the case where poll interval is 0 and
         * the chip in running purely under interrupt control
@@ -420,14 +443,18 @@ static void lis3lv02d_joystick_open(struct input_polled_dev *pidev)
 
 static void lis3lv02d_joystick_close(struct input_polled_dev *pidev)
 {
-       atomic_set(&lis3_dev.wake_thread, 0);
-       if (lis3_dev.pm_dev)
-               pm_runtime_put(lis3_dev.pm_dev);
+       struct lis3lv02d *lis3 = pidev->private;
+
+       atomic_set(&lis3->wake_thread, 0);
+       if (lis3->pm_dev)
+               pm_runtime_put(lis3->pm_dev);
 }
 
-static irqreturn_t lis302dl_interrupt(int irq, void *dummy)
+static irqreturn_t lis302dl_interrupt(int irq, void *data)
 {
-       if (!test_bit(0, &lis3_dev.misc_opened))
+       struct lis3lv02d *lis3 = data;
+
+       if (!test_bit(0, &lis3->misc_opened))
                goto out;
 
        /*
@@ -435,12 +462,12 @@ static irqreturn_t lis302dl_interrupt(int irq, void *dummy)
         * the lid is closed. This leads to interrupts as soon as a little move
         * is done.
         */
-       atomic_inc(&lis3_dev.count);
+       atomic_inc(&lis3->count);
 
-       wake_up_interruptible(&lis3_dev.misc_wait);
-       kill_fasync(&lis3_dev.async_queue, SIGIO, POLL_IN);
+       wake_up_interruptible(&lis3->misc_wait);
+       kill_fasync(&lis3->async_queue, SIGIO, POLL_IN);
 out:
-       if (atomic_read(&lis3_dev.wake_thread))
+       if (atomic_read(&lis3->wake_thread))
                return IRQ_WAKE_THREAD;
        return IRQ_HANDLED;
 }
@@ -512,28 +539,37 @@ static irqreturn_t lis302dl_interrupt_thread2_8b(int irq, void *data)
 
 static int lis3lv02d_misc_open(struct inode *inode, struct file *file)
 {
-       if (test_and_set_bit(0, &lis3_dev.misc_opened))
+       struct lis3lv02d *lis3 = container_of(file->private_data,
+                                             struct lis3lv02d, miscdev);
+
+       if (test_and_set_bit(0, &lis3->misc_opened))
                return -EBUSY; /* already open */
 
-       if (lis3_dev.pm_dev)
-               pm_runtime_get_sync(lis3_dev.pm_dev);
+       if (lis3->pm_dev)
+               pm_runtime_get_sync(lis3->pm_dev);
 
-       atomic_set(&lis3_dev.count, 0);
+       atomic_set(&lis3->count, 0);
        return 0;
 }
 
 static int lis3lv02d_misc_release(struct inode *inode, struct file *file)
 {
-       fasync_helper(-1, file, 0, &lis3_dev.async_queue);
-       clear_bit(0, &lis3_dev.misc_opened); /* release the device */
-       if (lis3_dev.pm_dev)
-               pm_runtime_put(lis3_dev.pm_dev);
+       struct lis3lv02d *lis3 = container_of(file->private_data,
+                                             struct lis3lv02d, miscdev);
+
+       fasync_helper(-1, file, 0, &lis3->async_queue);
+       clear_bit(0, &lis3->misc_opened); /* release the device */
+       if (lis3->pm_dev)
+               pm_runtime_put(lis3->pm_dev);
        return 0;
 }
 
 static ssize_t lis3lv02d_misc_read(struct file *file, char __user *buf,
                                size_t count, loff_t *pos)
 {
+       struct lis3lv02d *lis3 = container_of(file->private_data,
+                                             struct lis3lv02d, miscdev);
+
        DECLARE_WAITQUEUE(wait, current);
        u32 data;
        unsigned char byte_data;
@@ -542,10 +578,10 @@ static ssize_t lis3lv02d_misc_read(struct file *file, char __user *buf,
        if (count < 1)
                return -EINVAL;
 
-       add_wait_queue(&lis3_dev.misc_wait, &wait);
+       add_wait_queue(&lis3->misc_wait, &wait);
        while (true) {
                set_current_state(TASK_INTERRUPTIBLE);
-               data = atomic_xchg(&lis3_dev.count, 0);
+               data = atomic_xchg(&lis3->count, 0);
                if (data)
                        break;
 
@@ -575,22 +611,28 @@ static ssize_t lis3lv02d_misc_read(struct file *file, char __user *buf,
 
 out:
        __set_current_state(TASK_RUNNING);
-       remove_wait_queue(&lis3_dev.misc_wait, &wait);
+       remove_wait_queue(&lis3->misc_wait, &wait);
 
        return retval;
 }
 
 static unsigned int lis3lv02d_misc_poll(struct file *file, poll_table *wait)
 {
-       poll_wait(file, &lis3_dev.misc_wait, wait);
-       if (atomic_read(&lis3_dev.count))
+       struct lis3lv02d *lis3 = container_of(file->private_data,
+                                             struct lis3lv02d, miscdev);
+
+       poll_wait(file, &lis3->misc_wait, wait);
+       if (atomic_read(&lis3->count))
                return POLLIN | POLLRDNORM;
        return 0;
 }
 
 static int lis3lv02d_misc_fasync(int fd, struct file *file, int on)
 {
-       return fasync_helper(fd, file, on, &lis3_dev.async_queue);
+       struct lis3lv02d *lis3 = container_of(file->private_data,
+                                             struct lis3lv02d, miscdev);
+
+       return fasync_helper(fd, file, on, &lis3->async_queue);
 }
 
 static const struct file_operations lis3lv02d_misc_fops = {
@@ -603,85 +645,80 @@ static const struct file_operations lis3lv02d_misc_fops = {
        .fasync  = lis3lv02d_misc_fasync,
 };
 
-static struct miscdevice lis3lv02d_misc_device = {
-       .minor   = MISC_DYNAMIC_MINOR,
-       .name    = "freefall",
-       .fops    = &lis3lv02d_misc_fops,
-};
-
-int lis3lv02d_joystick_enable(void)
+int lis3lv02d_joystick_enable(struct lis3lv02d *lis3)
 {
        struct input_dev *input_dev;
        int err;
        int max_val, fuzz, flat;
        int btns[] = {BTN_X, BTN_Y, BTN_Z};
 
-       if (lis3_dev.idev)
+       if (lis3->idev)
                return -EINVAL;
 
-       lis3_dev.idev = input_allocate_polled_device();
-       if (!lis3_dev.idev)
+       lis3->idev = input_allocate_polled_device();
+       if (!lis3->idev)
                return -ENOMEM;
 
-       lis3_dev.idev->poll = lis3lv02d_joystick_poll;
-       lis3_dev.idev->open = lis3lv02d_joystick_open;
-       lis3_dev.idev->close = lis3lv02d_joystick_close;
-       lis3_dev.idev->poll_interval = MDPS_POLL_INTERVAL;
-       lis3_dev.idev->poll_interval_min = MDPS_POLL_MIN;
-       lis3_dev.idev->poll_interval_max = MDPS_POLL_MAX;
-       input_dev = lis3_dev.idev->input;
+       lis3->idev->poll = lis3lv02d_joystick_poll;
+       lis3->idev->open = lis3lv02d_joystick_open;
+       lis3->idev->close = lis3lv02d_joystick_close;
+       lis3->idev->poll_interval = MDPS_POLL_INTERVAL;
+       lis3->idev->poll_interval_min = MDPS_POLL_MIN;
+       lis3->idev->poll_interval_max = MDPS_POLL_MAX;
+       lis3->idev->private = lis3;
+       input_dev = lis3->idev->input;
 
        input_dev->name       = "ST LIS3LV02DL Accelerometer";
        input_dev->phys       = DRIVER_NAME "/input0";
        input_dev->id.bustype = BUS_HOST;
        input_dev->id.vendor  = 0;
-       input_dev->dev.parent = &lis3_dev.pdev->dev;
+       input_dev->dev.parent = &lis3->pdev->dev;
 
        set_bit(EV_ABS, input_dev->evbit);
-       max_val = (lis3_dev.mdps_max_val * lis3_dev.scale) / LIS3_ACCURACY;
-       if (lis3_dev.whoami == WAI_12B) {
+       max_val = (lis3->mdps_max_val * lis3->scale) / LIS3_ACCURACY;
+       if (lis3->whoami == WAI_12B) {
                fuzz = LIS3_DEFAULT_FUZZ_12B;
                flat = LIS3_DEFAULT_FLAT_12B;
        } else {
                fuzz = LIS3_DEFAULT_FUZZ_8B;
                flat = LIS3_DEFAULT_FLAT_8B;
        }
-       fuzz = (fuzz * lis3_dev.scale) / LIS3_ACCURACY;
-       flat = (flat * lis3_dev.scale) / LIS3_ACCURACY;
+       fuzz = (fuzz * lis3->scale) / LIS3_ACCURACY;
+       flat = (flat * lis3->scale) / LIS3_ACCURACY;
 
        input_set_abs_params(input_dev, ABS_X, -max_val, max_val, fuzz, flat);
        input_set_abs_params(input_dev, ABS_Y, -max_val, max_val, fuzz, flat);
        input_set_abs_params(input_dev, ABS_Z, -max_val, max_val, fuzz, flat);
 
-       lis3_dev.mapped_btns[0] = lis3lv02d_get_axis(abs(lis3_dev.ac.x), btns);
-       lis3_dev.mapped_btns[1] = lis3lv02d_get_axis(abs(lis3_dev.ac.y), btns);
-       lis3_dev.mapped_btns[2] = lis3lv02d_get_axis(abs(lis3_dev.ac.z), btns);
+       lis3->mapped_btns[0] = lis3lv02d_get_axis(abs(lis3->ac.x), btns);
+       lis3->mapped_btns[1] = lis3lv02d_get_axis(abs(lis3->ac.y), btns);
+       lis3->mapped_btns[2] = lis3lv02d_get_axis(abs(lis3->ac.z), btns);
 
-       err = input_register_polled_device(lis3_dev.idev);
+       err = input_register_polled_device(lis3->idev);
        if (err) {
-               input_free_polled_device(lis3_dev.idev);
-               lis3_dev.idev = NULL;
+               input_free_polled_device(lis3->idev);
+               lis3->idev = NULL;
        }
 
        return err;
 }
 EXPORT_SYMBOL_GPL(lis3lv02d_joystick_enable);
 
-void lis3lv02d_joystick_disable(void)
+void lis3lv02d_joystick_disable(struct lis3lv02d *lis3)
 {
-       if (lis3_dev.irq)
-               free_irq(lis3_dev.irq, &lis3_dev);
-       if (lis3_dev.pdata && lis3_dev.pdata->irq2)
-               free_irq(lis3_dev.pdata->irq2, &lis3_dev);
+       if (lis3->irq)
+               free_irq(lis3->irq, lis3);
+       if (lis3->pdata && lis3->pdata->irq2)
+               free_irq(lis3->pdata->irq2, lis3);
 
-       if (!lis3_dev.idev)
+       if (!lis3->idev)
                return;
 
-       if (lis3_dev.irq)
-               misc_deregister(&lis3lv02d_misc_device);
-       input_unregister_polled_device(lis3_dev.idev);
-       input_free_polled_device(lis3_dev.idev);
-       lis3_dev.idev = NULL;
+       if (lis3->irq)
+               misc_deregister(&lis3->miscdev);
+       input_unregister_polled_device(lis3->idev);
+       input_free_polled_device(lis3->idev);
+       lis3->idev = NULL;
 }
 EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable);
 
@@ -706,6 +743,7 @@ static void lis3lv02d_sysfs_poweron(struct lis3lv02d *lis3)
 static ssize_t lis3lv02d_selftest_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
+       struct lis3lv02d *lis3 = dev_get_drvdata(dev);
        s16 values[3];
 
        static const char ok[] = "OK";
@@ -713,8 +751,8 @@ static ssize_t lis3lv02d_selftest_show(struct device *dev,
        static const char irq[] = "FAIL_IRQ";
        const char *res;
 
-       lis3lv02d_sysfs_poweron(&lis3_dev);
-       switch (lis3lv02d_selftest(&lis3_dev, values)) {
+       lis3lv02d_sysfs_poweron(lis3);
+       switch (lis3lv02d_selftest(lis3, values)) {
        case SELFTEST_FAIL:
                res = fail;
                break;
@@ -733,33 +771,37 @@ static ssize_t lis3lv02d_selftest_show(struct device *dev,
 static ssize_t lis3lv02d_position_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
+       struct lis3lv02d *lis3 = dev_get_drvdata(dev);
        int x, y, z;
 
-       lis3lv02d_sysfs_poweron(&lis3_dev);
-       mutex_lock(&lis3_dev.mutex);
-       lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
-       mutex_unlock(&lis3_dev.mutex);
+       lis3lv02d_sysfs_poweron(lis3);
+       mutex_lock(&lis3->mutex);
+       lis3lv02d_get_xyz(lis3, &x, &y, &z);
+       mutex_unlock(&lis3->mutex);
        return sprintf(buf, "(%d,%d,%d)\n", x, y, z);
 }
 
 static ssize_t lis3lv02d_rate_show(struct device *dev,
                        struct device_attribute *attr, char *buf)
 {
-       lis3lv02d_sysfs_poweron(&lis3_dev);
-       return sprintf(buf, "%d\n", lis3lv02d_get_odr());
+       struct lis3lv02d *lis3 = dev_get_drvdata(dev);
+
+       lis3lv02d_sysfs_poweron(lis3);
+       return sprintf(buf, "%d\n", lis3lv02d_get_odr(lis3));
 }
 
 static ssize_t lis3lv02d_rate_set(struct device *dev,
                                struct device_attribute *attr, const char *buf,
                                size_t count)
 {
+       struct lis3lv02d *lis3 = dev_get_drvdata(dev);
        unsigned long rate;
 
        if (strict_strtoul(buf, 0, &rate))
                return -EINVAL;
 
-       lis3lv02d_sysfs_poweron(&lis3_dev);
-       if (lis3lv02d_set_odr(rate))
+       lis3lv02d_sysfs_poweron(lis3);
+       if (lis3lv02d_set_odr(lis3, rate))
                return -EINVAL;
 
        return count;
@@ -788,6 +830,7 @@ static int lis3lv02d_add_fs(struct lis3lv02d *lis3)
        if (IS_ERR(lis3->pdev))
                return PTR_ERR(lis3->pdev);
 
+       platform_set_drvdata(lis3->pdev, lis3);
        return sysfs_create_group(&lis3->pdev->dev.kobj, &lis3lv02d_attribute_group);
 }
 
@@ -801,7 +844,7 @@ int lis3lv02d_remove_fs(struct lis3lv02d *lis3)
 
                /* SYSFS may have left chip running. Turn off if necessary */
                if (!pm_runtime_suspended(lis3->pm_dev))
-                       lis3lv02d_poweroff(&lis3_dev);
+                       lis3lv02d_poweroff(lis3);
 
                pm_runtime_disable(lis3->pm_dev);
                pm_runtime_set_suspended(lis3->pm_dev);
@@ -811,24 +854,24 @@ int lis3lv02d_remove_fs(struct lis3lv02d *lis3)
 }
 EXPORT_SYMBOL_GPL(lis3lv02d_remove_fs);
 
-static void lis3lv02d_8b_configure(struct lis3lv02d *dev,
+static void lis3lv02d_8b_configure(struct lis3lv02d *lis3,
                                struct lis3lv02d_platform_data *p)
 {
        int err;
        int ctrl2 = p->hipass_ctrl;
 
        if (p->click_flags) {
-               dev->write(dev, CLICK_CFG, p->click_flags);
-               dev->write(dev, CLICK_TIMELIMIT, p->click_time_limit);
-               dev->write(dev, CLICK_LATENCY, p->click_latency);
-               dev->write(dev, CLICK_WINDOW, p->click_window);
-               dev->write(dev, CLICK_THSZ, p->click_thresh_z & 0xf);
-               dev->write(dev, CLICK_THSY_X,
+               lis3->write(lis3, CLICK_CFG, p->click_flags);
+               lis3->write(lis3, CLICK_TIMELIMIT, p->click_time_limit);
+               lis3->write(lis3, CLICK_LATENCY, p->click_latency);
+               lis3->write(lis3, CLICK_WINDOW, p->click_window);
+               lis3->write(lis3, CLICK_THSZ, p->click_thresh_z & 0xf);
+               lis3->write(lis3, CLICK_THSY_X,
                        (p->click_thresh_x & 0xf) |
                        (p->click_thresh_y << 4));
 
-               if (dev->idev) {
-                       struct input_dev *input_dev = lis3_dev.idev->input;
+               if (lis3->idev) {
+                       struct input_dev *input_dev = lis3->idev->input;
                        input_set_capability(input_dev, EV_KEY, BTN_X);
                        input_set_capability(input_dev, EV_KEY, BTN_Y);
                        input_set_capability(input_dev, EV_KEY, BTN_Z);
@@ -836,22 +879,22 @@ static void lis3lv02d_8b_configure(struct lis3lv02d *dev,
        }
 
        if (p->wakeup_flags) {
-               dev->write(dev, FF_WU_CFG_1, p->wakeup_flags);
-               dev->write(dev, FF_WU_THS_1, p->wakeup_thresh & 0x7f);
+               lis3->write(lis3, FF_WU_CFG_1, p->wakeup_flags);
+               lis3->write(lis3, FF_WU_THS_1, p->wakeup_thresh & 0x7f);
                /* pdata value + 1 to keep this backward compatible*/
-               dev->write(dev, FF_WU_DURATION_1, p->duration1 + 1);
+               lis3->write(lis3, FF_WU_DURATION_1, p->duration1 + 1);
                ctrl2 ^= HP_FF_WU1; /* Xor to keep compatible with old pdata*/
        }
 
        if (p->wakeup_flags2) {
-               dev->write(dev, FF_WU_CFG_2, p->wakeup_flags2);
-               dev->write(dev, FF_WU_THS_2, p->wakeup_thresh2 & 0x7f);
+               lis3->write(lis3, FF_WU_CFG_2, p->wakeup_flags2);
+               lis3->write(lis3, FF_WU_THS_2, p->wakeup_thresh2 & 0x7f);
                /* pdata value + 1 to keep this backward compatible*/
-               dev->write(dev, FF_WU_DURATION_2, p->duration2 + 1);
+               lis3->write(lis3, FF_WU_DURATION_2, p->duration2 + 1);
                ctrl2 ^= HP_FF_WU2; /* Xor to keep compatible with old pdata*/
        }
        /* Configure hipass filters */
-       dev->write(dev, CTRL_REG2, ctrl2);
+       lis3->write(lis3, CTRL_REG2, ctrl2);
 
        if (p->irq2) {
                err = request_threaded_irq(p->irq2,
@@ -859,7 +902,7 @@ static void lis3lv02d_8b_configure(struct lis3lv02d *dev,
                                        lis302dl_interrupt_thread2_8b,
                                        IRQF_TRIGGER_RISING | IRQF_ONESHOT |
                                        (p->irq_flags2 & IRQF_TRIGGER_MASK),
-                                       DRIVER_NAME, &lis3_dev);
+                                       DRIVER_NAME, lis3);
                if (err < 0)
                        pr_err("No second IRQ. Limited functionality\n");
        }
@@ -869,93 +912,97 @@ static void lis3lv02d_8b_configure(struct lis3lv02d *dev,
  * Initialise the accelerometer and the various subsystems.
  * Should be rather independent of the bus system.
  */
-int lis3lv02d_init_device(struct lis3lv02d *dev)
+int lis3lv02d_init_device(struct lis3lv02d *lis3)
 {
        int err;
        irq_handler_t thread_fn;
        int irq_flags = 0;
 
-       dev->whoami = lis3lv02d_read_8(dev, WHO_AM_I);
+       lis3->whoami = lis3lv02d_read_8(lis3, WHO_AM_I);
 
-       switch (dev->whoami) {
+       switch (lis3->whoami) {
        case WAI_12B:
                pr_info("12 bits sensor found\n");
-               dev->read_data = lis3lv02d_read_12;
-               dev->mdps_max_val = 2048;
-               dev->pwron_delay = LIS3_PWRON_DELAY_WAI_12B;
-               dev->odrs = lis3_12_rates;
-               dev->odr_mask = CTRL1_DF0 | CTRL1_DF1;
-               dev->scale = LIS3_SENSITIVITY_12B;
-               dev->regs = lis3_wai12_regs;
-               dev->regs_size = ARRAY_SIZE(lis3_wai12_regs);
+               lis3->read_data = lis3lv02d_read_12;
+               lis3->mdps_max_val = 2048;
+               lis3->pwron_delay = LIS3_PWRON_DELAY_WAI_12B;
+               lis3->odrs = lis3_12_rates;
+               lis3->odr_mask = CTRL1_DF0 | CTRL1_DF1;
+               lis3->scale = LIS3_SENSITIVITY_12B;
+               lis3->regs = lis3_wai12_regs;
+               lis3->regs_size = ARRAY_SIZE(lis3_wai12_regs);
                break;
        case WAI_8B:
                pr_info("8 bits sensor found\n");
-               dev->read_data = lis3lv02d_read_8;
-               dev->mdps_max_val = 128;
-               dev->pwron_delay = LIS3_PWRON_DELAY_WAI_8B;
-               dev->odrs = lis3_8_rates;
-               dev->odr_mask = CTRL1_DR;
-               dev->scale = LIS3_SENSITIVITY_8B;
-               dev->regs = lis3_wai8_regs;
-               dev->regs_size = ARRAY_SIZE(lis3_wai8_regs);
+               lis3->read_data = lis3lv02d_read_8;
+               lis3->mdps_max_val = 128;
+               lis3->pwron_delay = LIS3_PWRON_DELAY_WAI_8B;
+               lis3->odrs = lis3_8_rates;
+               lis3->odr_mask = CTRL1_DR;
+               lis3->scale = LIS3_SENSITIVITY_8B;
+               lis3->regs = lis3_wai8_regs;
+               lis3->regs_size = ARRAY_SIZE(lis3_wai8_regs);
                break;
        case WAI_3DC:
                pr_info("8 bits 3DC sensor found\n");
-               dev->read_data = lis3lv02d_read_8;
-               dev->mdps_max_val = 128;
-               dev->pwron_delay = LIS3_PWRON_DELAY_WAI_8B;
-               dev->odrs = lis3_3dc_rates;
-               dev->odr_mask = CTRL1_ODR0|CTRL1_ODR1|CTRL1_ODR2|CTRL1_ODR3;
-               dev->scale = LIS3_SENSITIVITY_8B;
+               lis3->read_data = lis3lv02d_read_8;
+               lis3->mdps_max_val = 128;
+               lis3->pwron_delay = LIS3_PWRON_DELAY_WAI_8B;
+               lis3->odrs = lis3_3dc_rates;
+               lis3->odr_mask = CTRL1_ODR0|CTRL1_ODR1|CTRL1_ODR2|CTRL1_ODR3;
+               lis3->scale = LIS3_SENSITIVITY_8B;
                break;
        default:
-               pr_err("unknown sensor type 0x%X\n", dev->whoami);
+               pr_err("unknown sensor type 0x%X\n", lis3->whoami);
                return -EINVAL;
        }
 
-       dev->reg_cache = kzalloc(max(sizeof(lis3_wai8_regs),
+       lis3->reg_cache = kzalloc(max(sizeof(lis3_wai8_regs),
                                     sizeof(lis3_wai12_regs)), GFP_KERNEL);
 
-       if (dev->reg_cache == NULL) {
+       if (lis3->reg_cache == NULL) {
                printk(KERN_ERR DRIVER_NAME "out of memory\n");
                return -ENOMEM;
        }
 
-       mutex_init(&dev->mutex);
-       atomic_set(&dev->wake_thread, 0);
+       mutex_init(&lis3->mutex);
+       atomic_set(&lis3->wake_thread, 0);
 
-       lis3lv02d_add_fs(dev);
-       lis3lv02d_poweron(dev);
+       lis3lv02d_add_fs(lis3);
+       err = lis3lv02d_poweron(lis3);
+       if (err) {
+               lis3lv02d_remove_fs(lis3);
+               return err;
+       }
 
-       if (dev->pm_dev) {
-               pm_runtime_set_active(dev->pm_dev);
-               pm_runtime_enable(dev->pm_dev);
+       if (lis3->pm_dev) {
+               pm_runtime_set_active(lis3->pm_dev);
+               pm_runtime_enable(lis3->pm_dev);
        }
 
-       if (lis3lv02d_joystick_enable())
+       if (lis3lv02d_joystick_enable(lis3))
                pr_err("joystick initialization failed\n");
 
        /* passing in platform specific data is purely optional and only
         * used by the SPI transport layer at the moment */
-       if (dev->pdata) {
-               struct lis3lv02d_platform_data *p = dev->pdata;
+       if (lis3->pdata) {
+               struct lis3lv02d_platform_data *p = lis3->pdata;
 
-               if (dev->whoami == WAI_8B)
-                       lis3lv02d_8b_configure(dev, p);
+               if (lis3->whoami == WAI_8B)
+                       lis3lv02d_8b_configure(lis3, p);
 
                irq_flags = p->irq_flags1 & IRQF_TRIGGER_MASK;
 
-               dev->irq_cfg = p->irq_cfg;
+               lis3->irq_cfg = p->irq_cfg;
                if (p->irq_cfg)
-                       dev->write(dev, CTRL_REG3, p->irq_cfg);
+                       lis3->write(lis3, CTRL_REG3, p->irq_cfg);
 
                if (p->default_rate)
-                       lis3lv02d_set_odr(p->default_rate);
+                       lis3lv02d_set_odr(lis3, p->default_rate);
        }
 
        /* bail if we did not get an IRQ from the bus layer */
-       if (!dev->irq) {
+       if (!lis3->irq) {
                pr_debug("No IRQ. Disabling /dev/freefall\n");
                goto out;
        }
@@ -971,23 +1018,27 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
         * io-apic is not configurable (and generates a warning) but I keep it
         * in case of support for other hardware.
         */
-       if (dev->pdata && dev->whoami == WAI_8B)
+       if (lis3->pdata && lis3->whoami == WAI_8B)
                thread_fn = lis302dl_interrupt_thread1_8b;
        else
                thread_fn = NULL;
 
-       err = request_threaded_irq(dev->irq, lis302dl_interrupt,
+       err = request_threaded_irq(lis3->irq, lis302dl_interrupt,
                                thread_fn,
                                IRQF_TRIGGER_RISING | IRQF_ONESHOT |
                                irq_flags,
-                               DRIVER_NAME, &lis3_dev);
+                               DRIVER_NAME, lis3);
 
        if (err < 0) {
                pr_err("Cannot get IRQ\n");
                goto out;
        }
 
-       if (misc_register(&lis3lv02d_misc_device))
+       lis3->miscdev.minor     = MISC_DYNAMIC_MINOR;
+       lis3->miscdev.name      = "freefall";
+       lis3->miscdev.fops      = &lis3lv02d_misc_fops;
+
+       if (misc_register(&lis3->miscdev))
                pr_err("misc_register failed\n");
 out:
        return 0;
index a1939589eb2c47e9067ecc85911a19cede974503..2b1482ad3f16aedc776ef4429e6c9da7741c7d5a 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/platform_device.h>
 #include <linux/input-polldev.h>
 #include <linux/regulator/consumer.h>
+#include <linux/miscdevice.h>
 
 /*
  * This driver tries to support the "digital" accelerometer chips from
@@ -273,6 +274,8 @@ struct lis3lv02d {
        struct fasync_struct    *async_queue; /* queue for the misc device */
        wait_queue_head_t       misc_wait; /* Wait queue for the misc device */
        unsigned long           misc_opened; /* bit0: whether the device is open */
+       struct miscdevice       miscdev;
+
        int                     data_ready_count[2];
        atomic_t                wake_thread;
        unsigned char           irq_cfg;
@@ -282,10 +285,10 @@ struct lis3lv02d {
 };
 
 int lis3lv02d_init_device(struct lis3lv02d *lis3);
-int lis3lv02d_joystick_enable(void);
-void lis3lv02d_joystick_disable(void);
+int lis3lv02d_joystick_enable(struct lis3lv02d *lis3);
+void lis3lv02d_joystick_disable(struct lis3lv02d *lis3);
 void lis3lv02d_poweroff(struct lis3lv02d *lis3);
-void lis3lv02d_poweron(struct lis3lv02d *lis3);
+int lis3lv02d_poweron(struct lis3lv02d *lis3);
 int lis3lv02d_remove_fs(struct lis3lv02d *lis3);
 
 extern struct lis3lv02d lis3_dev;
index b20dfb4522d278eebefa6eb8f2242e78c32f3f8d..6cdc38f6a9a83f671d6030f23aef59911a84568d 100644 (file)
@@ -161,8 +161,13 @@ static int __devinit lis3lv02d_i2c_probe(struct i2c_client *client,
        if (lis3_dev.reg_ctrl)
                lis3_reg_ctrl(&lis3_dev, LIS3_REG_OFF);
 
-       if (ret == 0)
-               return 0;
+       if (ret)
+               goto fail2;
+       return 0;
+
+fail2:
+       regulator_bulk_free(ARRAY_SIZE(lis3_dev.regulators),
+                               lis3_dev.regulators);
 fail:
        if (pdata && pdata->release_resources)
                pdata->release_resources();
@@ -177,7 +182,7 @@ static int __devexit lis3lv02d_i2c_remove(struct i2c_client *client)
        if (pdata && pdata->release_resources)
                pdata->release_resources();
 
-       lis3lv02d_joystick_disable();
+       lis3lv02d_joystick_disable(lis3);
        lis3lv02d_remove_fs(&lis3_dev);
 
        if (lis3_dev.reg_ctrl)
index c1f8a8fbf6943983a8e8a34b47e049cfc5111ef0..b2c1be12d16fb5625190b21e3bed774cc924d3a2 100644 (file)
@@ -83,7 +83,7 @@ static int __devinit lis302dl_spi_probe(struct spi_device *spi)
 static int __devexit lis302dl_spi_remove(struct spi_device *spi)
 {
        struct lis3lv02d *lis3 = spi_get_drvdata(spi);
-       lis3lv02d_joystick_disable();
+       lis3lv02d_joystick_disable(lis3);
        lis3lv02d_poweroff(lis3);
 
        return lis3lv02d_remove_fs(&lis3_dev);
index 1e88d478532156de395f609d2a750db792221164..91d0d4b55ae42b809520d4a6cd44dd8a68b95c6f 100644 (file)
@@ -164,7 +164,7 @@ config HP_ACCEL
 
          Support for a led indicating disk protection will be provided as
          hp::hddprotect. For more information on the feature, refer to
-         Documentation/hwmon/lis3lv02d.
+         Documentation/misc-devices/lis3lv02d.
 
          To compile this driver as a module, choose M here: the module will
          be called hp_accel.
index 760c6d7624fe505f5da3f40060a1df9d0eaf12b0..698e45c98b077f0ed7537d833d6510ec2a7d76ed 100644 (file)
@@ -161,6 +161,7 @@ static const struct bios_settings_t bios_tbl[] = {
        {"Acer", "Aspire 1410", "v1.3303", 0x55, 0x58, {0x9e, 0x00} },
        {"Acer", "Aspire 1410", "v1.3308", 0x55, 0x58, {0x9e, 0x00} },
        {"Acer", "Aspire 1410", "v1.3310", 0x55, 0x58, {0x9e, 0x00} },
+       {"Acer", "Aspire 1410", "v1.3314", 0x55, 0x58, {0x9e, 0x00} },
        /* Acer 1810xx */
        {"Acer", "Aspire 1810TZ", "v0.3108", 0x55, 0x58, {0x9e, 0x00} },
        {"Acer", "Aspire 1810T",  "v0.3108", 0x55, 0x58, {0x9e, 0x00} },
index 1b52d00e2f9069b045e8cfad7f399821d753f935..f93a47b7136a1cefdd953b3df7cceb98107d616c 100644 (file)
@@ -209,6 +209,8 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = {
        AXIS_DMI_MATCH("NC6715x", "HP Compaq 6715", y_inverted),
        AXIS_DMI_MATCH("NC693xx", "HP EliteBook 693", xy_rotated_right),
        AXIS_DMI_MATCH("NC693xx", "HP EliteBook 853", xy_swap),
+       AXIS_DMI_MATCH("NC854xx", "HP EliteBook 854", y_inverted),
+       AXIS_DMI_MATCH("NC273xx", "HP EliteBook 273", y_inverted),
        /* Intel-based HP Pavilion dv5 */
        AXIS_DMI_MATCH2("HPDV5_I",
                        PRODUCT_NAME, "HP Pavilion dv5",
@@ -227,6 +229,7 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = {
        AXIS_DMI_MATCH("HPB452x", "HP ProBook 452", y_inverted),
        AXIS_DMI_MATCH("HPB522x", "HP ProBook 522", xy_swap),
        AXIS_DMI_MATCH("HPB532x", "HP ProBook 532", y_inverted),
+       AXIS_DMI_MATCH("HPB655x", "HP ProBook 655", xy_swap_inverted),
        AXIS_DMI_MATCH("Mini510x", "HP Mini 510", xy_rotated_left_usd),
        { NULL, }
 /* Laptop models without axis info (yet):
@@ -320,7 +323,7 @@ static int lis3lv02d_add(struct acpi_device *device)
        INIT_WORK(&hpled_led.work, delayed_set_status_worker);
        ret = led_classdev_register(NULL, &hpled_led.led_classdev);
        if (ret) {
-               lis3lv02d_joystick_disable();
+               lis3lv02d_joystick_disable(&lis3_dev);
                lis3lv02d_poweroff(&lis3_dev);
                flush_work(&hpled_led.work);
                return ret;
@@ -334,7 +337,7 @@ static int lis3lv02d_remove(struct acpi_device *device, int type)
        if (!device)
                return -EINVAL;
 
-       lis3lv02d_joystick_disable();
+       lis3lv02d_joystick_disable(&lis3_dev);
        lis3lv02d_poweroff(&lis3_dev);
 
        led_classdev_unregister(&hpled_led.led_classdev);
@@ -354,8 +357,7 @@ static int lis3lv02d_suspend(struct acpi_device *device, pm_message_t state)
 
 static int lis3lv02d_resume(struct acpi_device *device)
 {
-       lis3lv02d_poweron(&lis3_dev);
-       return 0;
+       return lis3lv02d_poweron(&lis3_dev);
 }
 #else
 #define lis3lv02d_suspend NULL
index 8520a7f4dd62048eb5d9391341bf05baa26defc7..c2e0f1e97bcdec66d075d642727a0e6864097ba3 100644 (file)
@@ -29,4 +29,13 @@ config PPS_CLIENT_PARPORT
          If you say yes here you get support for a PPS source connected
          with the interrupt pin of your parallel port.
 
+config PPS_CLIENT_GPIO
+       tristate "PPS client using GPIO"
+       depends on PPS
+       help
+         If you say yes here you get support for a PPS source using
+         GPIO. To be useful you must also register a platform device
+         specifying the GPIO pin and other options, usually in your board
+         setup.
+
 endif
index 4feb7e9e71ee6c14fb8ce8585437ccd3d7dde24c..a461d15f4a2e8531a8fab7eff16ad7fa73ef4658 100644 (file)
@@ -5,5 +5,6 @@
 obj-$(CONFIG_PPS_CLIENT_KTIMER)        += pps-ktimer.o
 obj-$(CONFIG_PPS_CLIENT_LDISC) += pps-ldisc.o
 obj-$(CONFIG_PPS_CLIENT_PARPORT) += pps_parport.o
+obj-$(CONFIG_PPS_CLIENT_GPIO)  += pps-gpio.o
 
 ccflags-$(CONFIG_PPS_DEBUG) := -DDEBUG
diff --git a/drivers/pps/clients/pps-gpio.c b/drivers/pps/clients/pps-gpio.c
new file mode 100644 (file)
index 0000000..6550555
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * pps-gpio.c -- PPS client driver using GPIO
+ *
+ *
+ * Copyright (C) 2010 Ricardo Martins <rasm@fe.up.pt>
+ * Copyright (C) 2011 James Nuss <jamesnuss@nanometrics.ca>
+ *
+ *   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.
+ */
+
+#define PPS_GPIO_NAME "pps-gpio"
+#define pr_fmt(fmt) PPS_GPIO_NAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/pps_kernel.h>
+#include <linux/pps-gpio.h>
+#include <linux/gpio.h>
+#include <linux/list.h>
+
+/* Info for each registered platform device */
+struct pps_gpio_device_data {
+       int irq;                        /* IRQ used as PPS source */
+       struct pps_device *pps;         /* PPS source device */
+       struct pps_source_info info;    /* PPS source information */
+       const struct pps_gpio_platform_data *pdata;
+};
+
+/*
+ * Report the PPS event
+ */
+
+static irqreturn_t pps_gpio_irq_handler(int irq, void *data)
+{
+       const struct pps_gpio_device_data *info;
+       struct pps_event_time ts;
+       int rising_edge;
+
+       /* Get the time stamp first */
+       pps_get_ts(&ts);
+
+       info = data;
+
+       rising_edge = gpio_get_value(info->pdata->gpio_pin);
+       if ((rising_edge && !info->pdata->assert_falling_edge) ||
+                       (!rising_edge && info->pdata->assert_falling_edge))
+               pps_event(info->pps, &ts, PPS_CAPTUREASSERT, NULL);
+       else if (info->pdata->capture_clear &&
+                       ((rising_edge && info->pdata->assert_falling_edge) ||
+                        (!rising_edge && !info->pdata->assert_falling_edge)))
+               pps_event(info->pps, &ts, PPS_CAPTURECLEAR, NULL);
+
+       return IRQ_HANDLED;
+}
+
+static int pps_gpio_setup(struct platform_device *pdev)
+{
+       int ret;
+       const struct pps_gpio_platform_data *pdata = pdev->dev.platform_data;
+
+       ret = gpio_request(pdata->gpio_pin, pdata->gpio_label);
+       if (ret) {
+               pr_warning("failed to request GPIO %u\n", pdata->gpio_pin);
+               return -EINVAL;
+       }
+
+       ret = gpio_direction_input(pdata->gpio_pin);
+       if (ret) {
+               pr_warning("failed to set pin direction\n");
+               gpio_free(pdata->gpio_pin);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static unsigned long
+get_irqf_trigger_flags(const struct pps_gpio_platform_data *pdata)
+{
+       unsigned long flags = pdata->assert_falling_edge ?
+               IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
+
+       if (pdata->capture_clear) {
+               flags |= ((flags & IRQF_TRIGGER_RISING) ?
+                               IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING);
+       }
+
+       return flags;
+}
+
+static int pps_gpio_probe(struct platform_device *pdev)
+{
+       struct pps_gpio_device_data *data;
+       int irq;
+       int ret;
+       int err;
+       int pps_default_params;
+       const struct pps_gpio_platform_data *pdata = pdev->dev.platform_data;
+
+
+       /* GPIO setup */
+       ret = pps_gpio_setup(pdev);
+       if (ret)
+               return -EINVAL;
+
+       /* IRQ setup */
+       irq = gpio_to_irq(pdata->gpio_pin);
+       if (irq < 0) {
+               pr_err("failed to map GPIO to IRQ: %d\n", irq);
+               err = -EINVAL;
+               goto return_error;
+       }
+
+       /* allocate space for device info */
+       data = kzalloc(sizeof(struct pps_gpio_device_data), GFP_KERNEL);
+       if (data == NULL) {
+               err = -ENOMEM;
+               goto return_error;
+       }
+
+       /* initialize PPS specific parts of the bookkeeping data structure. */
+       data->info.mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT |
+               PPS_ECHOASSERT | PPS_CANWAIT | PPS_TSFMT_TSPEC;
+       if (pdata->capture_clear)
+               data->info.mode |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR |
+                       PPS_ECHOCLEAR;
+       data->info.owner = THIS_MODULE;
+       snprintf(data->info.name, PPS_MAX_NAME_LEN - 1, "%s.%d",
+                pdev->name, pdev->id);
+
+       /* register PPS source */
+       pps_default_params = PPS_CAPTUREASSERT | PPS_OFFSETASSERT;
+       if (pdata->capture_clear)
+               pps_default_params |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR;
+       data->pps = pps_register_source(&data->info, pps_default_params);
+       if (data->pps == NULL) {
+               kfree(data);
+               pr_err("failed to register IRQ %d as PPS source\n", irq);
+               err = -EINVAL;
+               goto return_error;
+       }
+
+       data->irq = irq;
+       data->pdata = pdata;
+
+       /* register IRQ interrupt handler */
+       ret = request_irq(irq, pps_gpio_irq_handler,
+                       get_irqf_trigger_flags(pdata), data->info.name, data);
+       if (ret) {
+               pps_unregister_source(data->pps);
+               kfree(data);
+               pr_err("failed to acquire IRQ %d\n", irq);
+               err = -EINVAL;
+               goto return_error;
+       }
+
+       platform_set_drvdata(pdev, data);
+       dev_info(data->pps->dev, "Registered IRQ %d as PPS source\n", irq);
+
+       return 0;
+
+return_error:
+       gpio_free(pdata->gpio_pin);
+       return err;
+}
+
+static int pps_gpio_remove(struct platform_device *pdev)
+{
+       struct pps_gpio_device_data *data = platform_get_drvdata(pdev);
+       const struct pps_gpio_platform_data *pdata = data->pdata;
+
+       platform_set_drvdata(pdev, NULL);
+       free_irq(data->irq, data);
+       gpio_free(pdata->gpio_pin);
+       pps_unregister_source(data->pps);
+       pr_info("removed IRQ %d as PPS source\n", data->irq);
+       kfree(data);
+       return 0;
+}
+
+static struct platform_driver pps_gpio_driver = {
+       .probe          = pps_gpio_probe,
+       .remove         =  __devexit_p(pps_gpio_remove),
+       .driver         = {
+               .name   = PPS_GPIO_NAME,
+               .owner  = THIS_MODULE
+       },
+};
+
+static int __init pps_gpio_init(void)
+{
+       int ret = platform_driver_register(&pps_gpio_driver);
+       if (ret < 0)
+               pr_err("failed to register platform driver\n");
+       return ret;
+}
+
+static void __exit pps_gpio_exit(void)
+{
+       platform_driver_unregister(&pps_gpio_driver);
+       pr_debug("unregistered platform driver\n");
+}
+
+module_init(pps_gpio_init);
+module_exit(pps_gpio_exit);
+
+MODULE_AUTHOR("Ricardo Martins <rasm@fe.up.pt>");
+MODULE_AUTHOR("James Nuss <jamesnuss@nanometrics.ca>");
+MODULE_DESCRIPTION("Use GPIO pin as PPS source");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0.0");
index 82583b0ff82dac05efd9c1d495654ccd244419cc..436b4e4e71a149384c1246baa2a508e4dce21f72 100644 (file)
@@ -51,17 +51,6 @@ static void pps_ktimer_event(unsigned long ptr)
        mod_timer(&ktimer, jiffies + HZ);
 }
 
-/*
- * The echo function
- */
-
-static void pps_ktimer_echo(struct pps_device *pps, int event, void *data)
-{
-       dev_info(pps->dev, "echo %s %s\n",
-               event & PPS_CAPTUREASSERT ? "assert" : "",
-               event & PPS_CAPTURECLEAR ? "clear" : "");
-}
-
 /*
  * The PPS info struct
  */
@@ -72,7 +61,6 @@ static struct pps_source_info pps_ktimer_info = {
        .mode           = PPS_CAPTUREASSERT | PPS_OFFSETASSERT |
                          PPS_ECHOASSERT |
                          PPS_CANWAIT | PPS_TSFMT_TSPEC,
-       .echo           = pps_ktimer_echo,
        .owner          = THIS_MODULE,
 };
 
index c571d6dd8f61f626bdaeb6405de5a3f8aa7a30a6..e1b4705ae3ec83ec1beddfda1dc98d4259bd2a6d 100644 (file)
@@ -133,14 +133,6 @@ out_both:
        return;
 }
 
-/* the PPS echo function */
-static void pps_echo(struct pps_device *pps, int event, void *data)
-{
-       dev_info(pps->dev, "echo %s %s\n",
-               event & PPS_CAPTUREASSERT ? "assert" : "",
-               event & PPS_CAPTURECLEAR ? "clear" : "");
-}
-
 static void parport_attach(struct parport *port)
 {
        struct pps_client_pp *device;
@@ -151,7 +143,6 @@ static void parport_attach(struct parport *port)
                                  PPS_OFFSETASSERT | PPS_OFFSETCLEAR | \
                                  PPS_ECHOASSERT | PPS_ECHOCLEAR | \
                                  PPS_CANWAIT | PPS_TSFMT_TSPEC,
-               .echo           = pps_echo,
                .owner          = THIS_MODULE,
                .dev            = NULL
        };
index a4e8eb9fece6a53c7e2ade169df43dcd9a8696a0..f197e8ea185c4099abc1289cd1b6cf74947f3bed 100644 (file)
@@ -52,6 +52,14 @@ static void pps_add_offset(struct pps_ktime *ts, struct pps_ktime *offset)
        ts->sec += offset->sec;
 }
 
+static void pps_echo_client_default(struct pps_device *pps, int event,
+               void *data)
+{
+       dev_info(pps->dev, "echo %s %s\n",
+               event & PPS_CAPTUREASSERT ? "assert" : "",
+               event & PPS_CAPTURECLEAR ? "clear" : "");
+}
+
 /*
  * Exported functions
  */
@@ -80,13 +88,6 @@ struct pps_device *pps_register_source(struct pps_source_info *info,
                err = -EINVAL;
                goto pps_register_source_exit;
        }
-       if ((info->mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)) != 0 &&
-                       info->echo == NULL) {
-               pr_err("%s: echo function is not defined\n",
-                                       info->name);
-               err = -EINVAL;
-               goto pps_register_source_exit;
-       }
        if ((info->mode & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) == 0) {
                pr_err("%s: unspecified time format\n",
                                        info->name);
@@ -108,6 +109,11 @@ struct pps_device *pps_register_source(struct pps_source_info *info,
        pps->params.mode = default_params;
        pps->info = *info;
 
+       /* check for default echo function */
+       if ((pps->info.mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)) &&
+                       pps->info.echo == NULL)
+               pps->info.echo = pps_echo_client_default;
+
        init_waitqueue_head(&pps->queue);
        spin_lock_init(&pps->lock);
 
index 01a7df5317c1bd9af23ed246e9b452cf057fdd85..e8326f26fa2f5c5ca11d26901f5e70052a1ffea6 100644 (file)
 #include "rtc-core.h"
 
 
-static DEFINE_IDR(rtc_idr);
-static DEFINE_MUTEX(idr_lock);
+static DEFINE_IDA(rtc_ida);
 struct class *rtc_class;
 
 static void rtc_device_release(struct device *dev)
 {
        struct rtc_device *rtc = to_rtc_device(dev);
-       mutex_lock(&idr_lock);
-       idr_remove(&rtc_idr, rtc->id);
-       mutex_unlock(&idr_lock);
+       ida_simple_remove(&rtc_ida, rtc->id);
        kfree(rtc);
 }
 
@@ -146,25 +143,16 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev,
        struct rtc_wkalrm alrm;
        int id, err;
 
-       if (idr_pre_get(&rtc_idr, GFP_KERNEL) == 0) {
-               err = -ENOMEM;
+       id = ida_simple_get(&rtc_ida, 0, 0, GFP_KERNEL);
+       if (id < 0) {
+               err = id;
                goto exit;
        }
 
-
-       mutex_lock(&idr_lock);
-       err = idr_get_new(&rtc_idr, NULL, &id);
-       mutex_unlock(&idr_lock);
-
-       if (err < 0)
-               goto exit;
-
-       id = id & MAX_ID_MASK;
-
        rtc = kzalloc(sizeof(struct rtc_device), GFP_KERNEL);
        if (rtc == NULL) {
                err = -ENOMEM;
-               goto exit_idr;
+               goto exit_ida;
        }
 
        rtc->id = id;
@@ -222,10 +210,8 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev,
 exit_kfree:
        kfree(rtc);
 
-exit_idr:
-       mutex_lock(&idr_lock);
-       idr_remove(&rtc_idr, id);
-       mutex_unlock(&idr_lock);
+exit_ida:
+       ida_simple_remove(&rtc_ida, id);
 
 exit:
        dev_err(dev, "rtc core: unable to register %s, err = %d\n",
@@ -276,7 +262,7 @@ static void __exit rtc_exit(void)
 {
        rtc_dev_exit();
        class_destroy(rtc_class);
-       idr_destroy(&rtc_idr);
+       ida_destroy(&rtc_ida);
 }
 
 subsys_initcall(rtc_init);
index 8a0b33033177174bca1766233ae596ae1f8e3ffa..0bd38da4ada0e7cfc9e112cefdd693b039efc54c 100644 (file)
@@ -650,6 +650,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
                                     AAC_OPT_NEW_COMM) ?
                                      (dev->scsi_host_ptr->max_sectors << 9) :
                                      65536)) {
+                                       kfree(usg);
                                        rcode = -EINVAL;
                                        goto cleanup;
                                }
index 5c1776406c963f996e16aac4781fe4540112d250..1408ebb491114afc9188064cfcd0835bfcb6ddd0 100644 (file)
@@ -310,15 +310,15 @@ mega_query_adapter(adapter_t *adapter)
        if (adapter->product_info.subsysvid == HP_SUBSYS_VID) {
                sprintf (adapter->fw_version, "%c%d%d.%d%d",
                         adapter->product_info.fw_version[2],
-                        adapter->product_info.fw_version[1] >> 8,
+                        adapter->product_info.fw_version[1] >> 4,
                         adapter->product_info.fw_version[1] & 0x0f,
-                        adapter->product_info.fw_version[0] >> 8,
+                        adapter->product_info.fw_version[0] >> 4,
                         adapter->product_info.fw_version[0] & 0x0f);
                sprintf (adapter->bios_version, "%c%d%d.%d%d",
                         adapter->product_info.bios_version[2],
-                        adapter->product_info.bios_version[1] >> 8,
+                        adapter->product_info.bios_version[1] >> 4,
                         adapter->product_info.bios_version[1] & 0x0f,
-                        adapter->product_info.bios_version[0] >> 8,
+                        adapter->product_info.bios_version[0] >> 4,
                         adapter->product_info.bios_version[0] & 0x0f);
        } else {
                memcpy(adapter->fw_version,
index b31a8e3841d795154672cad902ec628bafb59c6f..fa849bdd230f7c608c0fa792b5caeeca9cf7676c 100644 (file)
@@ -387,7 +387,7 @@ static void __remove(struct device *dev)
 
        if (oud->disk)
                put_disk(oud->disk);
-       ida_remove(&osd_minor_ida, oud->minor);
+       ida_simple_remove(&osd_minor_ida, oud->minor);
 
        kfree(oud);
 }
@@ -403,18 +403,12 @@ static int osd_probe(struct device *dev)
        if (scsi_device->type != TYPE_OSD)
                return -ENODEV;
 
-       do {
-               if (!ida_pre_get(&osd_minor_ida, GFP_KERNEL))
-                       return -ENODEV;
-
-               error = ida_get_new(&osd_minor_ida, &minor);
-       } while (error == -EAGAIN);
-
-       if (error)
-               return error;
-       if (minor >= SCSI_OSD_MAX_MINOR) {
-               error = -EBUSY;
-               goto err_retract_minor;
+       minor = ida_simple_get(&osd_minor_ida, 0,
+                              SCSI_OSD_MAX_MINOR, GFP_KERNEL);
+       if (minor < 0) {
+               if (minor == -ENOSPC)
+                       return -EBUSY;
+               return minor;
        }
 
        error = -ENOMEM;
@@ -491,7 +485,7 @@ err_free_osd:
        dev_set_drvdata(dev, NULL);
        kfree(oud);
 err_retract_minor:
-       ida_remove(&osd_minor_ida, minor);
+       ida_simple_remove(&osd_minor_ida, minor);
        return error;
 }
 
index 953773cb26d9a6204a52d56e75884622632c4c0c..c228b3b15343d176bb70628e1d09211a24e7c572 100644 (file)
@@ -111,7 +111,6 @@ static void scsi_disk_release(struct device *cdev);
 static void sd_print_sense_hdr(struct scsi_disk *, struct scsi_sense_hdr *);
 static void sd_print_result(struct scsi_disk *, int);
 
-static DEFINE_SPINLOCK(sd_index_lock);
 static DEFINE_IDA(sd_index_ida);
 
 /* This semaphore is used to mediate the 0->1 reference get in the
@@ -2580,22 +2579,15 @@ static int sd_probe(struct device *dev)
        if (!gd)
                goto out_free;
 
-       do {
-               if (!ida_pre_get(&sd_index_ida, GFP_KERNEL))
-                       goto out_put;
-
-               spin_lock(&sd_index_lock);
-               error = ida_get_new(&sd_index_ida, &index);
-               spin_unlock(&sd_index_lock);
-       } while (error == -EAGAIN);
-
-       if (error)
+       index = ida_simple_get(&sd_index_ida, 0, SD_MAX_DISKS, GFP_KERNEL);
+       if (index < 0) {
+               error = index;
+               if (error == -ENOSPC) {
+                       sdev_printk(KERN_WARNING, sdp,
+                                   "SCSI disk (sd) name space exhausted.\n");
+                       error = -ENODEV;
+               }
                goto out_put;
-
-       if (index >= SD_MAX_DISKS) {
-               error = -ENODEV;
-               sdev_printk(KERN_WARNING, sdp, "SCSI disk (sd) name space exhausted.\n");
-               goto out_free_index;
        }
 
        error = sd_format_disk_name("sd", index, gd->disk_name, DISK_NAME_LEN);
@@ -2633,9 +2625,7 @@ static int sd_probe(struct device *dev)
        return 0;
 
  out_free_index:
-       spin_lock(&sd_index_lock);
-       ida_remove(&sd_index_ida, index);
-       spin_unlock(&sd_index_lock);
+       ida_simple_remove(&sd_index_ida, index);
  out_put:
        put_disk(gd);
  out_free:
@@ -2691,9 +2681,7 @@ static void scsi_disk_release(struct device *dev)
        struct scsi_disk *sdkp = to_scsi_disk(dev);
        struct gendisk *disk = sdkp->disk;
        
-       spin_lock(&sd_index_lock);
-       ida_remove(&sd_index_ida, sdkp->index);
-       spin_unlock(&sd_index_lock);
+       ida_simple_remove(&sd_index_ida, sdkp->index);
 
        disk->private_data = NULL;
        put_disk(disk);
index 909ed9ed24c0fb25663ee09d5ac864628f220843..ce76d0c40aaf077ce7e055fb81070d0d67ed37b2 100644 (file)
@@ -2367,16 +2367,15 @@ static ssize_t
 sg_proc_write_adio(struct file *filp, const char __user *buffer,
                   size_t count, loff_t *off)
 {
-       int num;
-       char buff[11];
+       int err;
+       unsigned long num;
 
        if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
                return -EACCES;
-       num = (count < 10) ? count : 10;
-       if (copy_from_user(buff, buffer, num))
-               return -EFAULT;
-       buff[num] = '\0';
-       sg_allow_dio = simple_strtoul(buff, NULL, 10) ? 1 : 0;
+       err = kstrtoul_from_user(buffer, count, 0, &num);
+       if (err)
+               return err;
+       sg_allow_dio = num ? 1 : 0;
        return count;
 }
 
@@ -2389,17 +2388,15 @@ static ssize_t
 sg_proc_write_dressz(struct file *filp, const char __user *buffer,
                     size_t count, loff_t *off)
 {
-       int num;
+       int err;
        unsigned long k = ULONG_MAX;
-       char buff[11];
 
        if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
                return -EACCES;
-       num = (count < 10) ? count : 10;
-       if (copy_from_user(buff, buffer, num))
-               return -EFAULT;
-       buff[num] = '\0';
-       k = simple_strtoul(buff, NULL, 10);
+
+       err = kstrtoul_from_user(buffer, count, 0, &k);
+       if (err)
+               return err;
        if (k <= 1048576) {     /* limit "big buff" to 1 MB */
                sg_big_buff = k;
                return count;
index 5aac00eb1830c1724ed521f2bcc91693d9dbe646..ee2c060b034df0e02f1148a352689191c1c08d87 100644 (file)
@@ -1076,14 +1076,16 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
        case FBIOPUT_VSCREENINFO:
                if (copy_from_user(&var, argp, sizeof(var)))
                        return -EFAULT;
-               if (!lock_fb_info(info))
-                       return -ENODEV;
                console_lock();
+               if (!lock_fb_info(info)) {
+                       console_unlock();
+                       return -ENODEV;
+               }
                info->flags |= FBINFO_MISC_USEREVENT;
                ret = fb_set_var(info, &var);
                info->flags &= ~FBINFO_MISC_USEREVENT;
-               console_unlock();
                unlock_fb_info(info);
+               console_unlock();
                if (!ret && copy_to_user(argp, &var, sizeof(var)))
                        ret = -EFAULT;
                break;
@@ -1112,12 +1114,14 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
        case FBIOPAN_DISPLAY:
                if (copy_from_user(&var, argp, sizeof(var)))
                        return -EFAULT;
-               if (!lock_fb_info(info))
-                       return -ENODEV;
                console_lock();
+               if (!lock_fb_info(info)) {
+                       console_unlock();
+                       return -ENODEV;
+               }
                ret = fb_pan_display(info, &var);
-               console_unlock();
                unlock_fb_info(info);
+               console_unlock();
                if (ret == 0 && copy_to_user(argp, &var, sizeof(var)))
                        return -EFAULT;
                break;
@@ -1159,14 +1163,16 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
                unlock_fb_info(info);
                break;
        case FBIOBLANK:
-               if (!lock_fb_info(info))
-                       return -ENODEV;
                console_lock();
+               if (!lock_fb_info(info)) {
+                       console_unlock();
+                       return -ENODEV;
+               }
                info->flags |= FBINFO_MISC_USEREVENT;
                ret = fb_blank(info, arg);
                info->flags &= ~FBINFO_MISC_USEREVENT;
-               console_unlock();
                unlock_fb_info(info);
+               console_unlock();
                break;
        default:
                if (!lock_fb_info(info))
index 483d45180911f5729aa7ead5cd82558ccaf9c280..5754c9a4f58b49be5237ac50b70234779f0b07bd 100644 (file)
@@ -114,43 +114,7 @@ static struct bin_attribute w1_ds2760_bin_attr = {
        .read = w1_ds2760_read_bin,
 };
 
-static DEFINE_IDR(bat_idr);
-static DEFINE_MUTEX(bat_idr_lock);
-
-static int new_bat_id(void)
-{
-       int ret;
-
-       while (1) {
-               int id;
-
-               ret = idr_pre_get(&bat_idr, GFP_KERNEL);
-               if (ret == 0)
-                       return -ENOMEM;
-
-               mutex_lock(&bat_idr_lock);
-               ret = idr_get_new(&bat_idr, NULL, &id);
-               mutex_unlock(&bat_idr_lock);
-
-               if (ret == 0) {
-                       ret = id & MAX_ID_MASK;
-                       break;
-               } else if (ret == -EAGAIN) {
-                       continue;
-               } else {
-                       break;
-               }
-       }
-
-       return ret;
-}
-
-static void release_bat_id(int id)
-{
-       mutex_lock(&bat_idr_lock);
-       idr_remove(&bat_idr, id);
-       mutex_unlock(&bat_idr_lock);
-}
+static DEFINE_IDA(bat_ida);
 
 static int w1_ds2760_add_slave(struct w1_slave *sl)
 {
@@ -158,7 +122,7 @@ static int w1_ds2760_add_slave(struct w1_slave *sl)
        int id;
        struct platform_device *pdev;
 
-       id = new_bat_id();
+       id = ida_simple_get(&bat_ida, 0, 0, GFP_KERNEL);
        if (id < 0) {
                ret = id;
                goto noid;
@@ -187,7 +151,7 @@ bin_attr_failed:
 pdev_add_failed:
        platform_device_unregister(pdev);
 pdev_alloc_failed:
-       release_bat_id(id);
+       ida_simple_remove(&bat_ida, id);
 noid:
 success:
        return ret;
@@ -199,7 +163,7 @@ static void w1_ds2760_remove_slave(struct w1_slave *sl)
        int id = pdev->id;
 
        platform_device_unregister(pdev);
-       release_bat_id(id);
+       ida_simple_remove(&bat_ida, id);
        sysfs_remove_bin_file(&sl->dev.kobj, &w1_ds2760_bin_attr);
 }
 
@@ -217,14 +181,14 @@ static int __init w1_ds2760_init(void)
 {
        printk(KERN_INFO "1-Wire driver for the DS2760 battery monitor "
               " chip  - (c) 2004-2005, Szabolcs Gyurko\n");
-       idr_init(&bat_idr);
+       ida_init(&bat_ida);
        return w1_register_family(&w1_ds2760_family);
 }
 
 static void __exit w1_ds2760_exit(void)
 {
        w1_unregister_family(&w1_ds2760_family);
-       idr_destroy(&bat_idr);
+       ida_destroy(&bat_ida);
 }
 
 EXPORT_SYMBOL(w1_ds2760_read);
index 274c8f38303f5748478c47309c6e255b5c69ead1..a134b38e34b2d39730448e803ca2fb1ec6ab4beb 100644 (file)
@@ -99,43 +99,7 @@ static struct bin_attribute w1_ds2780_bin_attr = {
        .read = w1_ds2780_read_bin,
 };
 
-static DEFINE_IDR(bat_idr);
-static DEFINE_MUTEX(bat_idr_lock);
-
-static int new_bat_id(void)
-{
-       int ret;
-
-       while (1) {
-               int id;
-
-               ret = idr_pre_get(&bat_idr, GFP_KERNEL);
-               if (ret == 0)
-                       return -ENOMEM;
-
-               mutex_lock(&bat_idr_lock);
-               ret = idr_get_new(&bat_idr, NULL, &id);
-               mutex_unlock(&bat_idr_lock);
-
-               if (ret == 0) {
-                       ret = id & MAX_ID_MASK;
-                       break;
-               } else if (ret == -EAGAIN) {
-                       continue;
-               } else {
-                       break;
-               }
-       }
-
-       return ret;
-}
-
-static void release_bat_id(int id)
-{
-       mutex_lock(&bat_idr_lock);
-       idr_remove(&bat_idr, id);
-       mutex_unlock(&bat_idr_lock);
-}
+static DEFINE_IDA(bat_ida);
 
 static int w1_ds2780_add_slave(struct w1_slave *sl)
 {
@@ -143,7 +107,7 @@ static int w1_ds2780_add_slave(struct w1_slave *sl)
        int id;
        struct platform_device *pdev;
 
-       id = new_bat_id();
+       id = ida_simple_get(&bat_ida, 0, 0, GFP_KERNEL);
        if (id < 0) {
                ret = id;
                goto noid;
@@ -172,7 +136,7 @@ bin_attr_failed:
 pdev_add_failed:
        platform_device_unregister(pdev);
 pdev_alloc_failed:
-       release_bat_id(id);
+       ida_simple_remove(&bat_ida, id);
 noid:
        return ret;
 }
@@ -183,7 +147,7 @@ static void w1_ds2780_remove_slave(struct w1_slave *sl)
        int id = pdev->id;
 
        platform_device_unregister(pdev);
-       release_bat_id(id);
+       ida_simple_remove(&bat_ida, id);
        sysfs_remove_bin_file(&sl->dev.kobj, &w1_ds2780_bin_attr);
 }
 
@@ -199,14 +163,14 @@ static struct w1_family w1_ds2780_family = {
 
 static int __init w1_ds2780_init(void)
 {
-       idr_init(&bat_idr);
+       ida_init(&bat_ida);
        return w1_register_family(&w1_ds2780_family);
 }
 
 static void __exit w1_ds2780_exit(void)
 {
        w1_unregister_family(&w1_ds2780_family);
-       idr_destroy(&bat_idr);
+       ida_destroy(&bat_ida);
 }
 
 module_init(w1_ds2780_init);
index e29ec485af255822b8414be128fc8ef66da9a204..632b235f4fbe02c237de17fbde271c8bfe6f1240 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -1387,13 +1387,13 @@ static ssize_t aio_setup_vectored_rw(int type, struct kiocb *kiocb, bool compat)
                ret = compat_rw_copy_check_uvector(type,
                                (struct compat_iovec __user *)kiocb->ki_buf,
                                kiocb->ki_nbytes, 1, &kiocb->ki_inline_vec,
-                               &kiocb->ki_iovec);
+                               &kiocb->ki_iovec, 1);
        else
 #endif
                ret = rw_copy_check_uvector(type,
                                (struct iovec __user *)kiocb->ki_buf,
                                kiocb->ki_nbytes, 1, &kiocb->ki_inline_vec,
-                               &kiocb->ki_iovec);
+                               &kiocb->ki_iovec, 1);
        if (ret < 0)
                goto out;
 
index 15fceefbca0a02b9d1c9ddf3a4da224228c2ec40..bb85e484da08b40187bf2088fd43a27b42f7cd30 100644 (file)
@@ -1863,7 +1863,8 @@ static int btrfs_io_failed_hook(struct bio *failed_bio,
 
                read_lock(&em_tree->lock);
                em = lookup_extent_mapping(em_tree, start, failrec->len);
-               if (em->start > start || em->start + em->len < start) {
+               if (em && !IS_ERR(em) && (em->start > start ||
+                                       em->start + em->len < start)) {
                        free_extent_map(em);
                        em = NULL;
                }
index 0b48d018e38adbc1a72f78a4ab851626f2fffca8..53544759e42f766ccdf4380e509e437e7293c4f0 100644 (file)
@@ -550,7 +550,7 @@ out:
 ssize_t compat_rw_copy_check_uvector(int type,
                const struct compat_iovec __user *uvector, unsigned long nr_segs,
                unsigned long fast_segs, struct iovec *fast_pointer,
-               struct iovec **ret_pointer)
+               struct iovec **ret_pointer, int check_access)
 {
        compat_ssize_t tot_len;
        struct iovec *iov = *ret_pointer = fast_pointer;
@@ -597,7 +597,8 @@ ssize_t compat_rw_copy_check_uvector(int type,
                }
                if (len < 0)    /* size_t not fitting in compat_ssize_t .. */
                        goto out;
-               if (!access_ok(vrfy_dir(type), compat_ptr(buf), len)) {
+               if (check_access &&
+                   !access_ok(vrfy_dir(type), compat_ptr(buf), len)) {
                        ret = -EFAULT;
                        goto out;
                }
@@ -1111,7 +1112,7 @@ static ssize_t compat_do_readv_writev(int type, struct file *file,
                goto out;
 
        tot_len = compat_rw_copy_check_uvector(type, uvector, nr_segs,
-                                              UIO_FASTIOV, iovstack, &iov);
+                                              UIO_FASTIOV, iovstack, &iov, 1);
        if (tot_len == 0) {
                ret = 0;
                goto out;
index b98b5a184a8a4b9e69a2c1ec6d111721faefc723..f37e6c7c853f18d70a3881b4fada4e2ca963eb3b 100644 (file)
@@ -932,12 +932,13 @@ struct ext4_inode_info {
 #define test_opt2(sb, opt)             (EXT4_SB(sb)->s_mount_opt2 & \
                                         EXT4_MOUNT2_##opt)
 
-#define ext4_set_bit                   __test_and_set_bit_le
+#define ext4_test_and_set_bit          __test_and_set_bit_le
+#define ext4_set_bit                   __set_bit_le
 #define ext4_set_bit_atomic            ext2_set_bit_atomic
-#define ext4_clear_bit                 __test_and_clear_bit_le
+#define ext4_test_and_clear_bit                __test_and_clear_bit_le
+#define ext4_clear_bit                 __clear_bit_le
 #define ext4_clear_bit_atomic          ext2_clear_bit_atomic
 #define ext4_test_bit                  test_bit_le
-#define ext4_find_first_zero_bit       find_first_zero_bit_le
 #define ext4_find_next_zero_bit                find_next_zero_bit_le
 #define ext4_find_next_bit             find_next_bit_le
 
index 9c63f273b550497759103ad0f6b4aaafd8e2049d..fd96ea1facd3fd6af36bc400fe686659b62b14e1 100644 (file)
@@ -252,7 +252,7 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
                fatal = ext4_journal_get_write_access(handle, bh2);
        }
        ext4_lock_group(sb, block_group);
-       cleared = ext4_clear_bit(bit, bitmap_bh->b_data);
+       cleared = ext4_test_and_clear_bit(bit, bitmap_bh->b_data);
        if (fatal || !cleared) {
                ext4_unlock_group(sb, block_group);
                goto out;
@@ -729,7 +729,7 @@ static int ext4_claim_inode(struct super_block *sb,
         */
        down_read(&grp->alloc_sem);
        ext4_lock_group(sb, group);
-       if (ext4_set_bit(ino, inode_bitmap_bh->b_data)) {
+       if (ext4_test_and_set_bit(ino, inode_bitmap_bh->b_data)) {
                /* not a free inode */
                retval = 1;
                goto err_ret;
index bcde467acca396a1916831849bc495faa5d413b5..d355e6e36b366bfe7dc8cc91cbabdad05976ba2c 100644 (file)
@@ -849,5 +849,52 @@ static inline void _ocfs2_clear_bit(unsigned int bit, unsigned long *bitmap)
 #define ocfs2_test_bit test_bit_le
 #define ocfs2_find_next_zero_bit find_next_zero_bit_le
 #define ocfs2_find_next_bit find_next_bit_le
+
+static inline void *correct_addr_and_bit_unaligned(int *bit, void *addr)
+{
+#if BITS_PER_LONG == 64
+       *bit += ((unsigned long) addr & 7UL) << 3;
+       addr = (void *) ((unsigned long) addr & ~7UL);
+#elif BITS_PER_LONG == 32
+       *bit += ((unsigned long) addr & 3UL) << 3;
+       addr = (void *) ((unsigned long) addr & ~3UL);
+#else
+#error "how many bits you are?!"
+#endif
+       return addr;
+}
+
+static inline void ocfs2_set_bit_unaligned(int bit, void *bitmap)
+{
+       bitmap = correct_addr_and_bit_unaligned(&bit, bitmap);
+       ocfs2_set_bit(bit, bitmap);
+}
+
+static inline void ocfs2_clear_bit_unaligned(int bit, void *bitmap)
+{
+       bitmap = correct_addr_and_bit_unaligned(&bit, bitmap);
+       ocfs2_clear_bit(bit, bitmap);
+}
+
+static inline int ocfs2_test_bit_unaligned(int bit, void *bitmap)
+{
+       bitmap = correct_addr_and_bit_unaligned(&bit, bitmap);
+       return ocfs2_test_bit(bit, bitmap);
+}
+
+static inline int ocfs2_find_next_zero_bit_unaligned(void *bitmap, int max,
+                                                       int start)
+{
+       int fix = 0, ret, tmpmax;
+       bitmap = correct_addr_and_bit_unaligned(&fix, bitmap);
+       tmpmax = max + fix;
+       start += fix;
+
+       ret = ocfs2_find_next_zero_bit(bitmap, tmpmax, start) - fix;
+       if (ret > max)
+               return max;
+       return ret;
+}
+
 #endif  /* OCFS2_H */
 
index dc8007fc924718c6d461b22cee52e4a8fbd6ae7d..bee645e15cc59fa38c55adca7945ff958bcfb4dd 100644 (file)
@@ -549,8 +549,8 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
                                goto out_commit;
                        }
                        lock_buffer(qbh);
-                       WARN_ON(!ocfs2_test_bit(bit, dchunk->dqc_bitmap));
-                       ocfs2_clear_bit(bit, dchunk->dqc_bitmap);
+                       WARN_ON(!ocfs2_test_bit_unaligned(bit, dchunk->dqc_bitmap));
+                       ocfs2_clear_bit_unaligned(bit, dchunk->dqc_bitmap);
                        le32_add_cpu(&dchunk->dqc_free, 1);
                        unlock_buffer(qbh);
                        ocfs2_journal_dirty(handle, qbh);
@@ -944,7 +944,7 @@ static struct ocfs2_quota_chunk *ocfs2_find_free_entry(struct super_block *sb,
                      * ol_quota_entries_per_block(sb);
        }
 
-       found = ocfs2_find_next_zero_bit(dchunk->dqc_bitmap, len, 0);
+       found = ocfs2_find_next_zero_bit_unaligned(dchunk->dqc_bitmap, len, 0);
        /* We failed? */
        if (found == len) {
                mlog(ML_ERROR, "Did not find empty entry in chunk %d with %u"
@@ -1208,7 +1208,7 @@ static void olq_alloc_dquot(struct buffer_head *bh, void *private)
        struct ocfs2_local_disk_chunk *dchunk;
 
        dchunk = (struct ocfs2_local_disk_chunk *)bh->b_data;
-       ocfs2_set_bit(*offset, dchunk->dqc_bitmap);
+       ocfs2_set_bit_unaligned(*offset, dchunk->dqc_bitmap);
        le32_add_cpu(&dchunk->dqc_free, -1);
 }
 
@@ -1289,7 +1289,7 @@ int ocfs2_local_release_dquot(handle_t *handle, struct dquot *dquot)
                        (od->dq_chunk->qc_headerbh->b_data);
        /* Mark structure as freed */
        lock_buffer(od->dq_chunk->qc_headerbh);
-       ocfs2_clear_bit(offset, dchunk->dqc_bitmap);
+       ocfs2_clear_bit_unaligned(offset, dchunk->dqc_bitmap);
        le32_add_cpu(&dchunk->dqc_free, 1);
        unlock_buffer(od->dq_chunk->qc_headerbh);
        ocfs2_journal_dirty(handle, od->dq_chunk->qc_headerbh);
index 179f1c33ea578481cdc3388d54717089704a51a3..7a220bec217cf88b63947c63c4ac866b91b0ba45 100644 (file)
@@ -617,7 +617,8 @@ ssize_t do_loop_readv_writev(struct file *filp, struct iovec *iov,
 ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
                              unsigned long nr_segs, unsigned long fast_segs,
                              struct iovec *fast_pointer,
-                             struct iovec **ret_pointer)
+                             struct iovec **ret_pointer,
+                             int check_access)
 {
        unsigned long seg;
        ssize_t ret;
@@ -673,7 +674,8 @@ ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
                        ret = -EINVAL;
                        goto out;
                }
-               if (unlikely(!access_ok(vrfy_dir(type), buf, len))) {
+               if (check_access
+                   && unlikely(!access_ok(vrfy_dir(type), buf, len))) {
                        ret = -EFAULT;
                        goto out;
                }
@@ -705,7 +707,7 @@ static ssize_t do_readv_writev(int type, struct file *file,
        }
 
        ret = rw_copy_check_uvector(type, uvector, nr_segs,
-                       ARRAY_SIZE(iovstack), iovstack, &iov);
+                                   ARRAY_SIZE(iovstack), iovstack, &iov, 1);
        if (ret <= 0)
                goto out;
 
index 8779405e15a871eba64681021065ed1ab0e71853..4ce46bd370cdaa8a76ad0ed6d984251c9b76de7d 100644 (file)
@@ -548,7 +548,8 @@ extern ssize_t compat_rw_copy_check_uvector(int type,
                const struct compat_iovec __user *uvector,
                unsigned long nr_segs,
                unsigned long fast_segs, struct iovec *fast_pointer,
-               struct iovec **ret_pointer);
+               struct iovec **ret_pointer,
+               int check_access);
 
 extern void __user *compat_alloc_user_space(unsigned long len);
 
index 65970b811e22359a7e94afbbf1e0e204ce4ad4dc..0e5f5785d9f2df3c524099142da6202b54f0ff47 100644 (file)
@@ -46,6 +46,8 @@ struct debug_obj {
  *                     fails
  * @fixup_free:                fixup function, which is called when the free check
  *                     fails
+ * @fixup_assert_init:  fixup function, which is called when the assert_init
+ *                     check fails
  */
 struct debug_obj_descr {
        const char              *name;
@@ -54,6 +56,7 @@ struct debug_obj_descr {
        int (*fixup_activate)   (void *addr, enum debug_obj_state state);
        int (*fixup_destroy)    (void *addr, enum debug_obj_state state);
        int (*fixup_free)       (void *addr, enum debug_obj_state state);
+       int (*fixup_assert_init)(void *addr, enum debug_obj_state state);
 };
 
 #ifdef CONFIG_DEBUG_OBJECTS
@@ -64,6 +67,7 @@ extern void debug_object_activate  (void *addr, struct debug_obj_descr *descr);
 extern void debug_object_deactivate(void *addr, struct debug_obj_descr *descr);
 extern void debug_object_destroy   (void *addr, struct debug_obj_descr *descr);
 extern void debug_object_free      (void *addr, struct debug_obj_descr *descr);
+extern void debug_object_assert_init(void *addr, struct debug_obj_descr *descr);
 
 /*
  * Active state:
@@ -89,6 +93,8 @@ static inline void
 debug_object_destroy   (void *addr, struct debug_obj_descr *descr) { }
 static inline void
 debug_object_free      (void *addr, struct debug_obj_descr *descr) { }
+static inline void
+debug_object_assert_init(void *addr, struct debug_obj_descr *descr) { }
 
 static inline void debug_objects_early_init(void) { }
 static inline void debug_objects_mem_init(void) { }
index 7b776d71d36d0e465dfb4b6384899026253540cc..6701d9432f0bc89d4f935b861fc1b5a9b8bd3d77 100644 (file)
@@ -219,14 +219,19 @@ struct dmar_rmrr_unit {
 #define for_each_rmrr_units(rmrr) \
        list_for_each_entry(rmrr, &dmar_rmrr_units, list)
 
+extern struct list_head dmar_atsr_units;
 struct dmar_atsr_unit {
        struct list_head list;          /* list of ATSR units */
        struct acpi_dmar_header *hdr;   /* ACPI header */
        struct pci_dev **devices;       /* target devices */
        int devices_cnt;                /* target device count */
+       u16     segment;                /* PCI domain           */
        u8 include_all:1;               /* include all ports */
 };
 
+#define for_each_atsr_unit(atsr) \
+       list_for_each_entry(atsr, &dmar_atsr_units, list)
+
 extern int intel_iommu_init(void);
 #else /* !CONFIG_DMAR: */
 static inline int intel_iommu_init(void) { return -ENODEV; }
index 178cdb4f1d4afe81a66e631872de4b587e95d1c4..e4fe6034b96a2f6cbf61cbd515d9d709faa62760 100644 (file)
@@ -1625,9 +1625,10 @@ struct inode_operations {
 struct seq_file;
 
 ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
-                               unsigned long nr_segs, unsigned long fast_segs,
-                               struct iovec *fast_pointer,
-                               struct iovec **ret_pointer);
+                             unsigned long nr_segs, unsigned long fast_segs,
+                             struct iovec *fast_pointer,
+                             struct iovec **ret_pointer,
+                             int check_access);
 
 extern ssize_t vfs_read(struct file *, char __user *, size_t, loff_t *);
 extern ssize_t vfs_write(struct file *, const char __user *, size_t, loff_t *);
index 219ca4f6bea66a0a755101ea2d9c615a67854283..d690c0fe4b8b24b425790789b66e317285af1e5e 100644 (file)
@@ -125,6 +125,7 @@ struct hpet_info {
 #define        HPET_EPI        _IO('h', 0x04)  /* enable periodic */
 #define        HPET_DPI        _IO('h', 0x05)  /* disable periodic */
 #define        HPET_IRQFREQ    _IOW('h', 0x6, unsigned long)   /* IRQFREQ usec */
+#define        HPET_ALLOC_TIMER _IO('h', 0x7)
 
 #define MAX_HPET_TBS   8               /* maximum hpet timer blocks */
 
index f97672a36fa8d740c16751a0dc2e0753b5092b30..265e2c3cbd1cd74d2b3efd416aa9301c90ae90ad 100644 (file)
@@ -303,7 +303,7 @@ extern void jiffies_to_timespec(const unsigned long jiffies,
 extern unsigned long timeval_to_jiffies(const struct timeval *value);
 extern void jiffies_to_timeval(const unsigned long jiffies,
                               struct timeval *value);
-extern clock_t jiffies_to_clock_t(long x);
+extern clock_t jiffies_to_clock_t(unsigned long x);
 extern unsigned long clock_t_to_jiffies(unsigned long x);
 extern u64 jiffies_64_to_clock_t(u64 x);
 extern u64 nsec_to_clock_t(u64 x);
diff --git a/include/linux/leds-renesas-tpu.h b/include/linux/leds-renesas-tpu.h
new file mode 100644 (file)
index 0000000..0553870
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __LEDS_RENESAS_TPU_H__
+#define __LEDS_RENESAS_TPU_H__
+
+struct led_renesas_tpu_config {
+       char *name;
+       unsigned pin_gpio_fn;
+       unsigned pin_gpio;
+       unsigned int channel_offset;
+       unsigned int timer_bit;
+       unsigned int max_brightness;
+       unsigned int refresh_rate;
+};
+
+#endif /* __LEDS_RENESAS_TPU_H__ */
index 1e5df2af8d845c6a2ff63115245c88cba4a95cdc..2d4beab0d5b7270a96bbff233457b0cb3ae095d1 100644 (file)
 #define ANON_INODE_FS_MAGIC    0x09041934
 #define PSTOREFS_MAGIC         0x6165676C
 
-#define MINIX_SUPER_MAGIC      0x137F          /* original minix fs */
-#define MINIX_SUPER_MAGIC2     0x138F          /* minix fs, 30 char names */
-#define MINIX2_SUPER_MAGIC     0x2468          /* minix V2 fs */
-#define MINIX2_SUPER_MAGIC2    0x2478          /* minix V2 fs, 30 char names */
-#define MINIX3_SUPER_MAGIC     0x4d5a          /* minix V3 fs */
+#define MINIX_SUPER_MAGIC      0x137F          /* minix v1 fs, 14 char names */
+#define MINIX_SUPER_MAGIC2     0x138F          /* minix v1 fs, 30 char names */
+#define MINIX2_SUPER_MAGIC     0x2468          /* minix v2 fs, 14 char names */
+#define MINIX2_SUPER_MAGIC2    0x2478          /* minix v2 fs, 30 char names */
+#define MINIX3_SUPER_MAGIC     0x4d5a          /* minix v3 fs, 60 char names */
 
 #define MSDOS_SUPER_MAGIC      0x4d44          /* MD */
 #define NCP_SUPER_MAGIC                0x564c          /* Guess, what 0x564c is :-) */
index 3b535db00a94983324d42106fae5bd05670f3157..5633f514889b54e142c32364fae311a12e7abbc1 100644 (file)
@@ -35,7 +35,8 @@ enum mem_cgroup_page_stat_item {
 extern unsigned long mem_cgroup_isolate_pages(unsigned long nr_to_scan,
                                        struct list_head *dst,
                                        unsigned long *scanned, int order,
-                                       int mode, struct zone *z,
+                                       isolate_mode_t mode,
+                                       struct zone *z,
                                        struct mem_cgroup *mem_cont,
                                        int active, int file);
 
index be1ac8d7789be37b21dd5fdf72832aea621926bd..19fd15d4734ce9156ae20277f7919f55bf8ceb08 100644 (file)
@@ -164,6 +164,18 @@ static inline int is_unevictable_lru(enum lru_list l)
 #define LRU_ALL_EVICTABLE (LRU_ALL_FILE | LRU_ALL_ANON)
 #define LRU_ALL             ((1 << NR_LRU_LISTS) - 1)
 
+/* Isolate inactive pages */
+#define ISOLATE_INACTIVE       ((__force fmode_t)0x1)
+/* Isolate active pages */
+#define ISOLATE_ACTIVE         ((__force fmode_t)0x2)
+/* Isolate clean file */
+#define ISOLATE_CLEAN          ((__force fmode_t)0x4)
+/* Isolate unmapped file */
+#define ISOLATE_UNMAPPED       ((__force fmode_t)0x8)
+
+/* LRU Isolation modes. */
+typedef unsigned __bitwise__ isolate_mode_t;
+
 enum zone_watermarks {
        WMARK_MIN,
        WMARK_LOW,
diff --git a/include/linux/pps-gpio.h b/include/linux/pps-gpio.h
new file mode 100644 (file)
index 0000000..0035abe
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * pps-gpio.h -- PPS client for GPIOs
+ *
+ *
+ * Copyright (C) 2011 James Nuss <jamesnuss@nanometrics.ca>
+ *
+ *   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.
+ */
+
+#ifndef _PPS_GPIO_H
+#define _PPS_GPIO_H
+
+struct pps_gpio_platform_data {
+       bool assert_falling_edge;
+       bool capture_clear;
+       unsigned int gpio_pin;
+       const char *gpio_label;
+};
+
+#endif
index 9680867a41fb93c7b5ef0a7c989b448eefd4a066..3808f10a66219a32b00b36f6f1c7ed39a73e413a 100644 (file)
@@ -245,15 +245,10 @@ static inline void lru_cache_add_file(struct page *page)
        __lru_cache_add(page, LRU_INACTIVE_FILE);
 }
 
-/* LRU Isolation modes. */
-#define ISOLATE_INACTIVE 0     /* Isolate inactive pages. */
-#define ISOLATE_ACTIVE 1       /* Isolate active pages. */
-#define ISOLATE_BOTH 2         /* Isolate both active and inactive pages. */
-
 /* linux/mm/vmscan.c */
 extern unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
                                        gfp_t gfp_mask, nodemask_t *mask);
-extern int __isolate_lru_page(struct page *page, int mode, int file);
+extern int __isolate_lru_page(struct page *page, isolate_mode_t mode, int file);
 extern unsigned long shrink_all_memory(unsigned long nr_pages);
 extern int vm_swappiness;
 extern int remove_mapping(struct address_space *mapping, struct page *page);
index 8c03b98df5f93d196d523c60f31a850ffe9a22e4..0dc0809125f63e11108420f562c6e32f1678e934 100644 (file)
@@ -847,4 +847,17 @@ asmlinkage long sys_open_by_handle_at(int mountdirfd,
                                      struct file_handle __user *handle,
                                      int flags);
 asmlinkage long sys_setns(int fd, int nstype);
+asmlinkage long sys_process_vm_readv(pid_t pid,
+                                    const struct iovec __user *lvec,
+                                    unsigned long liovcnt,
+                                    const struct iovec __user *rvec,
+                                    unsigned long riovcnt,
+                                    unsigned long flags);
+asmlinkage long sys_process_vm_writev(pid_t pid,
+                                     const struct iovec __user *lvec,
+                                     unsigned long liovcnt,
+                                     const struct iovec __user *rvec,
+                                     unsigned long riovcnt,
+                                     unsigned long flags);
+
 #endif
index 11684d9e6bd2391374f2cc3fd9ff7d4f9df4e11d..2487af98839789b10b871f9a95ad26e3908e4feb 100644 (file)
@@ -971,6 +971,10 @@ extern int proc_dointvec(struct ctl_table *, int,
                         void __user *, size_t *, loff_t *);
 extern int proc_dointvec_minmax(struct ctl_table *, int,
                                void __user *, size_t *, loff_t *);
+extern int proc_dointvec_bool(struct ctl_table *, int,
+                               void __user *, size_t *, loff_t *);
+extern int proc_dointvec_unsigned(struct ctl_table *, int,
+                               void __user *, size_t *, loff_t *);
 extern int proc_dointvec_jiffies(struct ctl_table *, int,
                                 void __user *, size_t *, loff_t *);
 extern int proc_dointvec_userhz_jiffies(struct ctl_table *, int,
index f1bfa12ea246209802624502c50da5380e66049e..5e8bd6cf8c2d71e85c3c1834124c1b0e6a62a142 100644 (file)
@@ -129,8 +129,6 @@ extern int vm_highmem_is_dirtyable;
 extern int block_dump;
 extern int laptop_mode;
 
-extern unsigned long determine_dirtyable_memory(void);
-
 extern int dirty_background_ratio_handler(struct ctl_table *table, int write,
                void __user *buffer, size_t *lenp,
                loff_t *ppos);
index 58ce8fe4478365484ac2d5ab2e7883efce83d114..5cb20ccb195606b9cc0fdac6869b2789c06e1649 100644 (file)
@@ -23,7 +23,7 @@
 #define SCSI_NETLINK_H
 
 #include <linux/netlink.h>
-
+#include <linux/types.h>
 
 /*
  * This file intended to be included by both kernel and user space
diff --git a/include/trace/events/irq_vectors.h b/include/trace/events/irq_vectors.h
new file mode 100644 (file)
index 0000000..699ddaa
--- /dev/null
@@ -0,0 +1,56 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM irq_vectors
+
+#if !defined(_TRACE_IRQ_VECTORS_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_IRQ_VECTORS_H
+
+#include <linux/tracepoint.h>
+#include <asm/irq.h>
+
+#ifndef irq_vector_name_table
+#define irq_vector_name_table { -1, NULL }
+#endif
+
+DECLARE_EVENT_CLASS(irq_vector,
+
+       TP_PROTO(int irq),
+
+       TP_ARGS(irq),
+
+       TP_STRUCT__entry(
+               __field(        int,    irq     )
+       ),
+
+       TP_fast_assign(
+               __entry->irq = irq;
+       ),
+
+       TP_printk("irq=%d name=%s", __entry->irq,
+               __print_symbolic(__entry->irq, irq_vector_name_table))
+);
+
+/*
+ * irq_vector_entry - called before enterring a interrupt vector handler
+ */
+DEFINE_EVENT(irq_vector, irq_vector_entry,
+
+       TP_PROTO(int irq),
+
+       TP_ARGS(irq)
+);
+
+/*
+ * irq_vector_exit - called immediately after the interrupt vector
+ * handler returns
+ */
+DEFINE_EVENT(irq_vector, irq_vector_exit,
+
+       TP_PROTO(int irq),
+
+       TP_ARGS(irq)
+);
+
+#endif /*  _TRACE_IRQ_VECTORS_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
index 36851f7f13daf558107d0df16052f5d8939bd1d1..edc4b3d25a2d4e38917c83554eccd23a32fc8815 100644 (file)
@@ -266,7 +266,7 @@ DECLARE_EVENT_CLASS(mm_vmscan_lru_isolate_template,
                unsigned long nr_lumpy_taken,
                unsigned long nr_lumpy_dirty,
                unsigned long nr_lumpy_failed,
-               int isolate_mode),
+               isolate_mode_t isolate_mode),
 
        TP_ARGS(order, nr_requested, nr_scanned, nr_taken, nr_lumpy_taken, nr_lumpy_dirty, nr_lumpy_failed, isolate_mode),
 
@@ -278,7 +278,7 @@ DECLARE_EVENT_CLASS(mm_vmscan_lru_isolate_template,
                __field(unsigned long, nr_lumpy_taken)
                __field(unsigned long, nr_lumpy_dirty)
                __field(unsigned long, nr_lumpy_failed)
-               __field(int, isolate_mode)
+               __field(isolate_mode_t, isolate_mode)
        ),
 
        TP_fast_assign(
@@ -312,7 +312,7 @@ DEFINE_EVENT(mm_vmscan_lru_isolate_template, mm_vmscan_lru_isolate,
                unsigned long nr_lumpy_taken,
                unsigned long nr_lumpy_dirty,
                unsigned long nr_lumpy_failed,
-               int isolate_mode),
+               isolate_mode_t isolate_mode),
 
        TP_ARGS(order, nr_requested, nr_scanned, nr_taken, nr_lumpy_taken, nr_lumpy_dirty, nr_lumpy_failed, isolate_mode)
 
@@ -327,7 +327,7 @@ DEFINE_EVENT(mm_vmscan_lru_isolate_template, mm_vmscan_memcg_isolate,
                unsigned long nr_lumpy_taken,
                unsigned long nr_lumpy_dirty,
                unsigned long nr_lumpy_failed,
-               int isolate_mode),
+               isolate_mode_t isolate_mode),
 
        TP_ARGS(order, nr_requested, nr_scanned, nr_taken, nr_lumpy_taken, nr_lumpy_dirty, nr_lumpy_failed, isolate_mode)
 
index c0851a8e030cbcf38701f77a5d79e253d81e0327..0f6e1d985a3b2851c662337c1671b57cc4270f0a 100644 (file)
@@ -28,7 +28,7 @@ int __initdata rd_doload;     /* 1 = load RAM disk, 0 = don't load */
 int root_mountflags = MS_RDONLY | MS_SILENT;
 static char * __initdata root_device_name;
 static char __initdata saved_root_name[64];
-static int __initdata root_wait;
+static int root_wait;
 
 dev_t ROOT_DEV;
 
@@ -85,12 +85,15 @@ no_match:
 
 /**
  * devt_from_partuuid - looks up the dev_t of a partition by its UUID
- * @uuid:      36 byte char array containing a hex ascii UUID
+ * @uuid:      min 36 byte char array containing a hex ascii UUID
  *
  * The function will return the first partition which contains a matching
  * UUID value in its partition_meta_info struct.  This does not search
  * by filesystem UUIDs.
  *
+ * If @uuid is followed by a "/PARTNROFF=%d", then the number will be
+ * extracted and used as an offset from the partition identified by the UUID.
+ *
  * Returns the matching dev_t on success or 0 on failure.
  */
 static dev_t devt_from_partuuid(char *uuid_str)
@@ -98,6 +101,28 @@ static dev_t devt_from_partuuid(char *uuid_str)
        dev_t res = 0;
        struct device *dev = NULL;
        u8 uuid[16];
+       struct gendisk *disk;
+       struct hd_struct *part;
+       int offset = 0;
+
+       if (strlen(uuid_str) < 36)
+               goto done;
+
+       /* Check for optional partition number offset attributes. */
+       if (uuid_str[36]) {
+               char c = 0;
+               /* Explicitly fail on poor PARTUUID syntax. */
+               if (sscanf(&uuid_str[36],
+                          "/PARTNROFF=%d%c", &offset, &c) != 1) {
+                       printk(KERN_ERR "VFS: PARTUUID= is invalid.\n"
+                        "Expected PARTUUID=<valid-uuid-id>[/PARTNROFF=%%d]\n");
+                       if (root_wait)
+                               printk(KERN_ERR
+                                    "Disabling rootwait; root= is invalid.\n");
+                       root_wait = 0;
+                       goto done;
+               }
+       }
 
        /* Pack the requested UUID in the expected format. */
        part_pack_uuid(uuid_str, uuid);
@@ -107,8 +132,21 @@ static dev_t devt_from_partuuid(char *uuid_str)
                goto done;
 
        res = dev->devt;
-       put_device(dev);
 
+       /* Attempt to find the partition by offset. */
+       if (!offset)
+               goto no_offset;
+
+       res = 0;
+       disk = part_to_disk(dev_to_part(dev));
+       part = disk_get_part(disk, dev_to_part(dev)->partno + offset);
+       if (part) {
+               res = part_devt(part);
+               put_device(part_to_dev(part));
+       }
+
+no_offset:
+       put_device(dev);
 done:
        return res;
 }
@@ -126,6 +164,8 @@ done:
  *        used when disk name of partitioned disk ends on a digit.
  *     6) PARTUUID=00112233-4455-6677-8899-AABBCCDDEEFF representing the
  *        unique id of a partition if the partition table provides it.
+ *     7) PARTUUID=<UUID>/PARTNROFF=<int> to select a partition in relation to
+ *        a partition with a known unique id.
  *
  *     If name doesn't have fall into the categories above, we return (0,0).
  *     block_class is used to check if something is a disk name. If the disk
@@ -143,8 +183,6 @@ dev_t name_to_dev_t(char *name)
 #ifdef CONFIG_BLOCK
        if (strncmp(name, "PARTUUID=", 9) == 0) {
                name += 9;
-               if (strlen(name) != 36)
-                       goto fail;
                res = devt_from_partuuid(name);
                if (!res)
                        goto fail;
index 8b5ce5d3f3ef3e4f468d5afc4175cd22518fc029..6da67b60c7b324f253c68f3bc365d822b4dc99d4 100644 (file)
@@ -20,6 +20,9 @@
 
 DEFINE_SPINLOCK(mq_lock);
 
+#define INIT_IPC_SHM_IDS(name) \
+       { .rw_mutex = __RWSEM_INITIALIZER(name.rw_mutex), }
+
 /*
  * The next 2 defines are here bc this is the only file
  * compiled when either CONFIG_SYSVIPC and CONFIG_POSIX_MQUEUE
@@ -27,6 +30,9 @@ DEFINE_SPINLOCK(mq_lock);
  */
 struct ipc_namespace init_ipc_ns = {
        .count          = ATOMIC_INIT(1),
+       .ids    = {
+               [IPC_SHM_IDS] = INIT_IPC_SHM_IDS(init_ipc_ns.ids[IPC_SHM_IDS]),
+       },
 #ifdef CONFIG_POSIX_MQUEUE
        .mq_queues_max   = DFLT_QUEUESMAX,
        .mq_msg_max      = DFLT_MSGMAX,
index 02ecf2c078fce9b62ee2b1ec0ef252c0320acdf5..c548ba5b0384a97310d74193d937b6f3b4236262 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -74,9 +74,18 @@ void shm_init_ns(struct ipc_namespace *ns)
        ns->shm_ctlmax = SHMMAX;
        ns->shm_ctlall = SHMALL;
        ns->shm_ctlmni = SHMMNI;
-       ns->shm_rmid_forced = 0;
+       ns->shm_rmid_forced = 1;
        ns->shm_tot = 0;
-       ipc_init_ids(&shm_ids(ns));
+
+       /*
+        * For init_ipc_ns shm_ids().rw_mutex is statically initialized
+        * as kernel threads should be able to use it in do_exit() before
+        * shm_init(), which is called on do_initcall()
+        */
+       if (ns == &init_ipc_ns)
+               __ipc_init_ids(&shm_ids(ns));
+       else
+               ipc_init_ids(&shm_ids(ns));
 }
 
 /*
index 75261a31d48da6ce865ffacb3e180b2708906678..673dde5f5a78243413872acc7848355b0462ce76 100644 (file)
@@ -108,31 +108,35 @@ static int __init ipc_init(void)
 }
 __initcall(ipc_init);
 
-/**
- *     ipc_init_ids            -       initialise IPC identifiers
- *     @ids: Identifier set
- *
- *     Set up the sequence range to use for the ipc identifier range (limited
- *     below IPCMNI) then initialise the ids idr.
- */
-void ipc_init_ids(struct ipc_ids *ids)
+void __ipc_init_ids(struct ipc_ids *ids)
 {
-       init_rwsem(&ids->rw_mutex);
-
        ids->in_use = 0;
        ids->seq = 0;
        {
                int seq_limit = INT_MAX/SEQ_MULTIPLIER;
                if (seq_limit > USHRT_MAX)
                        ids->seq_max = USHRT_MAX;
-                else
-                       ids->seq_max = seq_limit;
+               else
+                       ids->seq_max = seq_limit;
        }
 
        idr_init(&ids->ipcs_idr);
 }
 
+/**
+ *     ipc_init_ids            -       initialise IPC identifiers
+ *     @ids: Identifier set
+ *
+ *     Set up the sequence range to use for the ipc identifier range (limited
+ *     below IPCMNI) then initialise the ids idr.
+ */
+
+void ipc_init_ids(struct ipc_ids *ids)
+{
+       init_rwsem(&ids->rw_mutex);
+       __ipc_init_ids(ids);
+}
+
 #ifdef CONFIG_PROC_FS
 static const struct file_operations sysvipc_proc_fops;
 /**
index 6f5c20bedaab21ff1dd0e05ad90ae0ecadeb82aa..8bbcd9c850b3e5e184da94e5dc4235593dc95d69 100644 (file)
@@ -80,6 +80,7 @@ struct seq_file;
 struct ipc_ids;
 
 void ipc_init_ids(struct ipc_ids *);
+void __ipc_init_ids(struct ipc_ids *ids);
 #ifdef CONFIG_PROC_FS
 void __init ipc_init_proc_interface(const char *path, const char *header,
                int ids, int (*show)(struct seq_file *, void *));
index 09fae2677a45e11ab650b91b1dee7877a2ee8957..2c1d6ab7106ee9921bc8456d0e9b5e11637a11f3 100644 (file)
@@ -1260,12 +1260,13 @@ static void audit_log_vformat(struct audit_buffer *ab, const char *fmt,
                avail = audit_expand(ab,
                        max_t(unsigned, AUDIT_BUFSIZ, 1+len-avail));
                if (!avail)
-                       goto out;
+                       goto out_va_end;
                len = vsnprintf(skb_tail_pointer(skb), avail, fmt, args2);
        }
-       va_end(args2);
        if (len > 0)
                skb_put(skb, len);
+out_va_end:
+       va_end(args2);
 out:
        return;
 }
index 184d8987489d32c974b0f80dcab8fba992322e0b..d3466d09a7ca790048517ce5d712214873470be8 100644 (file)
@@ -2198,7 +2198,7 @@ static ssize_t write_enabled_file_bool(struct file *file,
               const char __user *user_buf, size_t count, loff_t *ppos)
 {
        char buf[32];
-       int buf_size;
+       size_t buf_size;
 
        buf_size = min(count, (sizeof(buf)-1));
        if (copy_from_user(buf, user_buf, buf_size))
index 62cbc8877fef2564d2d7284d44959d08e64b08ce..7a34e9fcc8160e48874943b00c7c10bee631caf6 100644 (file)
@@ -146,6 +146,10 @@ cond_syscall(sys_io_submit);
 cond_syscall(sys_io_cancel);
 cond_syscall(sys_io_getevents);
 cond_syscall(sys_syslog);
+cond_syscall(sys_process_vm_readv);
+cond_syscall(sys_process_vm_writev);
+cond_syscall(compat_sys_process_vm_readv);
+cond_syscall(compat_sys_process_vm_writev);
 
 /* arch-specific weak syscall entries */
 cond_syscall(sys_pciconfig_read);
index 4f057f9c0c4302d01d647f026410d9b77c781cf5..f31e7ec8ceaaa0f3f866bc6f9b6f5f10eef7a1f5 100644 (file)
@@ -349,9 +349,7 @@ static struct ctl_table kern_table[] = {
                .data           = &sysctl_timer_migration,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .proc_handler   = proc_dointvec_bool,
        },
 #endif
        {
@@ -709,9 +707,7 @@ static struct ctl_table kern_table[] = {
                .data           = &dmesg_restrict,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .proc_handler   = proc_dointvec_bool,
        },
        {
                .procname       = "kptr_restrict",
@@ -754,9 +750,7 @@ static struct ctl_table kern_table[] = {
                .data           = &softlockup_panic,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .proc_handler   = proc_dointvec_bool,
        },
        {
                .procname       = "nmi_watchdog",
@@ -870,9 +864,7 @@ static struct ctl_table kern_table[] = {
                .data           = &sysctl_hung_task_panic,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .proc_handler   = proc_dointvec_bool,
        },
        {
                .procname       = "hung_task_check_count",
@@ -1202,8 +1194,7 @@ static struct ctl_table vm_table[] = {
                .data           = &sysctl_max_map_count,
                .maxlen         = sizeof(sysctl_max_map_count),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .proc_handler   = proc_dointvec_unsigned,
        },
 #else
        {
@@ -1211,8 +1202,7 @@ static struct ctl_table vm_table[] = {
                .data           = &sysctl_nr_trim_pages,
                .maxlen         = sizeof(sysctl_nr_trim_pages),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .proc_handler   = proc_dointvec_unsigned,
        },
 #endif
        {
@@ -1227,16 +1217,14 @@ static struct ctl_table vm_table[] = {
                .data           = &block_dump,
                .maxlen         = sizeof(block_dump),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec,
-               .extra1         = &zero,
+               .proc_handler   = proc_dointvec_unsigned,
        },
        {
                .procname       = "vfs_cache_pressure",
                .data           = &sysctl_vfs_cache_pressure,
                .maxlen         = sizeof(sysctl_vfs_cache_pressure),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec,
-               .extra1         = &zero,
+               .proc_handler   = proc_dointvec_unsigned,
        },
 #ifdef HAVE_ARCH_PICK_MMAP_LAYOUT
        {
@@ -1244,8 +1232,7 @@ static struct ctl_table vm_table[] = {
                .data           = &sysctl_legacy_va_layout,
                .maxlen         = sizeof(sysctl_legacy_va_layout),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec,
-               .extra1         = &zero,
+               .proc_handler   = proc_dointvec_unsigned,
        },
 #endif
 #ifdef CONFIG_NUMA
@@ -1254,8 +1241,7 @@ static struct ctl_table vm_table[] = {
                .data           = &zone_reclaim_mode,
                .maxlen         = sizeof(zone_reclaim_mode),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec,
-               .extra1         = &zero,
+               .proc_handler   = proc_dointvec_unsigned,
        },
        {
                .procname       = "min_unmapped_ratio",
@@ -1310,8 +1296,7 @@ static struct ctl_table vm_table[] = {
                .data           = &vdso_enabled,
                .maxlen         = sizeof(vdso_enabled),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec,
-               .extra1         = &zero,
+               .proc_handler   = proc_dointvec_unsigned,
        },
 #endif
 #ifdef CONFIG_HIGHMEM
@@ -1320,9 +1305,7 @@ static struct ctl_table vm_table[] = {
                .data           = &vm_highmem_is_dirtyable,
                .maxlen         = sizeof(vm_highmem_is_dirtyable),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .proc_handler   = proc_dointvec_bool,
        },
 #endif
        {
@@ -1338,18 +1321,14 @@ static struct ctl_table vm_table[] = {
                .data           = &sysctl_memory_failure_early_kill,
                .maxlen         = sizeof(sysctl_memory_failure_early_kill),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .proc_handler   = proc_dointvec_bool,
        },
        {
                .procname       = "memory_failure_recovery",
                .data           = &sysctl_memory_failure_recovery,
                .maxlen         = sizeof(sysctl_memory_failure_recovery),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .proc_handler   = proc_dointvec_bool,
        },
 #endif
        { }
@@ -2477,6 +2456,60 @@ int proc_dointvec_minmax(struct ctl_table *table, int write,
                                do_proc_dointvec_minmax_conv, &param);
 }
 
+/**
+ * proc_dointvec_bool - read a vector of integers with 0/1 values
+ * @table: the sysctl table
+ * @write: %TRUE if this is a write to the sysctl file
+ * @buffer: the user buffer
+ * @lenp: the size of the user buffer
+ * @ppos: file position
+ *
+ * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
+ * values from/to the user buffer, treated as an ASCII string.
+ *
+ * This routine will ensure the values are either 0 or 1.
+ *
+ * Returns 0 on success.
+ */
+int proc_dointvec_bool(struct ctl_table *table, int write,
+                 void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       struct do_proc_dointvec_minmax_conv_param param = {
+               .min = &zero,
+               .max = &one,
+       };
+       return do_proc_dointvec(table, write, buffer, lenp, ppos,
+                               do_proc_dointvec_minmax_conv, &param);
+}
+EXPORT_SYMBOL(proc_dointvec_bool);
+
+/**
+ * proc_dointvec_unsigned - read a vector of integers with positive values
+ * @table: the sysctl table
+ * @write: %TRUE if this is a write to the sysctl file
+ * @buffer: the user buffer
+ * @lenp: the size of the user buffer
+ * @ppos: file position
+ *
+ * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
+ * values from/to the user buffer, treated as an ASCII string.
+ *
+ * This routine will ensure the values are positive.
+ *
+ * Returns 0 on success.
+ */
+int proc_dointvec_unsigned(struct ctl_table *table, int write,
+                 void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       struct do_proc_dointvec_minmax_conv_param param = {
+               .min = &zero,
+               .max = (int *) table->extra2,
+       };
+       return do_proc_dointvec(table, write, buffer, lenp, ppos,
+                               do_proc_dointvec_minmax_conv, &param);
+}
+EXPORT_SYMBOL(proc_dointvec_unsigned);
+
 static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int write,
                                     void __user *buffer,
                                     size_t *lenp, loff_t *ppos,
index 58636b7ee5e0245369e07be90c2d423a33124536..73e416db0a1e6b23205cc416864ea2c91b9d26d0 100644 (file)
@@ -575,7 +575,7 @@ EXPORT_SYMBOL(jiffies_to_timeval);
 /*
  * Convert jiffies/jiffies_64 to clock_t and back.
  */
-clock_t jiffies_to_clock_t(long x)
+clock_t jiffies_to_clock_t(unsigned long x)
 {
 #if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0
 # if HZ < USER_HZ
index dbaa62422b13c057754252d986f97440ec7dd3af..42d02c1e877d3aa211a82eff0eb2f755ffebad93 100644 (file)
@@ -480,12 +480,41 @@ static int timer_fixup_free(void *addr, enum debug_obj_state state)
        }
 }
 
+/*
+ * fixup_assert_init is called when:
+ * - an untracked/uninit-ed object is found
+ */
+static int timer_fixup_assert_init(void *addr, enum debug_obj_state state)
+{
+       struct timer_list *timer = addr;
+
+       switch (state) {
+       case ODEBUG_STATE_NOTAVAILABLE:
+               if (timer->entry.prev == TIMER_ENTRY_STATIC) {
+                       /*
+                        * This is not really a fixup. The timer was
+                        * statically initialized. We just make sure that it
+                        * is tracked in the object tracker.
+                        */
+                       debug_object_init(timer, &timer_debug_descr);
+                       return 0;
+               } else {
+                       WARN_ON(1);
+                       init_timer(timer);
+                       return 1;
+               }
+       default:
+               return 0;
+       }
+}
+
 static struct debug_obj_descr timer_debug_descr = {
-       .name           = "timer_list",
-       .debug_hint     = timer_debug_hint,
-       .fixup_init     = timer_fixup_init,
-       .fixup_activate = timer_fixup_activate,
-       .fixup_free     = timer_fixup_free,
+       .name                   = "timer_list",
+       .debug_hint             = timer_debug_hint,
+       .fixup_init             = timer_fixup_init,
+       .fixup_activate         = timer_fixup_activate,
+       .fixup_free             = timer_fixup_free,
+       .fixup_assert_init      = timer_fixup_assert_init,
 };
 
 static inline void debug_timer_init(struct timer_list *timer)
@@ -508,6 +537,11 @@ static inline void debug_timer_free(struct timer_list *timer)
        debug_object_free(timer, &timer_debug_descr);
 }
 
+static inline void debug_timer_assert_init(struct timer_list *timer)
+{
+       debug_object_assert_init(timer, &timer_debug_descr);
+}
+
 static void __init_timer(struct timer_list *timer,
                         const char *name,
                         struct lock_class_key *key);
@@ -531,6 +565,7 @@ EXPORT_SYMBOL_GPL(destroy_timer_on_stack);
 static inline void debug_timer_init(struct timer_list *timer) { }
 static inline void debug_timer_activate(struct timer_list *timer) { }
 static inline void debug_timer_deactivate(struct timer_list *timer) { }
+static inline void debug_timer_assert_init(struct timer_list *timer) { }
 #endif
 
 static inline void debug_init(struct timer_list *timer)
@@ -552,6 +587,11 @@ static inline void debug_deactivate(struct timer_list *timer)
        trace_timer_cancel(timer);
 }
 
+static inline void debug_assert_init(struct timer_list *timer)
+{
+       debug_timer_assert_init(timer);
+}
+
 static void __init_timer(struct timer_list *timer,
                         const char *name,
                         struct lock_class_key *key)
@@ -902,6 +942,8 @@ int del_timer(struct timer_list *timer)
        unsigned long flags;
        int ret = 0;
 
+       debug_assert_init(timer);
+
        timer_stats_timer_clear_start_info(timer);
        if (timer_pending(timer)) {
                base = lock_timer_base(timer, &flags);
@@ -932,6 +974,8 @@ int try_to_del_timer_sync(struct timer_list *timer)
        unsigned long flags;
        int ret = -1;
 
+       debug_assert_init(timer);
+
        base = lock_timer_base(timer, &flags);
 
        if (base->running_timer == timer)
index c0cb9c4bc46d661ef5f37fda9ac8faa199a1ca23..5e4fd9a0ebb1251172543717a344e401a4c47464 100644 (file)
@@ -1109,6 +1109,24 @@ config SYSCTL_SYSCALL_CHECK
          to properly maintain and use. This enables checks that help
          you to keep things correct.
 
+config ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS
+       bool
+
+config DEBUG_STRICT_USER_COPY_CHECKS
+       bool "Strict user copy size checks"
+       depends on ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS
+       depends on DEBUG_KERNEL && !TRACE_BRANCH_PROFILING
+       help
+         Enabling this option turns a certain set of sanity checks for user
+         copy operations into compile time failures.
+
+         The copy_from_user() etc checks are there to help test if there
+         are sufficient security checks on the length argument of
+         the copy operation, by having gcc prove that the argument is
+         within bounds.
+
+         If unsure, say N.
+
 source mm/Kconfig.debug
 source kernel/trace/Kconfig
 
index d5d175c8a6ca3242b91e9d804e2b3f35209caea8..15f7bb62da982b07ac371064548f60878f2f7fa6 100644 (file)
@@ -14,6 +14,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \
         proportions.o prio_heap.o ratelimit.o show_mem.o \
         is_single_threaded.o plist.o decompress.o find_next_bit.o
 
+obj-$(CONFIG_ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS) += usercopy.o
 lib-$(CONFIG_MMU) += ioremap.o
 lib-$(CONFIG_SMP) += cpumask.o
 
index a6e633a48cea887fbba14b7c1cbab84bd485c67b..07005ba65c4bd30ef7c3d07fe41147d1cd928ddf 100644 (file)
@@ -1,4 +1,8 @@
 /*
+ * July 20, 2011 Bob Pearson <rpearson at systemfabricworks.com>
+ * added slice by 8 algorithm to the existing conventional and
+ * slice by 4 algorithms.
+ *
  * Oct 15, 2000 Matt Domsch <Matt_Domsch@dell.com>
  * Nicer crc32 functions/docs submitted by linux@horizon.com.  Thanks!
  * Code was from the public domain, copyright abandoned.  Code was
@@ -19,7 +23,6 @@
  * This source code is licensed under the GNU General Public License,
  * Version 2.  See the file COPYING for more details.
  */
-
 #include <linux/crc32.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/atomic.h>
 #include "crc32defs.h"
-#if CRC_LE_BITS == 8
-# define tole(x) __constant_cpu_to_le32(x)
+
+#if CRC_LE_BITS > 8
+# define tole(x) (__force u32) __constant_cpu_to_le32(x)
 #else
 # define tole(x) (x)
 #endif
 
-#if CRC_BE_BITS == 8
-# define tobe(x) __constant_cpu_to_be32(x)
+#if CRC_BE_BITS > 8
+# define tobe(x) (__force u32) __constant_cpu_to_be32(x)
 #else
 # define tobe(x) (x)
 #endif
@@ -45,54 +49,228 @@ MODULE_AUTHOR("Matt Domsch <Matt_Domsch@dell.com>");
 MODULE_DESCRIPTION("Ethernet CRC32 calculations");
 MODULE_LICENSE("GPL");
 
-#if CRC_LE_BITS == 8 || CRC_BE_BITS == 8
+#if CRC_LE_BITS > 8
+static inline u32 crc32_le_body(u32 crc, u8 const *buf, size_t len)
+{
+       const u8 *p8;
+       const u32 *p32;
+       int init_bytes, end_bytes;
+       size_t words;
+       int i;
+       u32 q;
+       u8 i0, i1, i2, i3;
+
+       crc = (__force u32) __cpu_to_le32(crc);
+
+#if CRC_LE_BITS == 64
+       p8 = buf;
+       p32 = (u32 *)(((uintptr_t)p8 + 7) & ~7);
+
+       init_bytes = (uintptr_t)p32 - (uintptr_t)p8;
+       if (init_bytes > len)
+               init_bytes = len;
+       words = (len - init_bytes) >> 3;
+       end_bytes = (len - init_bytes) & 7;
+#else
+       p8 = buf;
+       p32 = (u32 *)(((uintptr_t)p8 + 3) & ~3);
+
+       init_bytes = (uintptr_t)p32 - (uintptr_t)p8;
+       if (init_bytes > len)
+               init_bytes = len;
+       words = (len - init_bytes) >> 2;
+       end_bytes = (len - init_bytes) & 3;
+#endif
+
+       for (i = 0; i < init_bytes; i++) {
+#ifdef __LITTLE_ENDIAN
+               i0 = *p8++ ^ crc;
+               crc = t0_le[i0] ^ (crc >> 8);
+#else
+               i0 = *p8++ ^ (crc >> 24);
+               crc = t0_le[i0] ^ (crc << 8);
+#endif
+       }
+
+       for (i = 0; i < words; i++) {
+#ifdef __LITTLE_ENDIAN
+#  if CRC_LE_BITS == 64
+               /* slice by 8 algorithm */
+               q = *p32++ ^ crc;
+               i3 = q;
+               i2 = q >> 8;
+               i1 = q >> 16;
+               i0 = q >> 24;
+               crc = t7_le[i3] ^ t6_le[i2] ^ t5_le[i1] ^ t4_le[i0];
+
+               q = *p32++;
+               i3 = q;
+               i2 = q >> 8;
+               i1 = q >> 16;
+               i0 = q >> 24;
+               crc ^= t3_le[i3] ^ t2_le[i2] ^ t1_le[i1] ^ t0_le[i0];
+#  else
+               /* slice by 4 algorithm */
+               q = *p32++ ^ crc;
+               i3 = q;
+               i2 = q >> 8;
+               i1 = q >> 16;
+               i0 = q >> 24;
+               crc = t3_le[i3] ^ t2_le[i2] ^ t1_le[i1] ^ t0_le[i0];
+#  endif
+#else
+#  if CRC_LE_BITS == 64
+               q = *p32++ ^ crc;
+               i3 = q >> 24;
+               i2 = q >> 16;
+               i1 = q >> 8;
+               i0 = q;
+               crc = t7_le[i3] ^ t6_le[i2] ^ t5_le[i1] ^ t4_le[i0];
+
+               q = *p32++;
+               i3 = q >> 24;
+               i2 = q >> 16;
+               i1 = q >> 8;
+               i0 = q;
+               crc ^= t3_le[i3] ^ t2_le[i2] ^ t1_le[i1] ^ t0_le[i0];
+#  else
+               q = *p32++ ^ crc;
+               i3 = q >> 24;
+               i2 = q >> 16;
+               i1 = q >> 8;
+               i0 = q;
+               crc = t3_le[i3] ^ t2_le[i2] ^ t1_le[i1] ^ t0_le[i0];
+#  endif
+#endif
+       }
+
+       p8 = (u8 *)p32;
+
+       for (i = 0; i < end_bytes; i++) {
+#ifdef __LITTLE_ENDIAN
+               i0 = *p8++ ^ crc;
+               crc = t0_le[i0] ^ (crc >> 8);
+#else
+               i0 = *p8++ ^ (crc >> 24);
+               crc = t0_le[i0] ^ (crc << 8);
+#endif
+       }
 
-static inline u32
-crc32_body(u32 crc, unsigned char const *buf, size_t len, const u32 (*tab)[256])
+       return __le32_to_cpu((__force __le32)crc);
+}
+#endif
+
+#if CRC_BE_BITS > 8
+static inline u32 crc32_be_body(u32 crc, u8 const *buf, size_t len)
 {
-# ifdef __LITTLE_ENDIAN
-#  define DO_CRC(x) crc = tab[0][(crc ^ (x)) & 255] ^ (crc >> 8)
-#  define DO_CRC4 crc = tab[3][(crc) & 255] ^ \
-               tab[2][(crc >> 8) & 255] ^ \
-               tab[1][(crc >> 16) & 255] ^ \
-               tab[0][(crc >> 24) & 255]
-# else
-#  define DO_CRC(x) crc = tab[0][((crc >> 24) ^ (x)) & 255] ^ (crc << 8)
-#  define DO_CRC4 crc = tab[0][(crc) & 255] ^ \
-               tab[1][(crc >> 8) & 255] ^ \
-               tab[2][(crc >> 16) & 255] ^ \
-               tab[3][(crc >> 24) & 255]
-# endif
-       const u32 *b;
-       size_t    rem_len;
-
-       /* Align it */
-       if (unlikely((long)buf & 3 && len)) {
-               do {
-                       DO_CRC(*buf++);
-               } while ((--len) && ((long)buf)&3);
+       const u8 *p8;
+       const u32 *p32;
+       int init_bytes, end_bytes;
+       size_t words;
+       int i;
+       u32 q;
+       u8 i0, i1, i2, i3;
+
+       crc = (__force u32) __cpu_to_be32(crc);
+
+#if CRC_LE_BITS == 64
+       p8 = buf;
+       p32 = (u32 *)(((uintptr_t)p8 + 7) & ~7);
+
+       init_bytes = (uintptr_t)p32 - (uintptr_t)p8;
+       if (init_bytes > len)
+               init_bytes = len;
+       words = (len - init_bytes) >> 3;
+       end_bytes = (len - init_bytes) & 7;
+#else
+       p8 = buf;
+       p32 = (u32 *)(((uintptr_t)p8 + 3) & ~3);
+
+       init_bytes = (uintptr_t)p32 - (uintptr_t)p8;
+       if (init_bytes > len)
+               init_bytes = len;
+       words = (len - init_bytes) >> 2;
+       end_bytes = (len - init_bytes) & 3;
+#endif
+
+       for (i = 0; i < init_bytes; i++) {
+#ifdef __LITTLE_ENDIAN
+               i0 = *p8++ ^ crc;
+               crc = t0_be[i0] ^ (crc >> 8);
+#else
+               i0 = *p8++ ^ (crc >> 24);
+               crc = t0_be[i0] ^ (crc << 8);
+#endif
        }
-       rem_len = len & 3;
-       /* load data 32 bits wide, xor data 32 bits wide. */
-       len = len >> 2;
-       b = (const u32 *)buf;
-       for (--b; len; --len) {
-               crc ^= *++b; /* use pre increment for speed */
-               DO_CRC4;
+
+       for (i = 0; i < words; i++) {
+#ifdef __LITTLE_ENDIAN
+#  if CRC_LE_BITS == 64
+               /* slice by 8 algorithm */
+               q = *p32++ ^ crc;
+               i3 = q;
+               i2 = q >> 8;
+               i1 = q >> 16;
+               i0 = q >> 24;
+               crc = t7_be[i3] ^ t6_be[i2] ^ t5_be[i1] ^ t4_be[i0];
+
+               q = *p32++;
+               i3 = q;
+               i2 = q >> 8;
+               i1 = q >> 16;
+               i0 = q >> 24;
+               crc ^= t3_be[i3] ^ t2_be[i2] ^ t1_be[i1] ^ t0_be[i0];
+#  else
+               /* slice by 4 algorithm */
+               q = *p32++ ^ crc;
+               i3 = q;
+               i2 = q >> 8;
+               i1 = q >> 16;
+               i0 = q >> 24;
+               crc = t3_be[i3] ^ t2_be[i2] ^ t1_be[i1] ^ t0_be[i0];
+#  endif
+#else
+#  if CRC_LE_BITS == 64
+               q = *p32++ ^ crc;
+               i3 = q >> 24;
+               i2 = q >> 16;
+               i1 = q >> 8;
+               i0 = q;
+               crc = t7_be[i3] ^ t6_be[i2] ^ t5_be[i1] ^ t4_be[i0];
+
+               q = *p32++;
+               i3 = q >> 24;
+               i2 = q >> 16;
+               i1 = q >> 8;
+               i0 = q;
+               crc ^= t3_be[i3] ^ t2_be[i2] ^ t1_be[i1] ^ t0_be[i0];
+#  else
+               q = *p32++ ^ crc;
+               i3 = q >> 24;
+               i2 = q >> 16;
+               i1 = q >> 8;
+               i0 = q;
+               crc = t3_be[i3] ^ t2_be[i2] ^ t1_be[i1] ^ t0_be[i0];
+#  endif
+#endif
        }
-       len = rem_len;
-       /* And the last few bytes */
-       if (len) {
-               u8 *p = (u8 *)(b + 1) - 1;
-               do {
-                       DO_CRC(*++p); /* use pre increment for speed */
-               } while (--len);
+
+       p8 = (u8 *)p32;
+
+       for (i = 0; i < end_bytes; i++) {
+#ifdef __LITTLE_ENDIAN
+               i0 = *p8++ ^ crc;
+               crc = t0_be[i0] ^ (crc >> 8);
+#else
+               i0 = *p8++ ^ (crc >> 24);
+               crc = t0_be[i0] ^ (crc << 8);
+#endif
        }
-       return crc;
-#undef DO_CRC
-#undef DO_CRC4
+
+       return __be32_to_cpu((__force __be32)crc);
 }
 #endif
+
 /**
  * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32
  * @crc: seed value for computation.  ~0 for Ethernet, sometimes 0 for
@@ -100,53 +278,40 @@ crc32_body(u32 crc, unsigned char const *buf, size_t len, const u32 (*tab)[256])
  * @p: pointer to buffer over which CRC is run
  * @len: length of buffer @p
  */
-u32 __pure crc32_le(u32 crc, unsigned char const *p, size_t len);
-
-#if CRC_LE_BITS == 1
-/*
- * In fact, the table-based code will work in this case, but it can be
- * simplified by inlining the table in ?: form.
- */
-
 u32 __pure crc32_le(u32 crc, unsigned char const *p, size_t len)
 {
+#if CRC_LE_BITS == 1
        int i;
        while (len--) {
                crc ^= *p++;
                for (i = 0; i < 8; i++)
                        crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
        }
-       return crc;
-}
-#else                          /* Table-based approach */
-
-u32 __pure crc32_le(u32 crc, unsigned char const *p, size_t len)
-{
-# if CRC_LE_BITS == 8
-       const u32      (*tab)[] = crc32table_le;
-
-       crc = __cpu_to_le32(crc);
-       crc = crc32_body(crc, p, len, tab);
-       return __le32_to_cpu(crc);
+# elif CRC_LE_BITS == 2
+       while (len--) {
+               crc ^= *p++;
+               crc = (crc >> 2) ^ t0_le[crc & 0x03];
+               crc = (crc >> 2) ^ t0_le[crc & 0x03];
+               crc = (crc >> 2) ^ t0_le[crc & 0x03];
+               crc = (crc >> 2) ^ t0_le[crc & 0x03];
+       }
 # elif CRC_LE_BITS == 4
        while (len--) {
                crc ^= *p++;
-               crc = (crc >> 4) ^ crc32table_le[crc & 15];
-               crc = (crc >> 4) ^ crc32table_le[crc & 15];
+               crc = (crc >> 4) ^ t0_le[crc & 0x0f];
+               crc = (crc >> 4) ^ t0_le[crc & 0x0f];
        }
-       return crc;
-# elif CRC_LE_BITS == 2
+# elif CRC_LE_BITS == 8
        while (len--) {
                crc ^= *p++;
-               crc = (crc >> 2) ^ crc32table_le[crc & 3];
-               crc = (crc >> 2) ^ crc32table_le[crc & 3];
-               crc = (crc >> 2) ^ crc32table_le[crc & 3];
-               crc = (crc >> 2) ^ crc32table_le[crc & 3];
+               crc = (crc >> 8) ^ t0_le[crc & 0xff];
        }
-       return crc;
+# else
+       crc = crc32_le_body(crc, p, len);
 # endif
+       return crc;
 }
-#endif
+EXPORT_SYMBOL(crc32_le);
 
 /**
  * crc32_be() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32
@@ -155,57 +320,40 @@ u32 __pure crc32_le(u32 crc, unsigned char const *p, size_t len)
  * @p: pointer to buffer over which CRC is run
  * @len: length of buffer @p
  */
-u32 __pure crc32_be(u32 crc, unsigned char const *p, size_t len);
-
-#if CRC_BE_BITS == 1
-/*
- * In fact, the table-based code will work in this case, but it can be
- * simplified by inlining the table in ?: form.
- */
-
 u32 __pure crc32_be(u32 crc, unsigned char const *p, size_t len)
 {
+#if CRC_BE_BITS == 1
        int i;
        while (len--) {
                crc ^= *p++ << 24;
                for (i = 0; i < 8; i++)
-                       crc =
-                           (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE :
-                                         0);
+                       crc = (crc << 1) ^
+                             ((crc & 0x80000000) ? CRCPOLY_BE : 0);
+       }
+# elif CRC_BE_BITS == 2
+       while (len--) {
+               crc ^= *p++ << 24;
+               crc = (crc << 2) ^ t0_be[crc >> 30];
+               crc = (crc << 2) ^ t0_be[crc >> 30];
+               crc = (crc << 2) ^ t0_be[crc >> 30];
+               crc = (crc << 2) ^ t0_be[crc >> 30];
        }
-       return crc;
-}
-
-#else                          /* Table-based approach */
-u32 __pure crc32_be(u32 crc, unsigned char const *p, size_t len)
-{
-# if CRC_BE_BITS == 8
-       const u32      (*tab)[] = crc32table_be;
-
-       crc = __cpu_to_be32(crc);
-       crc = crc32_body(crc, p, len, tab);
-       return __be32_to_cpu(crc);
 # elif CRC_BE_BITS == 4
        while (len--) {
                crc ^= *p++ << 24;
-               crc = (crc << 4) ^ crc32table_be[crc >> 28];
-               crc = (crc << 4) ^ crc32table_be[crc >> 28];
+               crc = (crc << 4) ^ t0_be[crc >> 28];
+               crc = (crc << 4) ^ t0_be[crc >> 28];
        }
-       return crc;
-# elif CRC_BE_BITS == 2
+# elif CRC_BE_BITS == 8
        while (len--) {
                crc ^= *p++ << 24;
-               crc = (crc << 2) ^ crc32table_be[crc >> 30];
-               crc = (crc << 2) ^ crc32table_be[crc >> 30];
-               crc = (crc << 2) ^ crc32table_be[crc >> 30];
-               crc = (crc << 2) ^ crc32table_be[crc >> 30];
+               crc = (crc << 8) ^ t0_be[crc >> 24];
        }
-       return crc;
+# else
+       crc = crc32_be_body(crc, p, len);
 # endif
+       return crc;
 }
-#endif
-
-EXPORT_SYMBOL(crc32_le);
 EXPORT_SYMBOL(crc32_be);
 
 /*
index 9b6773d737495566846c66ab36c62b468ff88ab5..fe3fccdbd65dae41b62f88c6b153d618119c7df1 100644 (file)
@@ -6,27 +6,29 @@
 #define CRCPOLY_LE 0xedb88320
 #define CRCPOLY_BE 0x04c11db7
 
-/* How many bits at a time to use.  Requires a table of 4<<CRC_xx_BITS bytes. */
+/* How many bits at a time to use.  Valid values are 1, 2, 4, 8, 32 and 64. */
 /* For less performance-sensitive, use 4 */
 #ifndef CRC_LE_BITS 
-# define CRC_LE_BITS 8
+# define CRC_LE_BITS 64
 #endif
 #ifndef CRC_BE_BITS
-# define CRC_BE_BITS 8
+# define CRC_BE_BITS 64
 #endif
 
 /*
  * Little-endian CRC computation.  Used with serial bit streams sent
  * lsbit-first.  Be sure to use cpu_to_le32() to append the computed CRC.
  */
-#if CRC_LE_BITS > 8 || CRC_LE_BITS < 1 || CRC_LE_BITS & CRC_LE_BITS-1
-# error CRC_LE_BITS must be a power of 2 between 1 and 8
+#if CRC_LE_BITS > 64 || CRC_LE_BITS < 1 || CRC_LE_BITS == 16 || \
+       CRC_LE_BITS & CRC_LE_BITS-1
+# error "CRC_LE_BITS must be one of {1, 2, 4, 8, 32, 64}"
 #endif
 
 /*
  * Big-endian CRC computation.  Used with serial bit streams sent
  * msbit-first.  Be sure to use cpu_to_be32() to append the computed CRC.
  */
-#if CRC_BE_BITS > 8 || CRC_BE_BITS < 1 || CRC_BE_BITS & CRC_BE_BITS-1
-# error CRC_BE_BITS must be a power of 2 between 1 and 8
+#if CRC_BE_BITS > 64 || CRC_BE_BITS < 1 || CRC_BE_BITS == 16 || \
+       CRC_BE_BITS & CRC_BE_BITS-1
+# error "CRC_BE_BITS must be one of {1, 2, 4, 8, 32, 64}"
 #endif
index a78b7c6e042c9f64fb76bcb252236c456bf8a6a0..b07b5b82f39654921cd365837557aa721b3fd57e 100644 (file)
@@ -562,6 +562,39 @@ out_unlock:
        raw_spin_unlock_irqrestore(&db->lock, flags);
 }
 
+/**
+ * debug_object_assert_init - debug checks when object should be init-ed
+ * @addr:      address of the object
+ * @descr:     pointer to an object specific debug description structure
+ */
+void debug_object_assert_init(void *addr, struct debug_obj_descr *descr)
+{
+       struct debug_bucket *db;
+       struct debug_obj *obj;
+       unsigned long flags;
+
+       if (!debug_objects_enabled)
+               return;
+
+       db = get_bucket((unsigned long) addr);
+
+       raw_spin_lock_irqsave(&db->lock, flags);
+
+       obj = lookup_object(addr, db);
+       if (!obj) {
+               raw_spin_unlock_irqrestore(&db->lock, flags);
+               /*
+                * Maybe the object is static.  Let the type specific
+                * code decide what to do.
+                */
+               debug_object_fixup(descr->fixup_assert_init, addr,
+                                  ODEBUG_STATE_NOTAVAILABLE);
+               return;
+       }
+
+       raw_spin_unlock_irqrestore(&db->lock, flags);
+}
+
 /**
  * debug_object_active_state - debug checks object usage state machine
  * @addr:      address of the object
index 85d0e412a04f966a187fac0a5f8c7ff16c9a49c8..e1303d7c6b51d6e525ac403a4afad378c7887f69 100644 (file)
@@ -4,11 +4,20 @@
 
 #define ENTRIES_PER_LINE 4
 
+#if CRC_LE_BITS <= 8
 #define LE_TABLE_SIZE (1 << CRC_LE_BITS)
+#else
+#define LE_TABLE_SIZE 256
+#endif
+
+#if CRC_BE_BITS <= 8
 #define BE_TABLE_SIZE (1 << CRC_BE_BITS)
+#else
+#define BE_TABLE_SIZE 256
+#endif
 
-static uint32_t crc32table_le[4][LE_TABLE_SIZE];
-static uint32_t crc32table_be[4][BE_TABLE_SIZE];
+static uint32_t crc32table_le[8][256];
+static uint32_t crc32table_be[8][256];
 
 /**
  * crc32init_le() - allocate and initialize LE table data
@@ -24,14 +33,14 @@ static void crc32init_le(void)
 
        crc32table_le[0][0] = 0;
 
-       for (i = 1 << (CRC_LE_BITS - 1); i; i >>= 1) {
+       for (i = LE_TABLE_SIZE >> 1; i; i >>= 1) {
                crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
                for (j = 0; j < LE_TABLE_SIZE; j += 2 * i)
                        crc32table_le[0][i + j] = crc ^ crc32table_le[0][j];
        }
        for (i = 0; i < LE_TABLE_SIZE; i++) {
                crc = crc32table_le[0][i];
-               for (j = 1; j < 4; j++) {
+               for (j = 1; j < 8; j++) {
                        crc = crc32table_le[0][crc & 0xff] ^ (crc >> 8);
                        crc32table_le[j][i] = crc;
                }
@@ -55,44 +64,58 @@ static void crc32init_be(void)
        }
        for (i = 0; i < BE_TABLE_SIZE; i++) {
                crc = crc32table_be[0][i];
-               for (j = 1; j < 4; j++) {
+               for (j = 1; j < 8; j++) {
                        crc = crc32table_be[0][(crc >> 24) & 0xff] ^ (crc << 8);
                        crc32table_be[j][i] = crc;
                }
        }
 }
 
-static void output_table(uint32_t table[4][256], int len, char *trans)
+static void output_table(uint32_t table[8][256], int len, char trans)
 {
        int i, j;
 
-       for (j = 0 ; j < 4; j++) {
-               printf("{");
+       for (j = 0 ; j < 8; j++) {
+               printf("static const u32 t%d_%ce[] = {", j, trans);
                for (i = 0; i < len - 1; i++) {
-                       if (i % ENTRIES_PER_LINE == 0)
+                       if ((i % ENTRIES_PER_LINE) == 0)
                                printf("\n");
-                       printf("%s(0x%8.8xL), ", trans, table[j][i]);
+                       printf("to%ce(0x%8.8xL),", trans, table[j][i]);
+                       if ((i % ENTRIES_PER_LINE) != (ENTRIES_PER_LINE - 1))
+                               printf(" ");
+               }
+               printf("to%ce(0x%8.8xL)};\n\n", trans, table[j][len - 1]);
+
+               if (trans == 'l') {
+                       if ((j+1)*8 >= CRC_LE_BITS)
+                               break;
+               } else {
+                       if ((j+1)*8 >= CRC_BE_BITS)
+                               break;
                }
-               printf("%s(0x%8.8xL)},\n", trans, table[j][len - 1]);
        }
 }
 
 int main(int argc, char** argv)
 {
-       printf("/* this file is generated - do not edit */\n\n");
+       printf("/*\n");
+       printf(" * crc32table.h - CRC32 tables\n");
+       printf(" *    this file is generated - do not edit\n");
+       printf(" *      # gen_crc32table > crc32table.h\n");
+       printf(" *    with\n");
+       printf(" *      CRC_LE_BITS = %d\n", CRC_LE_BITS);
+       printf(" *      CRC_BE_BITS = %d\n", CRC_BE_BITS);
+       printf(" */\n");
+       printf("\n");
 
        if (CRC_LE_BITS > 1) {
                crc32init_le();
-               printf("static const u32 crc32table_le[4][256] = {");
-               output_table(crc32table_le, LE_TABLE_SIZE, "tole");
-               printf("};\n");
+               output_table(crc32table_le, LE_TABLE_SIZE, 'l');
        }
 
        if (CRC_BE_BITS > 1) {
                crc32init_be();
-               printf("static const u32 crc32table_be[4][256] = {");
-               output_table(crc32table_be, BE_TABLE_SIZE, "tobe");
-               printf("};\n");
+               output_table(crc32table_be, BE_TABLE_SIZE, 'b');
        }
 
        return 0;
index a2f9da59c1970cfab2a55c94f43da8843551ef05..d9df7454519cd546c71aa10adf14204bee86ef7f 100644 (file)
@@ -576,7 +576,6 @@ int radix_tree_tag_get(struct radix_tree_root *root,
 {
        unsigned int height, shift;
        struct radix_tree_node *node;
-       int saw_unset_tag = 0;
 
        /* check the root's tag bit */
        if (!root_tag_get(root, tag))
@@ -603,15 +602,10 @@ int radix_tree_tag_get(struct radix_tree_root *root,
                        return 0;
 
                offset = (index >> shift) & RADIX_TREE_MAP_MASK;
-
-               /*
-                * This is just a debug check.  Later, we can bale as soon as
-                * we see an unset tag.
-                */
                if (!tag_get(node, tag, offset))
-                       saw_unset_tag = 1;
+                       return 0;
                if (height == 1)
-                       return !!tag_get(node, tag, offset);
+                       return 1;
                node = rcu_dereference_raw(node->slots[offset]);
                shift -= RADIX_TREE_MAP_SHIFT;
                height--;
similarity index 100%
rename from arch/s390/lib/usercopy.c
rename to lib/usercopy.c
index 72c9e4fdde00d688648d54b153c614aed2f36f25..306742a28266e24469c89164be415e3d9fc52f4f 100644 (file)
@@ -5,7 +5,8 @@
 mmu-y                  := nommu.o
 mmu-$(CONFIG_MMU)      := fremap.o highmem.o madvise.o memory.o mincore.o \
                           mlock.o mmap.o mprotect.o mremap.o msync.o rmap.o \
-                          vmalloc.o pagewalk.o pgtable-generic.o
+                          vmalloc.o pagewalk.o pgtable-generic.o \
+                          process_vm_access.o
 
 obj-y                  := filemap.o mempool.o oom_kill.o fadvise.o \
                           maccess.o page_alloc.o page-writeback.o \
index 6cc604bd56496e2742e371d63234af08f9f0859b..a0e420207ebff3778fc5c17136dc2d5176391105 100644 (file)
@@ -35,10 +35,6 @@ struct compact_control {
        unsigned long migrate_pfn;      /* isolate_migratepages search base */
        bool sync;                      /* Synchronous migration */
 
-       /* Account for isolated anon and file pages */
-       unsigned long nr_anon;
-       unsigned long nr_file;
-
        unsigned int order;             /* order a direct compactor needs */
        int migratetype;                /* MOVABLE, RECLAIMABLE etc */
        struct zone *zone;
@@ -223,17 +219,13 @@ static void isolate_freepages(struct zone *zone,
 static void acct_isolated(struct zone *zone, struct compact_control *cc)
 {
        struct page *page;
-       unsigned int count[NR_LRU_LISTS] = { 0, };
+       unsigned int count[2] = { 0, };
 
-       list_for_each_entry(page, &cc->migratepages, lru) {
-               int lru = page_lru_base_type(page);
-               count[lru]++;
-       }
+       list_for_each_entry(page, &cc->migratepages, lru)
+               count[!!page_is_file_cache(page)]++;
 
-       cc->nr_anon = count[LRU_ACTIVE_ANON] + count[LRU_INACTIVE_ANON];
-       cc->nr_file = count[LRU_ACTIVE_FILE] + count[LRU_INACTIVE_FILE];
-       __mod_zone_page_state(zone, NR_ISOLATED_ANON, cc->nr_anon);
-       __mod_zone_page_state(zone, NR_ISOLATED_FILE, cc->nr_file);
+       __mod_zone_page_state(zone, NR_ISOLATED_ANON, count[0]);
+       __mod_zone_page_state(zone, NR_ISOLATED_FILE, count[1]);
 }
 
 /* Similar to reclaim, but different enough that they don't share logic */
@@ -269,6 +261,7 @@ static isolate_migrate_t isolate_migratepages(struct zone *zone,
        unsigned long last_pageblock_nr = 0, pageblock_nr;
        unsigned long nr_scanned = 0, nr_isolated = 0;
        struct list_head *migratelist = &cc->migratepages;
+       isolate_mode_t mode = ISOLATE_ACTIVE|ISOLATE_INACTIVE;
 
        /* Do not scan outside zone boundaries */
        low_pfn = max(cc->migrate_pfn, zone->zone_start_pfn);
@@ -356,8 +349,11 @@ static isolate_migrate_t isolate_migratepages(struct zone *zone,
                        continue;
                }
 
+               if (!cc->sync)
+                       mode |= ISOLATE_CLEAN;
+
                /* Try isolate the page */
-               if (__isolate_lru_page(page, ISOLATE_BOTH, 0) != 0)
+               if (__isolate_lru_page(page, mode, 0) != 0)
                        continue;
 
                VM_BUG_ON(PageTransCompound(page));
index 2fcfbdc45e3081a425944450f2d3115ca3118283..c6faa329b88b07a7d8b9256ed813eb4928c99931 100644 (file)
@@ -1231,7 +1231,8 @@ mem_cgroup_get_reclaim_stat_from_page(struct page *page)
 unsigned long mem_cgroup_isolate_pages(unsigned long nr_to_scan,
                                        struct list_head *dst,
                                        unsigned long *scanned, int order,
-                                       int mode, struct zone *z,
+                                       isolate_mode_t mode,
+                                       struct zone *z,
                                        struct mem_cgroup *mem_cont,
                                        int active, int file)
 {
@@ -4910,7 +4911,6 @@ static int alloc_mem_cgroup_per_zone_info(struct mem_cgroup *mem, int node)
        if (!pn)
                return 1;
 
-       mem->info.nodeinfo[node] = pn;
        for (zone = 0; zone < MAX_NR_ZONES; zone++) {
                mz = &pn->zoneinfo[zone];
                for_each_lru(l)
@@ -4919,6 +4919,7 @@ static int alloc_mem_cgroup_per_zone_info(struct mem_cgroup *mem, int node)
                mz->on_tree = false;
                mz->mem = mem;
        }
+       mem->info.nodeinfo[node] = pn;
        return 0;
 }
 
index 8b57173c1dd5b09a8bb0b3e24fedb8c8584ce447..905f2027b2a19f1eae63cc68f885934de574e65e 100644 (file)
@@ -1412,7 +1412,9 @@ asmlinkage long compat_sys_get_mempolicy(int __user *policy,
        err = sys_get_mempolicy(policy, nm, nr_bits+1, addr, flags);
 
        if (!err && nmask) {
-               err = copy_from_user(bm, nm, alloc_size);
+               unsigned long copy_size;
+               copy_size = min_t(unsigned long, sizeof(bm), alloc_size);
+               err = copy_from_user(bm, nm, copy_size);
                /* ensure entire bitmap is zeroed */
                err |= clear_user(nmask, ALIGN(maxnode-1, 8) / 8);
                err |= compat_put_bitmap(nmask, bm, nr_bits);
index 666e4e677414e6d790de715761e395116441e6c4..71713fc499628afe896389e32d7fc4fedd29d1ca 100644 (file)
@@ -621,38 +621,18 @@ static int move_to_new_page(struct page *newpage, struct page *page,
        return rc;
 }
 
-/*
- * Obtain the lock on page, remove all ptes and migrate the page
- * to the newly allocated page in newpage.
- */
-static int unmap_and_move(new_page_t get_new_page, unsigned long private,
-                       struct page *page, int force, bool offlining, bool sync)
+static int __unmap_and_move(struct page *page, struct page *newpage,
+                               int force, bool offlining, bool sync)
 {
-       int rc = 0;
-       int *result = NULL;
-       struct page *newpage = get_new_page(page, private, &result);
+       int rc = -EAGAIN;
        int remap_swapcache = 1;
        int charge = 0;
        struct mem_cgroup *mem;
        struct anon_vma *anon_vma = NULL;
 
-       if (!newpage)
-               return -ENOMEM;
-
-       if (page_count(page) == 1) {
-               /* page was freed from under us. So we are done. */
-               goto move_newpage;
-       }
-       if (unlikely(PageTransHuge(page)))
-               if (unlikely(split_huge_page(page)))
-                       goto move_newpage;
-
-       /* prepare cgroup just returns 0 or -ENOMEM */
-       rc = -EAGAIN;
-
        if (!trylock_page(page)) {
                if (!force || !sync)
-                       goto move_newpage;
+                       goto out;
 
                /*
                 * It's not safe for direct compaction to call lock_page.
@@ -668,7 +648,7 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
                 * altogether.
                 */
                if (current->flags & PF_MEMALLOC)
-                       goto move_newpage;
+                       goto out;
 
                lock_page(page);
        }
@@ -785,27 +765,52 @@ uncharge:
                mem_cgroup_end_migration(mem, page, newpage, rc == 0);
 unlock:
        unlock_page(page);
+out:
+       return rc;
+}
 
-move_newpage:
+/*
+ * Obtain the lock on page, remove all ptes and migrate the page
+ * to the newly allocated page in newpage.
+ */
+static int unmap_and_move(new_page_t get_new_page, unsigned long private,
+                       struct page *page, int force, bool offlining, bool sync)
+{
+       int rc = 0;
+       int *result = NULL;
+       struct page *newpage = get_new_page(page, private, &result);
+
+       if (!newpage)
+               return -ENOMEM;
+
+       if (page_count(page) == 1) {
+               /* page was freed from under us. So we are done. */
+               goto out;
+       }
+
+       if (unlikely(PageTransHuge(page)))
+               if (unlikely(split_huge_page(page)))
+                       goto out;
+
+       rc = __unmap_and_move(page, newpage, force, offlining, sync);
+out:
        if (rc != -EAGAIN) {
-               /*
-                * A page that has been migrated has all references
-                * removed and will be freed. A page that has not been
-                * migrated will have kepts its references and be
-                * restored.
-                */
-               list_del(&page->lru);
+               /*
+                * A page that has been migrated has all references
+                * removed and will be freed. A page that has not been
+                * migrated will have kepts its references and be
+                * restored.
+                */
+               list_del(&page->lru);
                dec_zone_page_state(page, NR_ISOLATED_ANON +
                                page_is_file_cache(page));
                putback_lru_page(page);
        }
-
        /*
         * Move the new page to the LRU. If migration was not successful
         * then this will free the page.
         */
        putback_lru_page(newpage);
-
        if (result) {
                if (rc)
                        *result = rc;
index 636a86876ff217a7f6d18f29c18524c2f2645a63..55556b05ef68b6a9f8727e2750c3a2f6a1a92db4 100644 (file)
@@ -79,6 +79,12 @@ static unsigned char mincore_page(struct address_space *mapping, pgoff_t pgoff)
        }
 #endif
        if (page) {
+#ifdef CONFIG_SWAP
+               if (radix_tree_exceptional_entry(page)) {
+                       swp_entry_t swap = radix_to_swp_entry(page);
+                       page = find_get_page(&swapper_space, swap.val);
+               }
+#endif
                present = PageUptodate(page);
                page_cache_release(page);
        }
index 626303b52f3ce0764d3bb1029f6bce8b5bcaa896..64bccffb848e8c5a5cdc8c8180de858269e9746b 100644 (file)
@@ -435,7 +435,7 @@ static int oom_kill_task(struct task_struct *p, struct mem_cgroup *mem)
        task_unlock(p);
 
        /*
-        * Kill all processes sharing p->mm in other thread groups, if any.
+        * Kill all user processes sharing p->mm in other thread groups, if any.
         * They don't get access to memory reserves or a higher scheduler
         * priority, though, to avoid depletion of all memory or task
         * starvation.  This prevents mm->mmap_sem livelock when an oom killed
@@ -445,7 +445,8 @@ static int oom_kill_task(struct task_struct *p, struct mem_cgroup *mem)
         * signal.
         */
        for_each_process(q)
-               if (q->mm == mm && !same_thread_group(q, p)) {
+               if (q->mm == mm && !same_thread_group(q, p) &&
+                   !(q->flags & PF_KTHREAD)) {
                        task_lock(q);   /* Protect ->comm from prctl() */
                        pr_err("Kill process %d (%s) sharing same memory\n",
                                task_pid_nr(q), q->comm);
index d1960744f881d34fe3f1c3412d717db86b8e5478..938d943a501514d52bbaffc26431ebd95ca81ed0 100644 (file)
@@ -142,6 +142,66 @@ unsigned long global_dirty_limit;
 static struct prop_descriptor vm_completions;
 static struct prop_descriptor vm_dirties;
 
+/*
+ * Work out the current dirty-memory clamping and background writeout
+ * thresholds.
+ *
+ * The main aim here is to lower them aggressively if there is a lot of mapped
+ * memory around.  To avoid stressing page reclaim with lots of unreclaimable
+ * pages.  It is better to clamp down on writers than to start swapping, and
+ * performing lots of scanning.
+ *
+ * We only allow 1/2 of the currently-unmapped memory to be dirtied.
+ *
+ * We don't permit the clamping level to fall below 5% - that is getting rather
+ * excessive.
+ *
+ * We make sure that the background writeout level is below the adjusted
+ * clamping level.
+ */
+static unsigned long highmem_dirtyable_memory(unsigned long total)
+{
+#ifdef CONFIG_HIGHMEM
+       int node;
+       unsigned long x = 0;
+
+       for_each_node_state(node, N_HIGH_MEMORY) {
+               struct zone *z =
+                       &NODE_DATA(node)->node_zones[ZONE_HIGHMEM];
+
+               x += zone_page_state(z, NR_FREE_PAGES) +
+                    zone_reclaimable_pages(z);
+       }
+       /*
+        * Make sure that the number of highmem pages is never larger
+        * than the number of the total dirtyable memory. This can only
+        * occur in very strange VM situations but we want to make sure
+        * that this does not occur.
+        */
+       return min(x, total);
+#else
+       return 0;
+#endif
+}
+
+/**
+ * determine_dirtyable_memory - amount of memory that may be used
+ *
+ * Returns the numebr of pages that can currently be freed and used
+ * by the kernel for direct mappings.
+ */
+static unsigned long determine_dirtyable_memory(void)
+{
+       unsigned long x;
+
+       x = global_page_state(NR_FREE_PAGES) + global_reclaimable_pages();
+
+       if (!vm_highmem_is_dirtyable)
+               x -= highmem_dirtyable_memory(x);
+
+       return x + 1;   /* Ensure that we never return 0 */
+}
+
 /*
  * couple the period to the dirty_ratio:
  *
@@ -208,7 +268,6 @@ int dirty_ratio_handler(struct ctl_table *table, int write,
        return ret;
 }
 
-
 int dirty_bytes_handler(struct ctl_table *table, int write,
                void __user *buffer, size_t *lenp,
                loff_t *ppos)
@@ -350,67 +409,6 @@ int bdi_set_max_ratio(struct backing_dev_info *bdi, unsigned max_ratio)
 }
 EXPORT_SYMBOL(bdi_set_max_ratio);
 
-/*
- * Work out the current dirty-memory clamping and background writeout
- * thresholds.
- *
- * The main aim here is to lower them aggressively if there is a lot of mapped
- * memory around.  To avoid stressing page reclaim with lots of unreclaimable
- * pages.  It is better to clamp down on writers than to start swapping, and
- * performing lots of scanning.
- *
- * We only allow 1/2 of the currently-unmapped memory to be dirtied.
- *
- * We don't permit the clamping level to fall below 5% - that is getting rather
- * excessive.
- *
- * We make sure that the background writeout level is below the adjusted
- * clamping level.
- */
-
-static unsigned long highmem_dirtyable_memory(unsigned long total)
-{
-#ifdef CONFIG_HIGHMEM
-       int node;
-       unsigned long x = 0;
-
-       for_each_node_state(node, N_HIGH_MEMORY) {
-               struct zone *z =
-                       &NODE_DATA(node)->node_zones[ZONE_HIGHMEM];
-
-               x += zone_page_state(z, NR_FREE_PAGES) +
-                    zone_reclaimable_pages(z);
-       }
-       /*
-        * Make sure that the number of highmem pages is never larger
-        * than the number of the total dirtyable memory. This can only
-        * occur in very strange VM situations but we want to make sure
-        * that this does not occur.
-        */
-       return min(x, total);
-#else
-       return 0;
-#endif
-}
-
-/**
- * determine_dirtyable_memory - amount of memory that may be used
- *
- * Returns the numebr of pages that can currently be freed and used
- * by the kernel for direct mappings.
- */
-unsigned long determine_dirtyable_memory(void)
-{
-       unsigned long x;
-
-       x = global_page_state(NR_FREE_PAGES) + global_reclaimable_pages();
-
-       if (!vm_highmem_is_dirtyable)
-               x -= highmem_dirtyable_memory(x);
-
-       return x + 1;   /* Ensure that we never return 0 */
-}
-
 static unsigned long hard_dirty_limit(unsigned long thresh)
 {
        return max(thresh, global_dirty_limit);
diff --git a/mm/process_vm_access.c b/mm/process_vm_access.c
new file mode 100644 (file)
index 0000000..5ac8abc
--- /dev/null
@@ -0,0 +1,487 @@
+/*
+ * linux/mm/process_vm_access.c
+ *
+ * Copyright (C) 2010-2011 Christopher Yeoh <cyeoh@au1.ibm.com>, IBM Corp.
+ *
+ * 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/mm.h>
+#include <linux/uio.h>
+#include <linux/sched.h>
+#include <linux/highmem.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/syscalls.h>
+
+#ifdef CONFIG_COMPAT
+#include <linux/compat.h>
+#endif
+
+/**
+ * process_vm_rw_pages - read/write pages from task specified
+ * @task: task to read/write from
+ * @mm: mm for task
+ * @process_pages: struct pages area that can store at least
+ *  nr_pages_to_copy struct page pointers
+ * @pa: address of page in task to start copying from/to
+ * @start_offset: offset in page to start copying from/to
+ * @len: number of bytes to copy
+ * @lvec: iovec array specifying where to copy to/from
+ * @lvec_cnt: number of elements in iovec array
+ * @lvec_current: index in iovec array we are up to
+ * @lvec_offset: offset in bytes from current iovec iov_base we are up to
+ * @vm_write: 0 means copy from, 1 means copy to
+ * @nr_pages_to_copy: number of pages to copy
+ * @bytes_copied: returns number of bytes successfully copied
+ * Returns 0 on success, error code otherwise
+ */
+static int process_vm_rw_pages(struct task_struct *task,
+                              struct mm_struct *mm,
+                              struct page **process_pages,
+                              unsigned long pa,
+                              unsigned long start_offset,
+                              unsigned long len,
+                              const struct iovec *lvec,
+                              unsigned long lvec_cnt,
+                              unsigned long *lvec_current,
+                              size_t *lvec_offset,
+                              int vm_write,
+                              unsigned int nr_pages_to_copy,
+                              ssize_t *bytes_copied)
+{
+       int pages_pinned;
+       void *target_kaddr;
+       int pgs_copied = 0;
+       int j;
+       int ret;
+       ssize_t bytes_to_copy;
+       ssize_t rc = 0;
+
+       *bytes_copied = 0;
+
+       /* Get the pages we're interested in */
+       down_read(&mm->mmap_sem);
+       pages_pinned = get_user_pages(task, mm, pa,
+                                     nr_pages_to_copy,
+                                     vm_write, 0, process_pages, NULL);
+       up_read(&mm->mmap_sem);
+
+       if (pages_pinned != nr_pages_to_copy) {
+               rc = -EFAULT;
+               goto end;
+       }
+
+       /* Do the copy for each page */
+       for (pgs_copied = 0;
+            (pgs_copied < nr_pages_to_copy) && (*lvec_current < lvec_cnt);
+            pgs_copied++) {
+               /* Make sure we have a non zero length iovec */
+               while (*lvec_current < lvec_cnt
+                      && lvec[*lvec_current].iov_len == 0)
+                       (*lvec_current)++;
+               if (*lvec_current == lvec_cnt)
+                       break;
+
+               /*
+                * Will copy smallest of:
+                * - bytes remaining in page
+                * - bytes remaining in destination iovec
+                */
+               bytes_to_copy = min_t(ssize_t, PAGE_SIZE - start_offset,
+                                     len - *bytes_copied);
+               bytes_to_copy = min_t(ssize_t, bytes_to_copy,
+                                     lvec[*lvec_current].iov_len
+                                     - *lvec_offset);
+
+               target_kaddr = kmap(process_pages[pgs_copied]) + start_offset;
+
+               if (vm_write)
+                       ret = copy_from_user(target_kaddr,
+                                            lvec[*lvec_current].iov_base
+                                            + *lvec_offset,
+                                            bytes_to_copy);
+               else
+                       ret = copy_to_user(lvec[*lvec_current].iov_base
+                                          + *lvec_offset,
+                                          target_kaddr, bytes_to_copy);
+               kunmap(process_pages[pgs_copied]);
+               if (ret) {
+                       *bytes_copied += bytes_to_copy - ret;
+                       pgs_copied++;
+                       rc = -EFAULT;
+                       goto end;
+               }
+               *bytes_copied += bytes_to_copy;
+               *lvec_offset += bytes_to_copy;
+               if (*lvec_offset == lvec[*lvec_current].iov_len) {
+                       /*
+                        * Need to copy remaining part of page into the
+                        * next iovec if there are any bytes left in page
+                        */
+                       (*lvec_current)++;
+                       *lvec_offset = 0;
+                       start_offset = (start_offset + bytes_to_copy)
+                               % PAGE_SIZE;
+                       if (start_offset)
+                               pgs_copied--;
+               } else {
+                       start_offset = 0;
+               }
+       }
+
+end:
+       if (vm_write) {
+               for (j = 0; j < pages_pinned; j++) {
+                       if (j < pgs_copied)
+                               set_page_dirty_lock(process_pages[j]);
+                       put_page(process_pages[j]);
+               }
+       } else {
+               for (j = 0; j < pages_pinned; j++)
+                       put_page(process_pages[j]);
+       }
+
+       return rc;
+}
+
+/* Maximum number of pages kmalloc'd to hold struct page's during copy */
+#define PVM_MAX_KMALLOC_PAGES (PAGE_SIZE * 2)
+
+/**
+ * process_vm_rw_single_vec - read/write pages from task specified
+ * @addr: start memory address of target process
+ * @len: size of area to copy to/from
+ * @lvec: iovec array specifying where to copy to/from locally
+ * @lvec_cnt: number of elements in iovec array
+ * @lvec_current: index in iovec array we are up to
+ * @lvec_offset: offset in bytes from current iovec iov_base we are up to
+ * @process_pages: struct pages area that can store at least
+ *  nr_pages_to_copy struct page pointers
+ * @mm: mm for task
+ * @task: task to read/write from
+ * @vm_write: 0 means copy from, 1 means copy to
+ * @bytes_copied: returns number of bytes successfully copied
+ * Returns 0 on success or on failure error code
+ */
+static int process_vm_rw_single_vec(unsigned long addr,
+                                   unsigned long len,
+                                   const struct iovec *lvec,
+                                   unsigned long lvec_cnt,
+                                   unsigned long *lvec_current,
+                                   size_t *lvec_offset,
+                                   struct page **process_pages,
+                                   struct mm_struct *mm,
+                                   struct task_struct *task,
+                                   int vm_write,
+                                   ssize_t *bytes_copied)
+{
+       unsigned long pa = addr & PAGE_MASK;
+       unsigned long start_offset = addr - pa;
+       unsigned long nr_pages;
+       ssize_t bytes_copied_loop;
+       ssize_t rc = 0;
+       unsigned long nr_pages_copied = 0;
+       unsigned long nr_pages_to_copy;
+       unsigned long max_pages_per_loop = PVM_MAX_KMALLOC_PAGES
+               / sizeof(struct pages *);
+
+       *bytes_copied = 0;
+
+       /* Work out address and page range required */
+       if (len == 0)
+               return 0;
+       nr_pages = (addr + len - 1) / PAGE_SIZE - addr / PAGE_SIZE + 1;
+
+       while ((nr_pages_copied < nr_pages) && (*lvec_current < lvec_cnt)) {
+               nr_pages_to_copy = min(nr_pages - nr_pages_copied,
+                                      max_pages_per_loop);
+
+               rc = process_vm_rw_pages(task, mm, process_pages, pa,
+                                        start_offset, len,
+                                        lvec, lvec_cnt,
+                                        lvec_current, lvec_offset,
+                                        vm_write, nr_pages_to_copy,
+                                        &bytes_copied_loop);
+               start_offset = 0;
+               *bytes_copied += bytes_copied_loop;
+
+               if (rc < 0) {
+                       return rc;
+               } else {
+                       len -= bytes_copied_loop;
+                       nr_pages_copied += nr_pages_to_copy;
+                       pa += nr_pages_to_copy * PAGE_SIZE;
+               }
+       }
+
+       return rc;
+}
+
+/**
+ * process_vm_rw_core - core of reading/writing pages from task specified
+ * @pid: PID of process to read/write from/to
+ * @lvec: iovec array specifying where to copy to/from locally
+ * @liovcnt: size of lvec array
+ * @rvec: iovec array specifying where to copy to/from in the other process
+ * @riovcnt: size of rvec array
+ * @flags: currently unused
+ * @vm_write: 0 if reading from other process, 1 if writing to other process
+ * Returns the number of bytes read/written or error code. May
+ *  return less bytes than expected if an error occurs during the copying
+ *  process.
+ */
+static ssize_t process_vm_rw_core(pid_t pid, const struct iovec *lvec,
+                                 unsigned long liovcnt,
+                                 const struct iovec *rvec,
+                                 unsigned long riovcnt,
+                                 unsigned long flags, int vm_write)
+{
+       struct task_struct *task;
+       struct page **process_pages = NULL;
+       struct mm_struct *mm;
+       unsigned long i;
+       ssize_t rc = 0;
+       ssize_t bytes_copied_loop;
+       ssize_t bytes_copied = 0;
+       unsigned long nr_pages = 0;
+       unsigned long nr_pages_iov;
+       unsigned long iov_l_curr_idx = 0;
+       size_t iov_l_curr_offset = 0;
+       ssize_t iov_len;
+
+       /*
+        * Work out how many pages of struct pages we're going to need
+        * when eventually calling get_user_pages
+        */
+       for (i = 0; i < riovcnt; i++) {
+               iov_len = rvec[i].iov_len;
+               if (iov_len > 0) {
+                       nr_pages_iov = ((unsigned long)rvec[i].iov_base
+                                       + iov_len)
+                               / PAGE_SIZE - (unsigned long)rvec[i].iov_base
+                               / PAGE_SIZE + 1;
+                       nr_pages = max(nr_pages, nr_pages_iov);
+               }
+       }
+
+       if (nr_pages == 0)
+               return 0;
+
+       /* For reliability don't try to kmalloc more than 2 pages worth */
+       process_pages = kmalloc(min_t(size_t, PVM_MAX_KMALLOC_PAGES,
+                                     sizeof(struct pages *)*nr_pages),
+                               GFP_KERNEL);
+
+       if (!process_pages)
+               return -ENOMEM;
+
+       /* Get process information */
+       rcu_read_lock();
+       task = find_task_by_vpid(pid);
+       if (task)
+               get_task_struct(task);
+       rcu_read_unlock();
+       if (!task) {
+               rc = -ESRCH;
+               goto free_proc_pages;
+       }
+
+       task_lock(task);
+       if (__ptrace_may_access(task, PTRACE_MODE_ATTACH)) {
+               task_unlock(task);
+               rc = -EPERM;
+               goto put_task_struct;
+       }
+       mm = task->mm;
+
+       if (!mm || (task->flags & PF_KTHREAD)) {
+               task_unlock(task);
+               rc = -EINVAL;
+               goto put_task_struct;
+       }
+
+       atomic_inc(&mm->mm_users);
+       task_unlock(task);
+
+       for (i = 0; i < riovcnt && iov_l_curr_idx < liovcnt; i++) {
+               rc = process_vm_rw_single_vec(
+                       (unsigned long)rvec[i].iov_base, rvec[i].iov_len,
+                       lvec, liovcnt, &iov_l_curr_idx, &iov_l_curr_offset,
+                       process_pages, mm, task, vm_write, &bytes_copied_loop);
+               bytes_copied += bytes_copied_loop;
+               if (rc != 0) {
+                       /* If we have managed to copy any data at all then
+                          we return the number of bytes copied. Otherwise
+                          we return the error code */
+                       if (bytes_copied)
+                               rc = bytes_copied;
+                       goto put_mm;
+               }
+       }
+
+       rc = bytes_copied;
+put_mm:
+       mmput(mm);
+
+put_task_struct:
+       put_task_struct(task);
+
+free_proc_pages:
+       kfree(process_pages);
+       return rc;
+}
+
+/**
+ * process_vm_rw - check iovecs before calling core routine
+ * @pid: PID of process to read/write from/to
+ * @lvec: iovec array specifying where to copy to/from locally
+ * @liovcnt: size of lvec array
+ * @rvec: iovec array specifying where to copy to/from in the other process
+ * @riovcnt: size of rvec array
+ * @flags: currently unused
+ * @vm_write: 0 if reading from other process, 1 if writing to other process
+ * Returns the number of bytes read/written or error code. May
+ *  return less bytes than expected if an error occurs during the copying
+ *  process.
+ */
+static ssize_t process_vm_rw(pid_t pid,
+                            const struct iovec __user *lvec,
+                            unsigned long liovcnt,
+                            const struct iovec __user *rvec,
+                            unsigned long riovcnt,
+                            unsigned long flags, int vm_write)
+{
+       struct iovec iovstack_l[UIO_FASTIOV];
+       struct iovec iovstack_r[UIO_FASTIOV];
+       struct iovec *iov_l = iovstack_l;
+       struct iovec *iov_r = iovstack_r;
+       ssize_t rc;
+
+       if (flags != 0)
+               return -EINVAL;
+
+       /* Check iovecs */
+       if (vm_write)
+               rc = rw_copy_check_uvector(WRITE, lvec, liovcnt, UIO_FASTIOV,
+                                          iovstack_l, &iov_l, 1);
+       else
+               rc = rw_copy_check_uvector(READ, lvec, liovcnt, UIO_FASTIOV,
+                                          iovstack_l, &iov_l, 1);
+       if (rc <= 0)
+               goto free_iovecs;
+
+       rc = rw_copy_check_uvector(READ, rvec, riovcnt, UIO_FASTIOV,
+                                  iovstack_r, &iov_r, 0);
+       if (rc <= 0)
+               goto free_iovecs;
+
+       rc = process_vm_rw_core(pid, iov_l, liovcnt, iov_r, riovcnt, flags,
+                               vm_write);
+
+free_iovecs:
+       if (iov_r != iovstack_r)
+               kfree(iov_r);
+       if (iov_l != iovstack_l)
+               kfree(iov_l);
+
+       return rc;
+}
+
+SYSCALL_DEFINE6(process_vm_readv, pid_t, pid, const struct iovec __user *, lvec,
+               unsigned long, liovcnt, const struct iovec __user *, rvec,
+               unsigned long, riovcnt, unsigned long, flags)
+{
+       return process_vm_rw(pid, lvec, liovcnt, rvec, riovcnt, flags, 0);
+}
+
+SYSCALL_DEFINE6(process_vm_writev, pid_t, pid,
+               const struct iovec __user *, lvec,
+               unsigned long, liovcnt, const struct iovec __user *, rvec,
+               unsigned long, riovcnt, unsigned long, flags)
+{
+       return process_vm_rw(pid, lvec, liovcnt, rvec, riovcnt, flags, 1);
+}
+
+#ifdef CONFIG_COMPAT
+
+asmlinkage ssize_t
+compat_process_vm_rw(compat_pid_t pid,
+                    const struct compat_iovec __user *lvec,
+                    unsigned long liovcnt,
+                    const struct compat_iovec __user *rvec,
+                    unsigned long riovcnt,
+                    unsigned long flags, int vm_write)
+{
+       struct iovec iovstack_l[UIO_FASTIOV];
+       struct iovec iovstack_r[UIO_FASTIOV];
+       struct iovec *iov_l = iovstack_l;
+       struct iovec *iov_r = iovstack_r;
+       ssize_t rc = -EFAULT;
+
+       if (flags != 0)
+               return -EINVAL;
+
+       if (!access_ok(VERIFY_READ, lvec, liovcnt * sizeof(*lvec)))
+               goto out;
+
+       if (!access_ok(VERIFY_READ, rvec, riovcnt * sizeof(*rvec)))
+               goto out;
+
+       if (vm_write)
+               rc = compat_rw_copy_check_uvector(WRITE, lvec, liovcnt,
+                                                 UIO_FASTIOV, iovstack_l,
+                                                 &iov_l, 1);
+       else
+               rc = compat_rw_copy_check_uvector(READ, lvec, liovcnt,
+                                                 UIO_FASTIOV, iovstack_l,
+                                                 &iov_l, 1);
+       if (rc <= 0)
+               goto free_iovecs;
+       rc = compat_rw_copy_check_uvector(READ, rvec, riovcnt,
+                                         UIO_FASTIOV, iovstack_r,
+                                         &iov_r, 0);
+       if (rc <= 0)
+               goto free_iovecs;
+
+       rc = process_vm_rw_core(pid, iov_l, liovcnt, iov_r, riovcnt, flags,
+                          vm_write);
+
+free_iovecs:
+       if (iov_r != iovstack_r)
+               kfree(iov_r);
+       if (iov_l != iovstack_l)
+               kfree(iov_l);
+
+out:
+       return rc;
+}
+
+asmlinkage ssize_t
+compat_sys_process_vm_readv(compat_pid_t pid,
+                           const struct compat_iovec __user *lvec,
+                           unsigned long liovcnt,
+                           const struct compat_iovec __user *rvec,
+                           unsigned long riovcnt,
+                           unsigned long flags)
+{
+       return compat_process_vm_rw(pid, lvec, liovcnt, rvec,
+                                   riovcnt, flags, 0);
+}
+
+asmlinkage ssize_t
+compat_sys_process_vm_writev(compat_pid_t pid,
+                            const struct compat_iovec __user *lvec,
+                            unsigned long liovcnt,
+                            const struct compat_iovec __user *rvec,
+                            unsigned long riovcnt,
+                            unsigned long flags)
+{
+       return compat_process_vm_rw(pid, lvec, liovcnt, rvec,
+                                   riovcnt, flags, 1);
+}
+
+#endif
index 7ef69124fa3e5f4ef28baaed58a7e997d40155ab..3153729fa6a56f181c9154e9e457199c7ddfea78 100644 (file)
@@ -1013,23 +1013,27 @@ keep_lumpy:
  *
  * returns 0 on success, -ve errno on failure.
  */
-int __isolate_lru_page(struct page *page, int mode, int file)
+int __isolate_lru_page(struct page *page, isolate_mode_t mode, int file)
 {
+       bool all_lru_mode;
        int ret = -EINVAL;
 
        /* Only take pages on the LRU. */
        if (!PageLRU(page))
                return ret;
 
+       all_lru_mode = (mode & (ISOLATE_ACTIVE|ISOLATE_INACTIVE)) ==
+               (ISOLATE_ACTIVE|ISOLATE_INACTIVE);
+
        /*
         * When checking the active state, we need to be sure we are
         * dealing with comparible boolean values.  Take the logical not
         * of each.
         */
-       if (mode != ISOLATE_BOTH && (!PageActive(page) != !mode))
+       if (!all_lru_mode && !PageActive(page) != !(mode & ISOLATE_ACTIVE))
                return ret;
 
-       if (mode != ISOLATE_BOTH && page_is_file_cache(page) != file)
+       if (!all_lru_mode && !!page_is_file_cache(page) != file)
                return ret;
 
        /*
@@ -1042,6 +1046,12 @@ int __isolate_lru_page(struct page *page, int mode, int file)
 
        ret = -EBUSY;
 
+       if ((mode & ISOLATE_CLEAN) && (PageDirty(page) || PageWriteback(page)))
+               return ret;
+
+       if ((mode & ISOLATE_UNMAPPED) && page_mapped(page))
+               return ret;
+
        if (likely(get_page_unless_zero(page))) {
                /*
                 * Be careful not to clear PageLRU until after we're
@@ -1077,7 +1087,8 @@ int __isolate_lru_page(struct page *page, int mode, int file)
  */
 static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
                struct list_head *src, struct list_head *dst,
-               unsigned long *scanned, int order, int mode, int file)
+               unsigned long *scanned, int order, isolate_mode_t mode,
+               int file)
 {
        unsigned long nr_taken = 0;
        unsigned long nr_lumpy_taken = 0;
@@ -1202,8 +1213,8 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
 static unsigned long isolate_pages_global(unsigned long nr,
                                        struct list_head *dst,
                                        unsigned long *scanned, int order,
-                                       int mode, struct zone *z,
-                                       int active, int file)
+                                       isolate_mode_t mode,
+                                       struct zone *z, int active, int file)
 {
        int lru = LRU_BASE;
        if (active)
@@ -1455,6 +1466,7 @@ shrink_inactive_list(unsigned long nr_to_scan, struct zone *zone,
        unsigned long nr_taken;
        unsigned long nr_anon;
        unsigned long nr_file;
+       isolate_mode_t reclaim_mode = ISOLATE_INACTIVE;
 
        while (unlikely(too_many_isolated(zone, file, sc))) {
                congestion_wait(BLK_RW_ASYNC, HZ/10);
@@ -1465,15 +1477,21 @@ shrink_inactive_list(unsigned long nr_to_scan, struct zone *zone,
        }
 
        set_reclaim_mode(priority, sc, false);
+       if (sc->reclaim_mode & RECLAIM_MODE_LUMPYRECLAIM)
+               reclaim_mode |= ISOLATE_ACTIVE;
+
        lru_add_drain();
+
+       if (!sc->may_unmap)
+               reclaim_mode |= ISOLATE_UNMAPPED;
+       if (!sc->may_writepage)
+               reclaim_mode |= ISOLATE_CLEAN;
+
        spin_lock_irq(&zone->lru_lock);
 
        if (scanning_global_lru(sc)) {
-               nr_taken = isolate_pages_global(nr_to_scan,
-                       &page_list, &nr_scanned, sc->order,
-                       sc->reclaim_mode & RECLAIM_MODE_LUMPYRECLAIM ?
-                                       ISOLATE_BOTH : ISOLATE_INACTIVE,
-                       zone, 0, file);
+               nr_taken = isolate_pages_global(nr_to_scan, &page_list,
+                       &nr_scanned, sc->order, reclaim_mode, zone, 0, file);
                zone->pages_scanned += nr_scanned;
                if (current_is_kswapd())
                        __count_zone_vm_events(PGSCAN_KSWAPD, zone,
@@ -1482,12 +1500,9 @@ shrink_inactive_list(unsigned long nr_to_scan, struct zone *zone,
                        __count_zone_vm_events(PGSCAN_DIRECT, zone,
                                               nr_scanned);
        } else {
-               nr_taken = mem_cgroup_isolate_pages(nr_to_scan,
-                       &page_list, &nr_scanned, sc->order,
-                       sc->reclaim_mode & RECLAIM_MODE_LUMPYRECLAIM ?
-                                       ISOLATE_BOTH : ISOLATE_INACTIVE,
-                       zone, sc->mem_cgroup,
-                       0, file);
+               nr_taken = mem_cgroup_isolate_pages(nr_to_scan, &page_list,
+                       &nr_scanned, sc->order, reclaim_mode, zone,
+                       sc->mem_cgroup, 0, file);
                /*
                 * mem_cgroup_isolate_pages() keeps track of
                 * scanned pages on its own.
@@ -1592,19 +1607,26 @@ static void shrink_active_list(unsigned long nr_pages, struct zone *zone,
        struct page *page;
        struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(zone, sc);
        unsigned long nr_rotated = 0;
+       isolate_mode_t reclaim_mode = ISOLATE_ACTIVE;
 
        lru_add_drain();
+
+       if (!sc->may_unmap)
+               reclaim_mode |= ISOLATE_UNMAPPED;
+       if (!sc->may_writepage)
+               reclaim_mode |= ISOLATE_CLEAN;
+
        spin_lock_irq(&zone->lru_lock);
        if (scanning_global_lru(sc)) {
                nr_taken = isolate_pages_global(nr_pages, &l_hold,
                                                &pgscanned, sc->order,
-                                               ISOLATE_ACTIVE, zone,
+                                               reclaim_mode, zone,
                                                1, file);
                zone->pages_scanned += pgscanned;
        } else {
                nr_taken = mem_cgroup_isolate_pages(nr_pages, &l_hold,
                                                &pgscanned, sc->order,
-                                               ISOLATE_ACTIVE, zone,
+                                               reclaim_mode, zone,
                                                sc->mem_cgroup, 1, file);
                /*
                 * mem_cgroup_isolate_pages() keeps track of
@@ -2000,12 +2022,14 @@ static void shrink_zone(int priority, struct zone *zone,
        enum lru_list l;
        unsigned long nr_reclaimed, nr_scanned;
        unsigned long nr_to_reclaim = sc->nr_to_reclaim;
+       struct blk_plug plug;
 
 restart:
        nr_reclaimed = 0;
        nr_scanned = sc->nr_scanned;
        get_scan_count(zone, sc, nr, priority);
 
+       blk_start_plug(&plug);
        while (nr[LRU_INACTIVE_ANON] || nr[LRU_ACTIVE_FILE] ||
                                        nr[LRU_INACTIVE_FILE]) {
                for_each_evictable_lru(l) {
@@ -2029,6 +2053,7 @@ restart:
                if (nr_reclaimed >= nr_to_reclaim && priority < DEF_PRIORITY)
                        break;
        }
+       blk_finish_plug(&plug);
        sc->nr_reclaimed += nr_reclaimed;
 
        /*
index 338b510e90275b1da873ed83aa907c404997d353..4c48e13448f84e0df200ab0a2f0895d0eb5a709c 100644 (file)
@@ -38,7 +38,7 @@ long compat_keyctl_instantiate_key_iov(
 
        ret = compat_rw_copy_check_uvector(WRITE, _payload_iov, ioc,
                                           ARRAY_SIZE(iovstack),
-                                          iovstack, &iov);
+                                          iovstack, &iov, 1);
        if (ret < 0)
                return ret;
        if (ret == 0)
index eca51918c951d3a28db16bf0f61c749722b6ac64..0b3f5d72af1cecbd06b33c2151ec570a4cfaa2ee 100644 (file)
@@ -1065,7 +1065,7 @@ long keyctl_instantiate_key_iov(key_serial_t id,
                goto no_payload;
 
        ret = rw_copy_check_uvector(WRITE, _payload_iov, ioc,
-                                   ARRAY_SIZE(iovstack), iovstack, &iov);
+                                   ARRAY_SIZE(iovstack), iovstack, &iov, 1);
        if (ret < 0)
                return ret;
        if (ret == 0)
index 55d92cbb177acaf31a7b84282cf8d56b0c71fbe5..902187657bc2f740750993c4abf44b242ad81d81 100644 (file)
@@ -752,14 +752,6 @@ out:
        return length;
 }
 
-static inline int hexcode_to_int(int code) {
-       if (code == '\0' || !isxdigit(code))
-               return -1;
-       if (isdigit(code))
-               return code - '0';
-       return tolower(code) - 'a' + 10;
-}
-
 static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
 {
        char *scon = NULL, *tcon = NULL;
@@ -811,9 +803,11 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
                        if (c1 == '+')
                                c1 = ' ';
                        else if (c1 == '%') {
-                               if ((c1 = hexcode_to_int(*r++)) < 0)
+                               c1 = hex_to_bin(*r++);
+                               if (c1 < 0)
                                        goto out;
-                               if ((c2 = hexcode_to_int(*r++)) < 0)
+                               c2 = hex_to_bin(*r++);
+                               if (c2 < 0)
                                        goto out;
                                c1 = (c1 << 4) | c2;
                        }