Merge tag 'char-misc-3.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregk...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 15 Feb 2015 18:48:44 +0000 (10:48 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 15 Feb 2015 18:48:44 +0000 (10:48 -0800)
Pull char / misc patches from Greg KH:
 "Here's the big char/misc driver update for 3.20-rc1.

  Lots of little things in here, all described in the changelog.
  Nothing major or unusual, except maybe the binder selinux stuff, which
  was all acked by the proper selinux people and they thought it best to
  come through this tree.

  All of this has been in linux-next with no reported issues for a while"

* tag 'char-misc-3.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (90 commits)
  coresight: fix function etm_writel_cp14() parameter order
  coresight-etm: remove check for unknown Kconfig macro
  coresight: fixing CPU hwid lookup in device tree
  coresight: remove the unnecessary function coresight_is_bit_set()
  coresight: fix the debug AMBA bus name
  coresight: remove the extra spaces
  coresight: fix the link between orphan connection and newly added device
  coresight: remove the unnecessary replicator property
  coresight: fix the replicator subtype value
  pdfdocs: Fix 'make pdfdocs' failure for 'uio-howto.tmpl'
  mcb: Fix error path of mcb_pci_probe
  virtio/console: verify device has config space
  ti-st: clean up data types (fix harmless memory corruption)
  mei: me: release hw from reset only during the reset flow
  mei: mask interrupt set bit on clean reset bit
  extcon: max77693: Constify struct regmap_config
  extcon: adc-jack: Release IIO channel on driver remove
  extcon: Remove duplicated include from extcon-class.c
  Drivers: hv: vmbus: hv_process_timer_expiration() can be static
  Drivers: hv: vmbus: serialize Offer and Rescind offer
  ...

80 files changed:
Documentation/DocBook/uio-howto.tmpl
Documentation/devicetree/bindings/arm/coresight.txt
Documentation/devicetree/bindings/powerpc/fsl/lbc.txt
Documentation/stable_kernel_rules.txt
Documentation/trace/coresight.txt
MAINTAINERS
arch/powerpc/include/asm/fsl_lbc.h
arch/x86/include/uapi/asm/hyperv.h
drivers/android/binder.c
drivers/char/Kconfig
drivers/char/i8k.c
drivers/char/mem.c
drivers/char/virtio_console.c
drivers/coresight/coresight-etb10.c
drivers/coresight/coresight-etm3x.c
drivers/coresight/coresight-funnel.c
drivers/coresight/coresight-priv.h
drivers/coresight/coresight-replicator.c
drivers/coresight/coresight-tmc.c
drivers/coresight/coresight-tpiu.c
drivers/coresight/coresight.c
drivers/coresight/of_coresight.c
drivers/extcon/extcon-adc-jack.c
drivers/extcon/extcon-class.c
drivers/extcon/extcon-max77693.c
drivers/hv/channel.c
drivers/hv/channel_mgmt.c
drivers/hv/connection.c
drivers/hv/hv.c
drivers/hv/hv_balloon.c
drivers/hv/hv_fcopy.c
drivers/hv/hyperv_vmbus.h
drivers/hv/vmbus_drv.c
drivers/mcb/mcb-pci.c
drivers/misc/ad525x_dpot-spi.c
drivers/misc/ad525x_dpot.c
drivers/misc/genwqe/card_base.h
drivers/misc/genwqe/card_sysfs.c
drivers/misc/ioc4.c
drivers/misc/mei/amthif.c
drivers/misc/mei/bus.c
drivers/misc/mei/client.c
drivers/misc/mei/client.h
drivers/misc/mei/debugfs.c
drivers/misc/mei/hbm.c
drivers/misc/mei/hw-me.c
drivers/misc/mei/main.c
drivers/misc/mei/mei_dev.h
drivers/misc/mei/nfc.c
drivers/misc/mei/wd.c
drivers/misc/ti-st/st_core.c
drivers/misc/ti-st/st_kim.c
drivers/misc/ti-st/st_ll.c
drivers/misc/vmw_vmci/vmci_driver.c
drivers/misc/vmw_vmci/vmci_host.c
drivers/pcmcia/Kconfig
drivers/pcmcia/Makefile
drivers/pcmcia/cistpl.c
drivers/pcmcia/cs_internal.h
drivers/pcmcia/ds.c
drivers/pcmcia/rsrc_mgr.c
drivers/pcmcia/rsrc_pci.c [new file with mode: 0644]
drivers/pnp/pnpbios/core.c
drivers/uio/Kconfig
drivers/uio/Makefile
drivers/uio/uio_fsl_elbc_gpcm.c [new file with mode: 0644]
drivers/uio/uio_pci_generic.c
drivers/vme/vme.c
include/linux/coresight.h
include/linux/hyperv.h
include/linux/mei_cl_bus.h
include/linux/security.h
include/linux/ti_wilink_st.h
security/capability.c
security/security.c
security/selinux/hooks.c
security/selinux/include/classmap.h
tools/hv/Makefile
tools/hv/hv_fcopy_daemon.c
tools/hv/hv_kvp_daemon.c

index 1fdc246e425614b3e9ea2096de11e44ea728e904..cd0e452dfed56e91e8fd4223cf3536da4e90f799 100644 (file)
@@ -719,7 +719,7 @@ framework to set up sysfs files for this region. Simply leave it alone.
        </para>
 </sect1>
 
-<sect1 id="using uio_dmem_genirq">
+<sect1 id="using-uio_dmem_genirq">
 <title>Using uio_dmem_genirq for platform devices</title>
        <para>
        In addition to statically allocated memory ranges, they may also be
@@ -746,16 +746,16 @@ framework to set up sysfs files for this region. Simply leave it alone.
        following elements:
        </para>
        <itemizedlist>
-       <listitem><varname>struct uio_info uioinfo</varname>: The same
+       <listitem><para><varname>struct uio_info uioinfo</varname>: The same
        structure used as the  <varname>uio_pdrv_genirq</varname> platform
-       data</listitem>
-       <listitem><varname>unsigned int *dynamic_region_sizes</varname>:
+       data</para></listitem>
+       <listitem><para><varname>unsigned int *dynamic_region_sizes</varname>:
        Pointer to list of sizes of dynamic memory regions to be mapped into
        user space.
-       </listitem>
-       <listitem><varname>unsigned int num_dynamic_regions</varname>:
+       </para></listitem>
+       <listitem><para><varname>unsigned int num_dynamic_regions</varname>:
        Number of elements in <varname>dynamic_region_sizes</varname> array.
-       </listitem>
+       </para></listitem>
        </itemizedlist>
        <para>
        The dynamic regions defined in the platform data will be appended to
index d790f49066f3557a7cd362543f89c6e2d6cebd53..a3089359aaa6e58dfdf9588995d72b53ff2d1938 100644 (file)
@@ -38,8 +38,6 @@ its hardware characteristcs.
          AMBA markee):
                - "arm,coresight-replicator"
 
-       * id: a unique number that will identify this replicator.
-
        * port or ports: same as above.
 
 * Optional properties for ETM/PTMs:
@@ -94,8 +92,6 @@ Example:
                 * AMBA bus.  As such no need to add "arm,primecell".
                 */
                compatible = "arm,coresight-replicator";
-               /* this will show up in debugfs as "0.replicator" */
-               id = <0>;
 
                ports {
                        #address-cells = <1>;
index 3300fec501c540288663e93949faf2722f4fd730..1c80fcedebb52049721fbd61c4dd4c57133bd47c 100644 (file)
@@ -16,20 +16,28 @@ Example:
                           "fsl,pq2-localbus";
                #address-cells = <2>;
                #size-cells = <1>;
-               reg = <f0010100 40>;
+               reg = <0xf0010100 0x40>;
 
-               ranges = <0 0 fe000000 02000000
-                         1 0 f4500000 00008000>;
+               ranges = <0x0 0x0 0xfe000000 0x02000000
+                         0x1 0x0 0xf4500000 0x00008000
+                         0x2 0x0 0xfd810000 0x00010000>;
 
                flash@0,0 {
                        compatible = "jedec-flash";
-                       reg = <0 0 2000000>;
+                       reg = <0x0 0x0 0x2000000>;
                        bank-width = <4>;
                        device-width = <1>;
                };
 
                board-control@1,0 {
-                       reg = <1 0 20>;
+                       reg = <0x1 0x0 0x20>;
                        compatible = "fsl,mpc8272ads-bcsr";
                };
+
+               simple-periph@2,0 {
+                       compatible = "fsl,elbc-gpcm-uio";
+                       reg = <0x2 0x0 0x10000>;
+                       elbc-gpcm-br = <0xfd810800>;
+                       elbc-gpcm-or = <0xffff09f7>;
+               };
        };
index aee73e78c7d42a8aa7d9c1f630c705ddb6c3838c..02f8331edb8bfd54bf39b2ae150609ae158f2686 100644 (file)
@@ -32,18 +32,42 @@ Procedure for submitting patches to the -stable tree:
  - If the patch covers files in net/ or drivers/net please follow netdev stable
    submission guidelines as described in
    Documentation/networking/netdev-FAQ.txt
- - Send the patch, after verifying that it follows the above rules, to
-   stable@vger.kernel.org.  You must note the upstream commit ID in the
-   changelog of your submission, as well as the kernel version you wish
-   it to be applied to.
- - To have the patch automatically included in the stable tree, add the tag
+ - Security patches should not be handled (solely) by the -stable review
+   process but should follow the procedures in Documentation/SecurityBugs.
+
+For all other submissions, choose one of the following procedures:
+
+   --- Option 1 ---
+
+   To have the patch automatically included in the stable tree, add the tag
      Cc: stable@vger.kernel.org
    in the sign-off area. Once the patch is merged it will be applied to
    the stable tree without anything else needing to be done by the author
    or subsystem maintainer.
- - If the patch requires other patches as prerequisites which can be
-   cherry-picked, then this can be specified in the following format in
-   the sign-off area:
+
+   --- Option 2 ---
+
+   After the patch has been merged to Linus' tree, send an email to
+   stable@vger.kernel.org containing the subject of the patch, the commit ID,
+   why you think it should be applied, and what kernel version you wish it to
+   be applied to.
+
+   --- Option 3 ---
+
+   Send the patch, after verifying that it follows the above rules, to
+   stable@vger.kernel.org.  You must note the upstream commit ID in the
+   changelog of your submission, as well as the kernel version you wish
+   it to be applied to.
+
+Option 1 is probably the easiest and most common. Options 2 and 3 are more
+useful if the patch isn't deemed worthy at the time it is applied to a public
+git tree (for instance, because it deserves more regression testing first).
+Option 3 is especially useful if the patch needs some special handling to apply
+to an older kernel (e.g., if API's have changed in the meantime).
+
+Additionally, some patches submitted via Option 1 may have additional patch
+prerequisites which can be cherry-picked. This can be specified in the following
+format in the sign-off area:
 
      Cc: <stable@vger.kernel.org> # 3.3.x: a1f84a3: sched: Check for idle
      Cc: <stable@vger.kernel.org> # 3.3.x: 1b9508f: sched: Rate-limit newidle
@@ -57,13 +81,13 @@ Procedure for submitting patches to the -stable tree:
      git cherry-pick fd21073
      git cherry-pick <this commit>
 
+Following the submission:
+
  - The sender will receive an ACK when the patch has been accepted into the
    queue, or a NAK if the patch is rejected.  This response might take a few
    days, according to the developer's schedules.
  - If accepted, the patch will be added to the -stable queue, for review by
    other developers and by the relevant subsystem maintainer.
- - Security patches should not be sent to this alias, but instead to the
-   documented security@kernel.org address.
 
 
 Review cycle:
index bba7dbfc49edcd7077fc63f590e4ce502dbbdee3..02361552a3eac314a68338c5638f4239ed0d28d7 100644 (file)
@@ -46,7 +46,7 @@ At typical coresight system would look like this:
   | |   .        | !   | |   .        | !      | !        .   |      | SWD/
   | |   .        | !   | |   .        | !      | !        .   |      | JTAG
   *****************************************************************<-|
- *************************** AMBA Debug ABP ************************
+ *************************** AMBA Debug APB ************************
   *****************************************************************
    |    .          !         .          !        !        .    |
    |    .          *         .          *        *        .    |
@@ -79,7 +79,7 @@ At typical coresight system would look like this:
           To trace port                       TPIU= Trace Port Interface Unit
                                               SWD = Serial Wire Debug
 
-While on target configuration of the components is done via the ABP bus,
+While on target configuration of the components is done via the APB bus,
 all trace data are carried out-of-band on the ATB bus.  The CTM provides
 a way to aggregate and distribute signals between CoreSight components.
 
index d854959aa519e018365c1b03e89ab005c6a72d90..71a65389ca4d8756d5f4f252b99e4b8bc34ce446 100644 (file)
@@ -3033,6 +3033,7 @@ F:        drivers/platform/x86/dell-laptop.c
 
 DELL LAPTOP SMM DRIVER
 M:     Guenter Roeck <linux@roeck-us.net>
+S:     Maintained
 F:     drivers/char/i8k.c
 F:     include/uapi/linux/i8k.h
 
index 067fb0dca549b86fc4ad02cca3b180718c2a9593..c7240a024b96662bb81bf26f80314e3ce8aff42a 100644 (file)
@@ -95,6 +95,9 @@ struct fsl_lbc_bank {
 #define OR_FCM_TRLX_SHIFT                2
 #define OR_FCM_EHTR             0x00000002
 #define OR_FCM_EHTR_SHIFT                1
+
+#define OR_GPCM_AM             0xFFFF8000
+#define OR_GPCM_AM_SHIFT               15
 };
 
 struct fsl_lbc_regs {
index 462efe746d77fe59c2d71e676acc07b9b9e164d5..90c458e66e13332b847f2a5fb1f0772d3f70e39f 100644 (file)
 #define HV_X64_MSR_SINT14                      0x4000009E
 #define HV_X64_MSR_SINT15                      0x4000009F
 
+/*
+ * Synthetic Timer MSRs. Four timers per vcpu.
+ */
+#define HV_X64_MSR_STIMER0_CONFIG              0x400000B0
+#define HV_X64_MSR_STIMER0_COUNT               0x400000B1
+#define HV_X64_MSR_STIMER1_CONFIG              0x400000B2
+#define HV_X64_MSR_STIMER1_COUNT               0x400000B3
+#define HV_X64_MSR_STIMER2_CONFIG              0x400000B4
+#define HV_X64_MSR_STIMER2_COUNT               0x400000B5
+#define HV_X64_MSR_STIMER3_CONFIG              0x400000B6
+#define HV_X64_MSR_STIMER3_COUNT               0x400000B7
 
 #define HV_X64_MSR_HYPERCALL_ENABLE            0x00000001
 #define HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_SHIFT        12
index 8c43521d3f114d54c3c14fc9ec71d1a5f8f1814a..33b09b6568a4a464657b51667ffe8596c7893b2f 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
 #include <linux/pid_namespace.h>
+#include <linux/security.h>
 
 #ifdef CONFIG_ANDROID_BINDER_IPC_32BIT
 #define BINDER_IPC_32BIT 1
@@ -1400,6 +1401,11 @@ static void binder_transaction(struct binder_proc *proc,
                        return_error = BR_DEAD_REPLY;
                        goto err_dead_binder;
                }
+               if (security_binder_transaction(proc->tsk,
+                                               target_proc->tsk) < 0) {
+                       return_error = BR_FAILED_REPLY;
+                       goto err_invalid_target_handle;
+               }
                if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) {
                        struct binder_transaction *tmp;
 
@@ -1551,6 +1557,11 @@ static void binder_transaction(struct binder_proc *proc,
                                return_error = BR_FAILED_REPLY;
                                goto err_binder_get_ref_for_node_failed;
                        }
+                       if (security_binder_transfer_binder(proc->tsk,
+                                                           target_proc->tsk)) {
+                               return_error = BR_FAILED_REPLY;
+                               goto err_binder_get_ref_for_node_failed;
+                       }
                        ref = binder_get_ref_for_node(target_proc, node);
                        if (ref == NULL) {
                                return_error = BR_FAILED_REPLY;
@@ -1581,6 +1592,11 @@ static void binder_transaction(struct binder_proc *proc,
                                return_error = BR_FAILED_REPLY;
                                goto err_binder_get_ref_failed;
                        }
+                       if (security_binder_transfer_binder(proc->tsk,
+                                                           target_proc->tsk)) {
+                               return_error = BR_FAILED_REPLY;
+                               goto err_binder_get_ref_failed;
+                       }
                        if (ref->node->proc == target_proc) {
                                if (fp->type == BINDER_TYPE_HANDLE)
                                        fp->type = BINDER_TYPE_BINDER;
@@ -1638,6 +1654,13 @@ static void binder_transaction(struct binder_proc *proc,
                                return_error = BR_FAILED_REPLY;
                                goto err_fget_failed;
                        }
+                       if (security_binder_transfer_file(proc->tsk,
+                                                         target_proc->tsk,
+                                                         file) < 0) {
+                               fput(file);
+                               return_error = BR_FAILED_REPLY;
+                               goto err_get_unused_fd_failed;
+                       }
                        target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);
                        if (target_fd < 0) {
                                fput(file);
@@ -2675,6 +2698,9 @@ static int binder_ioctl_set_ctx_mgr(struct file *filp)
                ret = -EBUSY;
                goto out;
        }
+       ret = security_binder_set_context_mgr(proc->tsk);
+       if (ret < 0)
+               goto out;
        if (uid_valid(binder_context_mgr_uid)) {
                if (!uid_eq(binder_context_mgr_uid, curr_euid)) {
                        pr_err("BINDER_SET_CONTEXT_MGR bad uid %d != %d\n",
index efefd12a0f7bd97b2d6a3970eb068250bce257c2..a4af8221751e4d6905d37cefc628409f1fb30b7e 100644 (file)
@@ -6,6 +6,15 @@ menu "Character devices"
 
 source "drivers/tty/Kconfig"
 
+config DEVMEM
+       bool "/dev/mem virtual device support"
+       default y
+       help
+         Say Y here if you want to support the /dev/mem device.
+         The /dev/mem device is used to access areas of physical
+         memory.
+         When in doubt, say "Y".
+
 config DEVKMEM
        bool "/dev/kmem virtual device support"
        default y
index e34a019eb9306553c054494ede3376cb4751c103..24cc4ed9a78014509371815cbe0dfda3ef5ca679 100644 (file)
@@ -5,7 +5,8 @@
  *
  * Hwmon integration:
  * Copyright (C) 2011  Jean Delvare <jdelvare@suse.de>
- * Copyright (C) 2013  Guenter Roeck <linux@roeck-us.net>
+ * Copyright (C) 2013, 2014  Guenter Roeck <linux@roeck-us.net>
+ * Copyright (C) 2014  Pali Rohár <pali.rohar@gmail.com>
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -20,6 +21,7 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/init.h>
 #define I8K_SMM_SET_FAN                0x01a3
 #define I8K_SMM_GET_FAN                0x00a3
 #define I8K_SMM_GET_SPEED      0x02a3
+#define I8K_SMM_GET_FAN_TYPE   0x03a3
+#define I8K_SMM_GET_NOM_SPEED  0x04a3
 #define I8K_SMM_GET_TEMP       0x10a3
+#define I8K_SMM_GET_TEMP_TYPE  0x11a3
 #define I8K_SMM_GET_DELL_SIG1  0xfea3
 #define I8K_SMM_GET_DELL_SIG2  0xffa3
 
 #define I8K_FAN_MULT           30
+#define I8K_FAN_MAX_RPM                30000
 #define I8K_MAX_TEMP           127
 
 #define I8K_FN_NONE            0x00
 #define I8K_POWER_AC           0x05
 #define I8K_POWER_BATTERY      0x01
 
-#define I8K_TEMPERATURE_BUG    1
-
 static DEFINE_MUTEX(i8k_mutex);
 static char bios_version[4];
 static struct device *i8k_hwmon_dev;
 static u32 i8k_hwmon_flags;
-static int i8k_fan_mult;
-static int i8k_pwm_mult;
-static int i8k_fan_max = I8K_FAN_HIGH;
+static uint i8k_fan_mult = I8K_FAN_MULT;
+static uint i8k_pwm_mult;
+static uint i8k_fan_max = I8K_FAN_HIGH;
 
 #define I8K_HWMON_HAVE_TEMP1   (1 << 0)
 #define I8K_HWMON_HAVE_TEMP2   (1 << 1)
@@ -95,13 +99,13 @@ static bool power_status;
 module_param(power_status, bool, 0600);
 MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k");
 
-static int fan_mult = I8K_FAN_MULT;
-module_param(fan_mult, int, 0);
-MODULE_PARM_DESC(fan_mult, "Factor to multiply fan speed with");
+static uint fan_mult;
+module_param(fan_mult, uint, 0);
+MODULE_PARM_DESC(fan_mult, "Factor to multiply fan speed with (default: autodetect)");
 
-static int fan_max = I8K_FAN_HIGH;
-module_param(fan_max, int, 0);
-MODULE_PARM_DESC(fan_max, "Maximum configurable fan speed");
+static uint fan_max;
+module_param(fan_max, uint, 0);
+MODULE_PARM_DESC(fan_max, "Maximum configurable fan speed (default: autodetect)");
 
 static int i8k_open_fs(struct inode *inode, struct file *file);
 static long i8k_ioctl(struct file *, unsigned int, unsigned long);
@@ -275,6 +279,28 @@ static int i8k_get_fan_speed(int fan)
        return i8k_smm(&regs) ? : (regs.eax & 0xffff) * i8k_fan_mult;
 }
 
+/*
+ * Read the fan type.
+ */
+static int i8k_get_fan_type(int fan)
+{
+       struct smm_regs regs = { .eax = I8K_SMM_GET_FAN_TYPE, };
+
+       regs.ebx = fan & 0xff;
+       return i8k_smm(&regs) ? : regs.eax & 0xff;
+}
+
+/*
+ * Read the fan nominal rpm for specific fan speed.
+ */
+static int i8k_get_fan_nominal_speed(int fan, int speed)
+{
+       struct smm_regs regs = { .eax = I8K_SMM_GET_NOM_SPEED, };
+
+       regs.ebx = (fan & 0xff) | (speed << 8);
+       return i8k_smm(&regs) ? : (regs.eax & 0xffff) * i8k_fan_mult;
+}
+
 /*
  * Set the fan speed (off, low, high). Returns the new fan status.
  */
@@ -288,42 +314,52 @@ static int i8k_set_fan(int fan, int speed)
        return i8k_smm(&regs) ? : i8k_get_fan_status(fan);
 }
 
+static int i8k_get_temp_type(int sensor)
+{
+       struct smm_regs regs = { .eax = I8K_SMM_GET_TEMP_TYPE, };
+
+       regs.ebx = sensor & 0xff;
+       return i8k_smm(&regs) ? : regs.eax & 0xff;
+}
+
 /*
  * Read the cpu temperature.
  */
-static int i8k_get_temp(int sensor)
+static int _i8k_get_temp(int sensor)
 {
-       struct smm_regs regs = { .eax = I8K_SMM_GET_TEMP, };
-       int rc;
-       int temp;
+       struct smm_regs regs = {
+               .eax = I8K_SMM_GET_TEMP,
+               .ebx = sensor & 0xff,
+       };
 
-#ifdef I8K_TEMPERATURE_BUG
-       static int prev[4] = { I8K_MAX_TEMP+1, I8K_MAX_TEMP+1, I8K_MAX_TEMP+1, I8K_MAX_TEMP+1 };
-#endif
-       regs.ebx = sensor & 0xff;
-       rc = i8k_smm(&regs);
-       if (rc < 0)
-               return rc;
+       return i8k_smm(&regs) ? : regs.eax & 0xff;
+}
 
-       temp = regs.eax & 0xff;
+static int i8k_get_temp(int sensor)
+{
+       int temp = _i8k_get_temp(sensor);
 
-#ifdef I8K_TEMPERATURE_BUG
        /*
         * Sometimes the temperature sensor returns 0x99, which is out of range.
-        * In this case we return (once) the previous cached value. For example:
+        * In this case we retry (once) before returning an error.
         # 1003655137 00000058 00005a4b
         # 1003655138 00000099 00003a80 <--- 0x99 = 153 degrees
         # 1003655139 00000054 00005c52
         */
-       if (temp > I8K_MAX_TEMP) {
-               temp = prev[sensor];
-               prev[sensor] = I8K_MAX_TEMP+1;
-       } else {
-               prev[sensor] = temp;
+       if (temp == 0x99) {
+               msleep(100);
+               temp = _i8k_get_temp(sensor);
        }
+       /*
+        * Return -ENODATA for all invalid temperatures.
+        *
+        * Known instances are the 0x99 value as seen above as well as
+        * 0xc1 (193), which may be returned when trying to read the GPU
+        * temperature if the system supports a GPU and it is currently
+        * turned off.
+        */
        if (temp > I8K_MAX_TEMP)
-               return -ERANGE;
-#endif
+               return -ENODATA;
 
        return temp;
 }
@@ -493,6 +529,29 @@ static int i8k_open_fs(struct inode *inode, struct file *file)
  * Hwmon interface
  */
 
+static ssize_t i8k_hwmon_show_temp_label(struct device *dev,
+                                        struct device_attribute *devattr,
+                                        char *buf)
+{
+       static const char * const labels[] = {
+               "CPU",
+               "GPU",
+               "SODIMM",
+               "Other",
+               "Ambient",
+               "Other",
+       };
+       int index = to_sensor_dev_attr(devattr)->index;
+       int type;
+
+       type = i8k_get_temp_type(index);
+       if (type < 0)
+               return type;
+       if (type >= ARRAY_SIZE(labels))
+               type = ARRAY_SIZE(labels) - 1;
+       return sprintf(buf, "%s\n", labels[type]);
+}
+
 static ssize_t i8k_hwmon_show_temp(struct device *dev,
                                   struct device_attribute *devattr,
                                   char *buf)
@@ -501,13 +560,42 @@ static ssize_t i8k_hwmon_show_temp(struct device *dev,
        int temp;
 
        temp = i8k_get_temp(index);
-       if (temp == -ERANGE)
-               return -EINVAL;
        if (temp < 0)
                return temp;
        return sprintf(buf, "%d\n", temp * 1000);
 }
 
+static ssize_t i8k_hwmon_show_fan_label(struct device *dev,
+                                       struct device_attribute *devattr,
+                                       char *buf)
+{
+       static const char * const labels[] = {
+               "Processor Fan",
+               "Motherboard Fan",
+               "Video Fan",
+               "Power Supply Fan",
+               "Chipset Fan",
+               "Other Fan",
+       };
+       int index = to_sensor_dev_attr(devattr)->index;
+       bool dock = false;
+       int type;
+
+       type = i8k_get_fan_type(index);
+       if (type < 0)
+               return type;
+
+       if (type & 0x10) {
+               dock = true;
+               type &= 0x0F;
+       }
+
+       if (type >= ARRAY_SIZE(labels))
+               type = (ARRAY_SIZE(labels) - 1);
+
+       return sprintf(buf, "%s%s\n", (dock ? "Docking " : ""), labels[type]);
+}
+
 static ssize_t i8k_hwmon_show_fan(struct device *dev,
                                  struct device_attribute *devattr,
                                  char *buf)
@@ -555,45 +643,66 @@ static ssize_t i8k_hwmon_set_pwm(struct device *dev,
 }
 
 static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL,
+                         0);
 static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL,
+                         1);
 static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL,
+                         2);
 static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 3);
-static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, i8k_hwmon_show_fan, NULL,
-                         I8K_FAN_LEFT);
+static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL,
+                         3);
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, i8k_hwmon_show_fan, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan1_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL,
+                         0);
 static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm,
-                         i8k_hwmon_set_pwm, I8K_FAN_LEFT);
+                         i8k_hwmon_set_pwm, 0);
 static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, i8k_hwmon_show_fan, NULL,
-                         I8K_FAN_RIGHT);
+                         1);
+static SENSOR_DEVICE_ATTR(fan2_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL,
+                         1);
 static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm,
-                         i8k_hwmon_set_pwm, I8K_FAN_RIGHT);
+                         i8k_hwmon_set_pwm, 1);
 
 static struct attribute *i8k_attrs[] = {
        &sensor_dev_attr_temp1_input.dev_attr.attr,     /* 0 */
-       &sensor_dev_attr_temp2_input.dev_attr.attr,     /* 1 */
-       &sensor_dev_attr_temp3_input.dev_attr.attr,     /* 2 */
-       &sensor_dev_attr_temp4_input.dev_attr.attr,     /* 3 */
-       &sensor_dev_attr_fan1_input.dev_attr.attr,      /* 4 */
-       &sensor_dev_attr_pwm1.dev_attr.attr,            /* 5 */
-       &sensor_dev_attr_fan2_input.dev_attr.attr,      /* 6 */
-       &sensor_dev_attr_pwm2.dev_attr.attr,            /* 7 */
+       &sensor_dev_attr_temp1_label.dev_attr.attr,     /* 1 */
+       &sensor_dev_attr_temp2_input.dev_attr.attr,     /* 2 */
+       &sensor_dev_attr_temp2_label.dev_attr.attr,     /* 3 */
+       &sensor_dev_attr_temp3_input.dev_attr.attr,     /* 4 */
+       &sensor_dev_attr_temp3_label.dev_attr.attr,     /* 5 */
+       &sensor_dev_attr_temp4_input.dev_attr.attr,     /* 6 */
+       &sensor_dev_attr_temp4_label.dev_attr.attr,     /* 7 */
+       &sensor_dev_attr_fan1_input.dev_attr.attr,      /* 8 */
+       &sensor_dev_attr_fan1_label.dev_attr.attr,      /* 9 */
+       &sensor_dev_attr_pwm1.dev_attr.attr,            /* 10 */
+       &sensor_dev_attr_fan2_input.dev_attr.attr,      /* 11 */
+       &sensor_dev_attr_fan2_label.dev_attr.attr,      /* 12 */
+       &sensor_dev_attr_pwm2.dev_attr.attr,            /* 13 */
        NULL
 };
 
 static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr,
                              int index)
 {
-       if (index == 0 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP1))
+       if (index >= 0 && index <= 1 &&
+           !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP1))
                return 0;
-       if (index == 1 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP2))
+       if (index >= 2 && index <= 3 &&
+           !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP2))
                return 0;
-       if (index == 2 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP3))
+       if (index >= 4 && index <= 5 &&
+           !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP3))
                return 0;
-       if (index == 3 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP4))
+       if (index >= 6 && index <= 7 &&
+           !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP4))
                return 0;
-       if (index >= 4 && index <= 5 &&
+       if (index >= 8 && index <= 10 &&
            !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN1))
                return 0;
-       if (index >= 6 && index <= 7 &&
+       if (index >= 11 && index <= 13 &&
            !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN2))
                return 0;
 
@@ -612,28 +721,28 @@ static int __init i8k_init_hwmon(void)
 
        i8k_hwmon_flags = 0;
 
-       /* CPU temperature attributes, if temperature reading is OK */
-       err = i8k_get_temp(0);
-       if (err >= 0 || err == -ERANGE)
+       /* CPU temperature attributes, if temperature type is OK */
+       err = i8k_get_temp_type(0);
+       if (err >= 0)
                i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP1;
        /* check for additional temperature sensors */
-       err = i8k_get_temp(1);
-       if (err >= 0 || err == -ERANGE)
+       err = i8k_get_temp_type(1);
+       if (err >= 0)
                i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP2;
-       err = i8k_get_temp(2);
-       if (err >= 0 || err == -ERANGE)
+       err = i8k_get_temp_type(2);
+       if (err >= 0)
                i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP3;
-       err = i8k_get_temp(3);
-       if (err >= 0 || err == -ERANGE)
+       err = i8k_get_temp_type(3);
+       if (err >= 0)
                i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP4;
 
-       /* Left fan attributes, if left fan is present */
-       err = i8k_get_fan_status(I8K_FAN_LEFT);
+       /* First fan attributes, if fan type is OK */
+       err = i8k_get_fan_type(0);
        if (err >= 0)
                i8k_hwmon_flags |= I8K_HWMON_HAVE_FAN1;
 
-       /* Right fan attributes, if right fan is present */
-       err = i8k_get_fan_status(I8K_FAN_RIGHT);
+       /* Second fan attributes, if fan type is OK */
+       err = i8k_get_fan_type(1);
        if (err >= 0)
                i8k_hwmon_flags |= I8K_HWMON_HAVE_FAN2;
 
@@ -649,16 +758,15 @@ static int __init i8k_init_hwmon(void)
 }
 
 struct i8k_config_data {
-       int fan_mult;
-       int fan_max;
+       uint fan_mult;
+       uint fan_max;
 };
 
 enum i8k_configs {
        DELL_LATITUDE_D520,
-       DELL_LATITUDE_E6540,
        DELL_PRECISION_490,
        DELL_STUDIO,
-       DELL_XPS_M140,
+       DELL_XPS,
 };
 
 static const struct i8k_config_data i8k_config_data[] = {
@@ -666,10 +774,6 @@ static const struct i8k_config_data i8k_config_data[] = {
                .fan_mult = 1,
                .fan_max = I8K_FAN_TURBO,
        },
-       [DELL_LATITUDE_E6540] = {
-               .fan_mult = 1,
-               .fan_max = I8K_FAN_HIGH,
-       },
        [DELL_PRECISION_490] = {
                .fan_mult = 1,
                .fan_max = I8K_FAN_TURBO,
@@ -678,7 +782,7 @@ static const struct i8k_config_data i8k_config_data[] = {
                .fan_mult = 1,
                .fan_max = I8K_FAN_HIGH,
        },
-       [DELL_XPS_M140] = {
+       [DELL_XPS] = {
                .fan_mult = 1,
                .fan_max = I8K_FAN_HIGH,
        },
@@ -714,22 +818,6 @@ static struct dmi_system_id i8k_dmi_table[] __initdata = {
                },
                .driver_data = (void *)&i8k_config_data[DELL_LATITUDE_D520],
        },
-       {
-               .ident = "Dell Latitude E6440",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6440"),
-               },
-               .driver_data = (void *)&i8k_config_data[DELL_LATITUDE_E6540],
-       },
-       {
-               .ident = "Dell Latitude E6540",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6540"),
-               },
-               .driver_data = (void *)&i8k_config_data[DELL_LATITUDE_E6540],
-       },
        {
                .ident = "Dell Latitude 2",
                .matches = {
@@ -789,13 +877,21 @@ static struct dmi_system_id i8k_dmi_table[] __initdata = {
                },
                .driver_data = (void *)&i8k_config_data[DELL_STUDIO],
        },
+       {
+               .ident = "Dell XPS 13",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "XPS13"),
+               },
+               .driver_data = (void *)&i8k_config_data[DELL_XPS],
+       },
        {
                .ident = "Dell XPS M140",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
                        DMI_MATCH(DMI_PRODUCT_NAME, "MXC051"),
                },
-               .driver_data = (void *)&i8k_config_data[DELL_XPS_M140],
+               .driver_data = (void *)&i8k_config_data[DELL_XPS],
        },
        { }
 };
@@ -808,6 +904,7 @@ MODULE_DEVICE_TABLE(dmi, i8k_dmi_table);
 static int __init i8k_probe(void)
 {
        const struct dmi_system_id *id;
+       int fan, ret;
 
        /*
         * Get DMI information
@@ -836,19 +933,40 @@ static int __init i8k_probe(void)
                        return -ENODEV;
        }
 
-       i8k_fan_mult = fan_mult;
-       i8k_fan_max = fan_max ? : I8K_FAN_HIGH; /* Must not be 0 */
+       /*
+        * Set fan multiplier and maximal fan speed from dmi config
+        * Values specified in module parameters override values from dmi
+        */
        id = dmi_first_match(i8k_dmi_table);
        if (id && id->driver_data) {
                const struct i8k_config_data *conf = id->driver_data;
-
-               if (fan_mult == I8K_FAN_MULT && conf->fan_mult)
-                       i8k_fan_mult = conf->fan_mult;
-               if (fan_max == I8K_FAN_HIGH && conf->fan_max)
-                       i8k_fan_max = conf->fan_max;
+               if (!fan_mult && conf->fan_mult)
+                       fan_mult = conf->fan_mult;
+               if (!fan_max && conf->fan_max)
+                       fan_max = conf->fan_max;
        }
+
+       i8k_fan_max = fan_max ? : I8K_FAN_HIGH; /* Must not be 0 */
        i8k_pwm_mult = DIV_ROUND_UP(255, i8k_fan_max);
 
+       if (!fan_mult) {
+               /*
+                * Autodetect fan multiplier based on nominal rpm
+                * If fan reports rpm value too high then set multiplier to 1
+                */
+               for (fan = 0; fan < 2; ++fan) {
+                       ret = i8k_get_fan_nominal_speed(fan, i8k_fan_max);
+                       if (ret < 0)
+                               continue;
+                       if (ret > I8K_FAN_MAX_RPM)
+                               i8k_fan_mult = 1;
+                       break;
+               }
+       } else {
+               /* Fan multiplier was specified in module param or in dmi */
+               i8k_fan_mult = fan_mult;
+       }
+
        return 0;
 }
 
index 9a6b63783a94dd19a4f49133fd94265fad98c19c..297110c12635d3b8c36b53a7f089aa2666024eca 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/io.h>
 #include <linux/aio.h>
 
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 #ifdef CONFIG_IA64
 # include <linux/efi.h>
@@ -352,7 +352,6 @@ static int mmap_mem(struct file *file, struct vm_area_struct *vma)
        return 0;
 }
 
-#ifdef CONFIG_DEVKMEM
 static int mmap_kmem(struct file *file, struct vm_area_struct *vma)
 {
        unsigned long pfn;
@@ -373,9 +372,7 @@ static int mmap_kmem(struct file *file, struct vm_area_struct *vma)
        vma->vm_pgoff = pfn;
        return mmap_mem(file, vma);
 }
-#endif
 
-#ifdef CONFIG_DEVKMEM
 /*
  * This function reads the *virtual* memory as seen by the kernel.
  */
@@ -555,9 +552,7 @@ static ssize_t write_kmem(struct file *file, const char __user *buf,
        *ppos = p;
        return virtr + wrote ? : err;
 }
-#endif
 
-#ifdef CONFIG_DEVPORT
 static ssize_t read_port(struct file *file, char __user *buf,
                         size_t count, loff_t *ppos)
 {
@@ -586,6 +581,7 @@ static ssize_t write_port(struct file *file, const char __user *buf,
                return -EFAULT;
        while (count-- > 0 && i < 65536) {
                char c;
+
                if (__get_user(c, tmp)) {
                        if (tmp > buf)
                                break;
@@ -598,7 +594,6 @@ static ssize_t write_port(struct file *file, const char __user *buf,
        *ppos = i;
        return tmp-buf;
 }
-#endif
 
 static ssize_t read_null(struct file *file, char __user *buf,
                         size_t count, loff_t *ppos)
@@ -642,6 +637,7 @@ static ssize_t read_iter_zero(struct kiocb *iocb, struct iov_iter *iter)
 
        while (iov_iter_count(iter)) {
                size_t chunk = iov_iter_count(iter), n;
+
                if (chunk > PAGE_SIZE)
                        chunk = PAGE_SIZE;      /* Just for latency reasons */
                n = iov_iter_zero(chunk, iter);
@@ -726,7 +722,7 @@ static int open_port(struct inode *inode, struct file *filp)
 #define open_mem       open_port
 #define open_kmem      open_mem
 
-static const struct file_operations mem_fops = {
+static const struct file_operations __maybe_unused mem_fops = {
        .llseek         = memory_lseek,
        .read           = read_mem,
        .write          = write_mem,
@@ -738,8 +734,7 @@ static const struct file_operations mem_fops = {
 #endif
 };
 
-#ifdef CONFIG_DEVKMEM
-static const struct file_operations kmem_fops = {
+static const struct file_operations __maybe_unused kmem_fops = {
        .llseek         = memory_lseek,
        .read           = read_kmem,
        .write          = write_kmem,
@@ -750,7 +745,6 @@ static const struct file_operations kmem_fops = {
        .mmap_capabilities = memory_mmap_capabilities,
 #endif
 };
-#endif
 
 static const struct file_operations null_fops = {
        .llseek         = null_lseek,
@@ -761,14 +755,12 @@ static const struct file_operations null_fops = {
        .splice_write   = splice_write_null,
 };
 
-#ifdef CONFIG_DEVPORT
-static const struct file_operations port_fops = {
+static const struct file_operations __maybe_unused port_fops = {
        .llseek         = memory_lseek,
        .read           = read_port,
        .write          = write_port,
        .open           = open_port,
 };
-#endif
 
 static const struct file_operations zero_fops = {
        .llseek         = zero_lseek,
@@ -795,7 +787,9 @@ static const struct memdev {
        const struct file_operations *fops;
        fmode_t fmode;
 } devlist[] = {
+#ifdef CONFIG_DEVMEM
         [1] = { "mem", 0, &mem_fops, FMODE_UNSIGNED_OFFSET },
+#endif
 #ifdef CONFIG_DEVKMEM
         [2] = { "kmem", 0, &kmem_fops, FMODE_UNSIGNED_OFFSET },
 #endif
index de03df9dd7c9614e290a7c60ddee6a1564c0f5f2..26afb56a807300026507fdf8624e8a597d1acdc0 100644 (file)
@@ -1986,6 +1986,12 @@ static int virtcons_probe(struct virtio_device *vdev)
        bool multiport;
        bool early = early_put_chars != NULL;
 
+       if (!vdev->config->get) {
+               dev_err(&vdev->dev, "%s failure: config access disabled\n",
+                       __func__);
+               return -EINVAL;
+       }
+
        /* Ensure to read early_put_chars now */
        barrier();
 
index c922d4aded8a3dadd3c91140b573f8f4eed7191f..c9acd406f0d02a4e8223b20d323c028d1938af9b 100644 (file)
@@ -454,7 +454,7 @@ static int etb_probe(struct amba_device *adev, const struct amba_id *id)
        if (ret)
                return ret;
 
-       drvdata->buffer_depth =  etb_get_buffer_depth(drvdata);
+       drvdata->buffer_depth = etb_get_buffer_depth(drvdata);
        clk_disable_unprepare(drvdata->clk);
 
        if (drvdata->buffer_depth < 0)
@@ -521,17 +521,7 @@ static struct amba_driver etb_driver = {
        .id_table       = etb_ids,
 };
 
-static int __init etb_init(void)
-{
-       return amba_driver_register(&etb_driver);
-}
-module_init(etb_init);
-
-static void __exit etb_exit(void)
-{
-       amba_driver_unregister(&etb_driver);
-}
-module_exit(etb_exit);
+module_amba_driver(etb_driver);
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("CoreSight Embedded Trace Buffer driver");
index d9e3ed6aa857b47469759cb32c486a885112e8a2..c965f5724abdb3cfc5d4693c94b26820a4800f05 100644 (file)
 
 #include "coresight-etm.h"
 
-#ifdef CONFIG_CORESIGHT_SOURCE_ETM_DEFAULT_ENABLE
-static int boot_enable = 1;
-#else
 static int boot_enable;
-#endif
-module_param_named(
-       boot_enable, boot_enable, int, S_IRUGO
-);
+module_param_named(boot_enable, boot_enable, int, S_IRUGO);
 
 /* The number of ETM/PTM currently registered */
 static int etm_count;
@@ -573,7 +567,8 @@ static ssize_t mode_store(struct device *dev,
        if (drvdata->mode & ETM_MODE_STALL) {
                if (!(drvdata->etmccr & ETMCCR_FIFOFULL)) {
                        dev_warn(drvdata->dev, "stall mode not supported\n");
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto err_unlock;
                }
                drvdata->ctrl |= ETMCR_STALL_MODE;
         } else
@@ -582,7 +577,8 @@ static ssize_t mode_store(struct device *dev,
        if (drvdata->mode & ETM_MODE_TIMESTAMP) {
                if (!(drvdata->etmccer & ETMCCER_TIMESTAMP)) {
                        dev_warn(drvdata->dev, "timestamp not supported\n");
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto err_unlock;
                }
                drvdata->ctrl |= ETMCR_TIMESTAMP_EN;
        } else
@@ -595,6 +591,10 @@ static ssize_t mode_store(struct device *dev,
        spin_unlock(&drvdata->spinlock);
 
        return size;
+
+err_unlock:
+       spin_unlock(&drvdata->spinlock);
+       return ret;
 }
 static DEVICE_ATTR_RW(mode);
 
@@ -1743,7 +1743,11 @@ static void etm_init_arch_data(void *info)
 
 static void etm_init_default_data(struct etm_drvdata *drvdata)
 {
-       static int etm3x_traceid;
+       /*
+        * A trace ID of value 0 is invalid, so let's start at some
+        * random value that fits in 7 bits and will be just as good.
+        */
+       static int etm3x_traceid = 0x10;
 
        u32 flags = (1 << 0 | /* instruction execute*/
                     3 << 3 | /* ARM instruction */
index 2108edffe1f4f5cceda529fd8049ca6a3caaddfd..3db36f70b6662f3be300df2a4270df7edaecd09e 100644 (file)
@@ -252,17 +252,7 @@ static struct amba_driver funnel_driver = {
        .id_table       = funnel_ids,
 };
 
-static int __init funnel_init(void)
-{
-       return amba_driver_register(&funnel_driver);
-}
-module_init(funnel_init);
-
-static void __exit funnel_exit(void)
-{
-       amba_driver_unregister(&funnel_driver);
-}
-module_exit(funnel_exit);
+module_amba_driver(funnel_driver);
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("CoreSight Funnel driver");
index 7b3372fca4f644c03bc3b292ec537cfad821cd89..62fcd98cc7cfc76798316c3a37a547063ed57955 100644 (file)
@@ -57,7 +57,7 @@ extern int etm_readl_cp14(u32 off, unsigned int *val);
 extern int etm_writel_cp14(u32 off, u32 val);
 #else
 static inline int etm_readl_cp14(u32 off, unsigned int *val) { return 0; }
-static inline int etm_writel_cp14(u32 val, u32 off) { return 0; }
+static inline int etm_writel_cp14(u32 off, u32 val) { return 0; }
 #endif
 
 #endif
index a2dfcf903551b9dc936aae81be01213e342224ed..cdf05537d57482ebdc83e428ebc41854650f3e39 100644 (file)
@@ -87,7 +87,7 @@ static int replicator_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        desc->type = CORESIGHT_DEV_TYPE_LINK;
-       desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT;
+       desc->subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT;
        desc->ops = &replicator_cs_ops;
        desc->pdata = pdev->dev.platform_data;
        desc->dev = &pdev->dev;
index ce2c293f17074eea85ba9c1a9bb537ac22a230b7..3ff232f9ddf78c5a3c4f6146b1ec2dac7aef87b0 100644 (file)
@@ -760,17 +760,7 @@ static struct amba_driver tmc_driver = {
        .id_table       = tmc_ids,
 };
 
-static int __init tmc_init(void)
-{
-       return amba_driver_register(&tmc_driver);
-}
-module_init(tmc_init);
-
-static void __exit tmc_exit(void)
-{
-       amba_driver_unregister(&tmc_driver);
-}
-module_exit(tmc_exit);
+module_amba_driver(tmc_driver);
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("CoreSight Trace Memory Controller driver");
index ae101082791a2c36a26644b6263a5cbf2d0eb416..3b33af2416bb4da64d2037b96edb6699affe17e9 100644 (file)
@@ -201,17 +201,7 @@ static struct amba_driver tpiu_driver = {
        .id_table       = tpiu_ids,
 };
 
-static int __init tpiu_init(void)
-{
-       return amba_driver_register(&tpiu_driver);
-}
-module_init(tpiu_init);
-
-static void __exit tpiu_exit(void)
-{
-       amba_driver_unregister(&tpiu_driver);
-}
-module_exit(tpiu_exit);
+module_amba_driver(tpiu_driver);
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("CoreSight Trace Port Interface Unit driver");
index 6e0181f844258113358cbfc7988cdabd1bb58774..c5def93823570d72b5962be46e07c5a89c1ac892 100644 (file)
@@ -498,17 +498,18 @@ static int coresight_orphan_match(struct device *dev, void *data)
         * Circle throuch all the connection of that component.  If we find
         * an orphan connection whose name matches @csdev, link it.
         */
-       for (i = 0; i < i_csdev->nr_outport; i++)       {
+       for (i = 0; i < i_csdev->nr_outport; i++) {
                conn = &i_csdev->conns[i];
 
                /* We have found at least one orphan connection */
                if (conn->child_dev == NULL) {
                        /* Does it match this newly added device? */
-                       if (!strcmp(dev_name(&csdev->dev), conn->child_name))
+                       if (!strcmp(dev_name(&csdev->dev), conn->child_name)) {
                                conn->child_dev = csdev;
-               } else {
-                       /* Too bad, this component still has an orphan */
-                       still_orphan = true;
+                       } else {
+                               /* This component still has an orphan */
+                               still_orphan = true;
+                       }
                }
        }
 
index 5030c073450831a7f37f89b12c35934bdb1d9f97..c3efa418a86d8eda8f715cecd97382deb965a8e8 100644 (file)
@@ -93,7 +93,7 @@ static int of_coresight_alloc_memory(struct device *dev,
        if (!pdata->outports)
                return -ENOMEM;
 
-       /* Children connected to this component via @outport */
+       /* Children connected to this component via @outports */
         pdata->child_names = devm_kzalloc(dev, pdata->nr_outport *
                                          sizeof(*pdata->child_names),
                                          GFP_KERNEL);
@@ -117,7 +117,7 @@ struct coresight_platform_data *of_get_coresight_platform_data(
        struct coresight_platform_data *pdata;
        struct of_endpoint endpoint, rendpoint;
        struct device *rdev;
-       struct device_node *cpu;
+       struct device_node *dn;
        struct device_node *ep = NULL;
        struct device_node *rparent = NULL;
        struct device_node *rport = NULL;
@@ -126,7 +126,7 @@ struct coresight_platform_data *of_get_coresight_platform_data(
        if (!pdata)
                return ERR_PTR(-ENOMEM);
 
-       /* Use device name as debugfs handle */
+       /* Use device name as sysfs handle */
        pdata->name = dev_name(dev);
 
        /* Get the number of input and output port for this component */
@@ -174,7 +174,7 @@ struct coresight_platform_data *of_get_coresight_platform_data(
                                continue;
 
                        rdev = of_coresight_get_endpoint_device(rparent);
-                       if (!dev)
+                       if (!rdev)
                                continue;
 
                        pdata->child_names[i] = dev_name(rdev);
@@ -186,14 +186,16 @@ struct coresight_platform_data *of_get_coresight_platform_data(
 
        /* Affinity defaults to CPU0 */
        pdata->cpu = 0;
-       cpu = of_parse_phandle(node, "cpu", 0);
-       if (cpu) {
-               const u32 *mpidr;
+       dn = of_parse_phandle(node, "cpu", 0);
+       if (dn) {
+               const u32 *cell;
                int len, index;
+               u64 hwid;
 
-               mpidr = of_get_property(cpu, "reg", &len);
-               if (mpidr && len == 4) {
-                       index = get_logical_index(be32_to_cpup(mpidr));
+               cell = of_get_property(dn, "reg", &len);
+               if (cell) {
+                       hwid = of_read_number(cell, of_n_addr_cells(dn));
+                       index = get_logical_index(hwid);
                        if (index != -EINVAL)
                                pdata->cpu = index;
                }
index 5d7ab577fba94602e638270cb2e4d34d189ef565..2bb82e55065aa3e7d615b6b1c2e46286df0d9d4e 100644 (file)
@@ -173,6 +173,7 @@ static int adc_jack_remove(struct platform_device *pdev)
 
        free_irq(data->irq, data);
        cancel_work_sync(&data->handler.work);
+       iio_channel_release(data->chan);
 
        return 0;
 }
index 043dcd9946c92ef1f965715a103eeb5ae449bd68..8319f25b7145fb6c5dbe1d1f31fa384b1e086b7b 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/of.h>
 #include <linux/slab.h>
 #include <linux/sysfs.h>
-#include <linux/of.h>
 
 /*
  * extcon_cable_name suggests the standard cable names for commonly used
index 740a14d35072a5aaf2d657d6dae628cade715200..af165fd0c6f54761a56d1cf75d81663173ff400a 100644 (file)
@@ -1033,7 +1033,7 @@ static irqreturn_t max77693_muic_irq_handler(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static struct regmap_config max77693_muic_regmap_config = {
+static const struct regmap_config max77693_muic_regmap_config = {
        .reg_bits = 8,
        .val_bits = 8,
 };
index 433f72a1c0062be9b13dff78b6885d37a80a8738..2978f5ee8d2a0abdeacdc8f7fc2121d35c0260a2 100644 (file)
@@ -73,14 +73,14 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
        unsigned long flags;
        int ret, t, err = 0;
 
-       spin_lock_irqsave(&newchannel->sc_lock, flags);
+       spin_lock_irqsave(&newchannel->lock, flags);
        if (newchannel->state == CHANNEL_OPEN_STATE) {
                newchannel->state = CHANNEL_OPENING_STATE;
        } else {
-               spin_unlock_irqrestore(&newchannel->sc_lock, flags);
+               spin_unlock_irqrestore(&newchannel->lock, flags);
                return -EINVAL;
        }
-       spin_unlock_irqrestore(&newchannel->sc_lock, flags);
+       spin_unlock_irqrestore(&newchannel->lock, flags);
 
        newchannel->onchannel_callback = onchannelcallback;
        newchannel->channel_callback_context = context;
@@ -366,8 +366,8 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer,
        unsigned long flags;
        int ret = 0;
 
-       next_gpadl_handle = atomic_read(&vmbus_connection.next_gpadl_handle);
-       atomic_inc(&vmbus_connection.next_gpadl_handle);
+       next_gpadl_handle =
+               (atomic_inc_return(&vmbus_connection.next_gpadl_handle) - 1);
 
        ret = create_gpadl_header(kbuffer, size, &msginfo, &msgcount);
        if (ret)
@@ -683,6 +683,50 @@ int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel,
 }
 EXPORT_SYMBOL_GPL(vmbus_sendpacket_pagebuffer);
 
+/*
+ * vmbus_sendpacket_multipagebuffer - Send a multi-page buffer packet
+ * using a GPADL Direct packet type.
+ * The buffer includes the vmbus descriptor.
+ */
+int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel,
+                             struct vmbus_packet_mpb_array *desc,
+                             u32 desc_size,
+                             void *buffer, u32 bufferlen, u64 requestid)
+{
+       int ret;
+       u32 packetlen;
+       u32 packetlen_aligned;
+       struct kvec bufferlist[3];
+       u64 aligned_data = 0;
+       bool signal = false;
+
+       packetlen = desc_size + bufferlen;
+       packetlen_aligned = ALIGN(packetlen, sizeof(u64));
+
+       /* Setup the descriptor */
+       desc->type = VM_PKT_DATA_USING_GPA_DIRECT;
+       desc->flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
+       desc->dataoffset8 = desc_size >> 3; /* in 8-bytes grandularity */
+       desc->length8 = (u16)(packetlen_aligned >> 3);
+       desc->transactionid = requestid;
+       desc->rangecount = 1;
+
+       bufferlist[0].iov_base = desc;
+       bufferlist[0].iov_len = desc_size;
+       bufferlist[1].iov_base = buffer;
+       bufferlist[1].iov_len = bufferlen;
+       bufferlist[2].iov_base = &aligned_data;
+       bufferlist[2].iov_len = (packetlen_aligned - packetlen);
+
+       ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal);
+
+       if (ret == 0 && signal)
+               vmbus_setevent(channel);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(vmbus_sendpacket_mpb_desc);
+
 /*
  * vmbus_sendpacket_multipagebuffer - Send a multi-page buffer packet
  * using a GPADL Direct packet type.
index 2c59f030546b0cf8beef508cdbedb96298484744..3736f71bdec5ba3ea314fd2f0ae069dfb70133bf 100644 (file)
@@ -146,7 +146,7 @@ static struct vmbus_channel *alloc_channel(void)
                return NULL;
 
        spin_lock_init(&channel->inbound_lock);
-       spin_lock_init(&channel->sc_lock);
+       spin_lock_init(&channel->lock);
 
        INIT_LIST_HEAD(&channel->sc_list);
        INIT_LIST_HEAD(&channel->percpu_list);
@@ -246,9 +246,9 @@ static void vmbus_process_rescind_offer(struct work_struct *work)
                spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
        } else {
                primary_channel = channel->primary_channel;
-               spin_lock_irqsave(&primary_channel->sc_lock, flags);
+               spin_lock_irqsave(&primary_channel->lock, flags);
                list_del(&channel->sc_list);
-               spin_unlock_irqrestore(&primary_channel->sc_lock, flags);
+               spin_unlock_irqrestore(&primary_channel->lock, flags);
        }
        free_channel(channel);
 }
@@ -279,9 +279,6 @@ static void vmbus_process_offer(struct work_struct *work)
        int ret;
        unsigned long flags;
 
-       /* The next possible work is rescind handling */
-       INIT_WORK(&newchannel->work, vmbus_process_rescind_offer);
-
        /* Make sure this is a new offer */
        spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
 
@@ -323,9 +320,9 @@ static void vmbus_process_offer(struct work_struct *work)
                         * Process the sub-channel.
                         */
                        newchannel->primary_channel = channel;
-                       spin_lock_irqsave(&channel->sc_lock, flags);
+                       spin_lock_irqsave(&channel->lock, flags);
                        list_add_tail(&newchannel->sc_list, &channel->sc_list);
-                       spin_unlock_irqrestore(&channel->sc_lock, flags);
+                       spin_unlock_irqrestore(&channel->lock, flags);
 
                        if (newchannel->target_cpu != get_cpu()) {
                                put_cpu();
@@ -341,11 +338,10 @@ static void vmbus_process_offer(struct work_struct *work)
                        if (channel->sc_creation_callback != NULL)
                                channel->sc_creation_callback(newchannel);
 
-                       return;
+                       goto done_init_rescind;
                }
 
-               free_channel(newchannel);
-               return;
+               goto err_free_chan;
        }
 
        /*
@@ -364,6 +360,8 @@ static void vmbus_process_offer(struct work_struct *work)
                &newchannel->offermsg.offer.if_type,
                &newchannel->offermsg.offer.if_instance,
                newchannel);
+       if (!newchannel->device_obj)
+               goto err_free_chan;
 
        /*
         * Add the new device to the bus. This will kick off device-driver
@@ -379,9 +377,19 @@ static void vmbus_process_offer(struct work_struct *work)
                list_del(&newchannel->listentry);
                spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
                kfree(newchannel->device_obj);
-
-               free_channel(newchannel);
+               goto err_free_chan;
        }
+done_init_rescind:
+       spin_lock_irqsave(&newchannel->lock, flags);
+       /* The next possible work is rescind handling */
+       INIT_WORK(&newchannel->work, vmbus_process_rescind_offer);
+       /* Check if rescind offer was already received */
+       if (newchannel->rescind)
+               queue_work(newchannel->controlwq, &newchannel->work);
+       spin_unlock_irqrestore(&newchannel->lock, flags);
+       return;
+err_free_chan:
+       free_channel(newchannel);
 }
 
 enum {
@@ -516,6 +524,7 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
 {
        struct vmbus_channel_rescind_offer *rescind;
        struct vmbus_channel *channel;
+       unsigned long flags;
 
        rescind = (struct vmbus_channel_rescind_offer *)hdr;
        channel = relid2channel(rescind->child_relid);
@@ -524,11 +533,20 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
                /* Just return here, no channel found */
                return;
 
+       spin_lock_irqsave(&channel->lock, flags);
        channel->rescind = true;
+       /*
+        * channel->work.func != vmbus_process_rescind_offer means we are still
+        * processing offer request and the rescind offer processing should be
+        * postponed. It will be done at the very end of vmbus_process_offer()
+        * as rescind flag is being checked there.
+        */
+       if (channel->work.func == vmbus_process_rescind_offer)
+               /* work is initialized for vmbus_process_rescind_offer() from
+                * vmbus_process_offer() where the channel got created */
+               queue_work(channel->controlwq, &channel->work);
 
-       /* work is initialized for vmbus_process_rescind_offer() from
-        * vmbus_process_offer() where the channel got created */
-       queue_work(channel->controlwq, &channel->work);
+       spin_unlock_irqrestore(&channel->lock, flags);
 }
 
 /*
@@ -815,7 +833,7 @@ cleanup:
 struct vmbus_channel *vmbus_get_outgoing_channel(struct vmbus_channel *primary)
 {
        struct list_head *cur, *tmp;
-       int cur_cpu = hv_context.vp_index[smp_processor_id()];
+       int cur_cpu;
        struct vmbus_channel *cur_channel;
        struct vmbus_channel *outgoing_channel = primary;
        int cpu_distance, new_cpu_distance;
@@ -823,6 +841,8 @@ struct vmbus_channel *vmbus_get_outgoing_channel(struct vmbus_channel *primary)
        if (list_empty(&primary->sc_list))
                return outgoing_channel;
 
+       cur_cpu = hv_context.vp_index[get_cpu()];
+       put_cpu();
        list_for_each_safe(cur, tmp, &primary->sc_list) {
                cur_channel = list_entry(cur, struct vmbus_channel, sc_list);
                if (cur_channel->state != CHANNEL_OPENED_STATE)
index e206619b946e577ff79b65a7273cfe5784964649..a63a795300b9ebbec393154fdfdce27e38ad3b0c 100644 (file)
@@ -80,8 +80,10 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo,
        msg->interrupt_page = virt_to_phys(vmbus_connection.int_page);
        msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages[0]);
        msg->monitor_page2 = virt_to_phys(vmbus_connection.monitor_pages[1]);
-       if (version == VERSION_WIN8_1)
-               msg->target_vcpu = hv_context.vp_index[smp_processor_id()];
+       if (version == VERSION_WIN8_1) {
+               msg->target_vcpu = hv_context.vp_index[get_cpu()];
+               put_cpu();
+       }
 
        /*
         * Add to list before we send the request since we may
index 3e4235c7a47fd30697b4c6d1e9b37b3bf55b7e6b..50e51a51ff8bde317def929e744a810e2ccaa62d 100644 (file)
@@ -28,7 +28,9 @@
 #include <linux/hyperv.h>
 #include <linux/version.h>
 #include <linux/interrupt.h>
+#include <linux/clockchips.h>
 #include <asm/hyperv.h>
+#include <asm/mshyperv.h>
 #include "hyperv_vmbus.h"
 
 /* The one and only */
@@ -37,6 +39,10 @@ struct hv_context hv_context = {
        .hypercall_page         = NULL,
 };
 
+#define HV_TIMER_FREQUENCY (10 * 1000 * 1000) /* 100ns period */
+#define HV_MAX_MAX_DELTA_TICKS 0xffffffff
+#define HV_MIN_DELTA_TICKS 1
+
 /*
  * query_hypervisor_info - Get version info of the windows hypervisor
  */
@@ -144,6 +150,8 @@ int hv_init(void)
               sizeof(int) * NR_CPUS);
        memset(hv_context.event_dpc, 0,
               sizeof(void *) * NR_CPUS);
+       memset(hv_context.clk_evt, 0,
+              sizeof(void *) * NR_CPUS);
 
        max_leaf = query_hypervisor_info();
 
@@ -258,10 +266,63 @@ u16 hv_signal_event(void *con_id)
        return status;
 }
 
+static int hv_ce_set_next_event(unsigned long delta,
+                               struct clock_event_device *evt)
+{
+       cycle_t current_tick;
+
+       WARN_ON(evt->mode != CLOCK_EVT_MODE_ONESHOT);
+
+       rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick);
+       current_tick += delta;
+       wrmsrl(HV_X64_MSR_STIMER0_COUNT, current_tick);
+       return 0;
+}
+
+static void hv_ce_setmode(enum clock_event_mode mode,
+                         struct clock_event_device *evt)
+{
+       union hv_timer_config timer_cfg;
+
+       switch (mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+               /* unsupported */
+               break;
+
+       case CLOCK_EVT_MODE_ONESHOT:
+               timer_cfg.enable = 1;
+               timer_cfg.auto_enable = 1;
+               timer_cfg.sintx = VMBUS_MESSAGE_SINT;
+               wrmsrl(HV_X64_MSR_STIMER0_CONFIG, timer_cfg.as_uint64);
+               break;
+
+       case CLOCK_EVT_MODE_UNUSED:
+       case CLOCK_EVT_MODE_SHUTDOWN:
+               wrmsrl(HV_X64_MSR_STIMER0_COUNT, 0);
+               wrmsrl(HV_X64_MSR_STIMER0_CONFIG, 0);
+               break;
+       case CLOCK_EVT_MODE_RESUME:
+               break;
+       }
+}
+
+static void hv_init_clockevent_device(struct clock_event_device *dev, int cpu)
+{
+       dev->name = "Hyper-V clockevent";
+       dev->features = CLOCK_EVT_FEAT_ONESHOT;
+       dev->cpumask = cpumask_of(cpu);
+       dev->rating = 1000;
+       dev->owner = THIS_MODULE;
+
+       dev->set_mode = hv_ce_setmode;
+       dev->set_next_event = hv_ce_set_next_event;
+}
+
 
 int hv_synic_alloc(void)
 {
        size_t size = sizeof(struct tasklet_struct);
+       size_t ced_size = sizeof(struct clock_event_device);
        int cpu;
 
        for_each_online_cpu(cpu) {
@@ -272,6 +333,13 @@ int hv_synic_alloc(void)
                }
                tasklet_init(hv_context.event_dpc[cpu], vmbus_on_event, cpu);
 
+               hv_context.clk_evt[cpu] = kzalloc(ced_size, GFP_ATOMIC);
+               if (hv_context.clk_evt[cpu] == NULL) {
+                       pr_err("Unable to allocate clock event device\n");
+                       goto err;
+               }
+               hv_init_clockevent_device(hv_context.clk_evt[cpu], cpu);
+
                hv_context.synic_message_page[cpu] =
                        (void *)get_zeroed_page(GFP_ATOMIC);
 
@@ -305,6 +373,7 @@ err:
 static void hv_synic_free_cpu(int cpu)
 {
        kfree(hv_context.event_dpc[cpu]);
+       kfree(hv_context.clk_evt[cpu]);
        if (hv_context.synic_event_page[cpu])
                free_page((unsigned long)hv_context.synic_event_page[cpu]);
        if (hv_context.synic_message_page[cpu])
@@ -388,6 +457,15 @@ void hv_synic_init(void *arg)
        hv_context.vp_index[cpu] = (u32)vp_index;
 
        INIT_LIST_HEAD(&hv_context.percpu_list[cpu]);
+
+       /*
+        * Register the per-cpu clockevent source.
+        */
+       if (ms_hyperv.features & HV_X64_MSR_SYNTIMER_AVAILABLE)
+               clockevents_config_and_register(hv_context.clk_evt[cpu],
+                                               HV_TIMER_FREQUENCY,
+                                               HV_MIN_DELTA_TICKS,
+                                               HV_MAX_MAX_DELTA_TICKS);
        return;
 }
 
index b958ded8ac7e9ffef85dbc3b8547746a5cf26367..ff169386b2c716bc04c8dcd03f54ad28615cc9de 100644 (file)
@@ -533,6 +533,9 @@ struct hv_dynmem_device {
         */
        struct task_struct *thread;
 
+       struct mutex ha_region_mutex;
+       struct completion waiter_event;
+
        /*
         * A list of hot-add regions.
         */
@@ -549,7 +552,59 @@ struct hv_dynmem_device {
 static struct hv_dynmem_device dm_device;
 
 static void post_status(struct hv_dynmem_device *dm);
+
 #ifdef CONFIG_MEMORY_HOTPLUG
+static void acquire_region_mutex(bool trylock)
+{
+       if (trylock) {
+               reinit_completion(&dm_device.waiter_event);
+               while (!mutex_trylock(&dm_device.ha_region_mutex))
+                       wait_for_completion(&dm_device.waiter_event);
+       } else {
+               mutex_lock(&dm_device.ha_region_mutex);
+       }
+}
+
+static void release_region_mutex(bool trylock)
+{
+       if (trylock) {
+               mutex_unlock(&dm_device.ha_region_mutex);
+       } else {
+               mutex_unlock(&dm_device.ha_region_mutex);
+               complete(&dm_device.waiter_event);
+       }
+}
+
+static int hv_memory_notifier(struct notifier_block *nb, unsigned long val,
+                             void *v)
+{
+       switch (val) {
+       case MEM_GOING_ONLINE:
+               acquire_region_mutex(true);
+               break;
+
+       case MEM_ONLINE:
+       case MEM_CANCEL_ONLINE:
+               release_region_mutex(true);
+               if (dm_device.ha_waiting) {
+                       dm_device.ha_waiting = false;
+                       complete(&dm_device.ol_waitevent);
+               }
+               break;
+
+       case MEM_GOING_OFFLINE:
+       case MEM_OFFLINE:
+       case MEM_CANCEL_OFFLINE:
+               break;
+       }
+       return NOTIFY_OK;
+}
+
+static struct notifier_block hv_memory_nb = {
+       .notifier_call = hv_memory_notifier,
+       .priority = 0
+};
+
 
 static void hv_bring_pgs_online(unsigned long start_pfn, unsigned long size)
 {
@@ -591,6 +646,7 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size,
                init_completion(&dm_device.ol_waitevent);
                dm_device.ha_waiting = true;
 
+               release_region_mutex(false);
                nid = memory_add_physaddr_to_nid(PFN_PHYS(start_pfn));
                ret = add_memory(nid, PFN_PHYS((start_pfn)),
                                (HA_CHUNK << PAGE_SHIFT));
@@ -619,6 +675,7 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size,
                 * have not been "onlined" within the allowed time.
                 */
                wait_for_completion_timeout(&dm_device.ol_waitevent, 5*HZ);
+               acquire_region_mutex(false);
                post_status(&dm_device);
        }
 
@@ -632,11 +689,6 @@ static void hv_online_page(struct page *pg)
        unsigned long cur_start_pgp;
        unsigned long cur_end_pgp;
 
-       if (dm_device.ha_waiting) {
-               dm_device.ha_waiting = false;
-               complete(&dm_device.ol_waitevent);
-       }
-
        list_for_each(cur, &dm_device.ha_region_list) {
                has = list_entry(cur, struct hv_hotadd_state, list);
                cur_start_pgp = (unsigned long)
@@ -834,6 +886,7 @@ static void hot_add_req(struct work_struct *dummy)
        resp.hdr.size = sizeof(struct dm_hot_add_response);
 
 #ifdef CONFIG_MEMORY_HOTPLUG
+       acquire_region_mutex(false);
        pg_start = dm->ha_wrk.ha_page_range.finfo.start_page;
        pfn_cnt = dm->ha_wrk.ha_page_range.finfo.page_cnt;
 
@@ -865,6 +918,7 @@ static void hot_add_req(struct work_struct *dummy)
        if (do_hot_add)
                resp.page_count = process_hot_add(pg_start, pfn_cnt,
                                                rg_start, rg_sz);
+       release_region_mutex(false);
 #endif
        /*
         * The result field of the response structure has the
@@ -928,9 +982,8 @@ static unsigned long compute_balloon_floor(void)
         *     128        72    (1/2)
         *     512       168    (1/4)
         *    2048       360    (1/8)
-        *    8192       552    (1/32)
-        *   32768      1320
-        *  131072      4392
+        *    8192       768    (1/16)
+        *   32768      1536    (1/32)
         */
        if (totalram_pages < MB2PAGES(128))
                min_pages = MB2PAGES(8) + (totalram_pages >> 1);
@@ -938,8 +991,10 @@ static unsigned long compute_balloon_floor(void)
                min_pages = MB2PAGES(40) + (totalram_pages >> 2);
        else if (totalram_pages < MB2PAGES(2048))
                min_pages = MB2PAGES(104) + (totalram_pages >> 3);
+       else if (totalram_pages < MB2PAGES(8192))
+               min_pages = MB2PAGES(256) + (totalram_pages >> 4);
        else
-               min_pages = MB2PAGES(296) + (totalram_pages >> 5);
+               min_pages = MB2PAGES(512) + (totalram_pages >> 5);
 #undef MB2PAGES
        return min_pages;
 }
@@ -1171,7 +1226,7 @@ static void balloon_down(struct hv_dynmem_device *dm,
 
        for (i = 0; i < range_count; i++) {
                free_balloon_pages(dm, &range_array[i]);
-               post_status(&dm_device);
+               complete(&dm_device.config_event);
        }
 
        if (req->more_pages == 1)
@@ -1195,19 +1250,16 @@ static void balloon_onchannelcallback(void *context);
 static int dm_thread_func(void *dm_dev)
 {
        struct hv_dynmem_device *dm = dm_dev;
-       int t;
 
        while (!kthread_should_stop()) {
-               t = wait_for_completion_interruptible_timeout(
+               wait_for_completion_interruptible_timeout(
                                                &dm_device.config_event, 1*HZ);
                /*
                 * The host expects us to post information on the memory
                 * pressure every second.
                 */
-
-               if (t == 0)
-                       post_status(dm);
-
+               reinit_completion(&dm_device.config_event);
+               post_status(dm);
        }
 
        return 0;
@@ -1387,7 +1439,9 @@ static int balloon_probe(struct hv_device *dev,
        dm_device.next_version = DYNMEM_PROTOCOL_VERSION_WIN7;
        init_completion(&dm_device.host_event);
        init_completion(&dm_device.config_event);
+       init_completion(&dm_device.waiter_event);
        INIT_LIST_HEAD(&dm_device.ha_region_list);
+       mutex_init(&dm_device.ha_region_mutex);
        INIT_WORK(&dm_device.balloon_wrk.wrk, balloon_up);
        INIT_WORK(&dm_device.ha_wrk.wrk, hot_add_req);
        dm_device.host_specified_ha_region = false;
@@ -1401,6 +1455,7 @@ static int balloon_probe(struct hv_device *dev,
 
 #ifdef CONFIG_MEMORY_HOTPLUG
        set_online_page_callback(&hv_online_page);
+       register_memory_notifier(&hv_memory_nb);
 #endif
 
        hv_set_drvdata(dev, &dm_device);
@@ -1519,6 +1574,7 @@ static int balloon_remove(struct hv_device *dev)
        kfree(send_buffer);
 #ifdef CONFIG_MEMORY_HOTPLUG
        restore_online_page_callback(&hv_online_page);
+       unregister_memory_notifier(&hv_memory_nb);
 #endif
        list_for_each_safe(cur, tmp, &dm->ha_region_list) {
                has = list_entry(cur, struct hv_hotadd_state, list);
index 23b2ce294c4ca78ea3f961ee102550e4aeb02632..cd453e4b2a07e74509e1300fdd5afa48b9abe05a 100644 (file)
@@ -86,6 +86,18 @@ static void fcopy_work_func(struct work_struct *dummy)
         * process the pending transaction.
         */
        fcopy_respond_to_host(HV_E_FAIL);
+
+       /* In the case the user-space daemon crashes, hangs or is killed, we
+        * need to down the semaphore, otherwise, after the daemon starts next
+        * time, the obsolete data in fcopy_transaction.message or
+        * fcopy_transaction.fcopy_msg will be used immediately.
+        *
+        * NOTE: fcopy_read() happens to get the semaphore (very rare)? We're
+        * still OK, because we've reported the failure to the host.
+        */
+       if (down_trylock(&fcopy_transaction.read_sema))
+               ;
+
 }
 
 static int fcopy_handle_handshake(u32 version)
@@ -344,6 +356,14 @@ static int fcopy_open(struct inode *inode, struct file *f)
        return 0;
 }
 
+/* XXX: there are still some tricky corner cases, e.g.,
+ * 1) In a SMP guest, when fcopy_release() runs between
+ * schedule_delayed_work() and fcopy_send_data(), there is
+ * still a chance an obsolete message will be queued.
+ *
+ * 2) When the fcopy daemon is running, if we unload the driver,
+ * we'll notice a kernel oops when we kill the daemon later.
+ */
 static int fcopy_release(struct inode *inode, struct file *f)
 {
        /*
@@ -351,6 +371,13 @@ static int fcopy_release(struct inode *inode, struct file *f)
         */
        in_hand_shake = true;
        opened = false;
+
+       if (cancel_delayed_work_sync(&fcopy_work)) {
+               /* We haven't up()-ed the semaphore(very rare)? */
+               if (down_trylock(&fcopy_transaction.read_sema))
+                       ;
+               fcopy_respond_to_host(HV_E_FAIL);
+       }
        return 0;
 }
 
index c386d8dc7223a2103ca2904ffc0a90ef026c156d..44b1c94247129b8e1d17467b4871c919b5a2b40f 100644 (file)
@@ -178,6 +178,23 @@ struct hv_message_header {
        };
 };
 
+/*
+ * Timer configuration register.
+ */
+union hv_timer_config {
+       u64 as_uint64;
+       struct {
+               u64 enable:1;
+               u64 periodic:1;
+               u64 lazy:1;
+               u64 auto_enable:1;
+               u64 reserved_z0:12;
+               u64 sintx:4;
+               u64 reserved_z1:44;
+       };
+};
+
+
 /* Define timer message payload structure. */
 struct hv_timer_message_payload {
        u32 timer_index;
@@ -519,6 +536,10 @@ struct hv_context {
         * buffer to post messages to the host.
         */
        void *post_msg_page[NR_CPUS];
+       /*
+        * Support PV clockevent device.
+        */
+       struct clock_event_device *clk_evt[NR_CPUS];
 };
 
 extern struct hv_context hv_context;
index bb3725b672cf0d58d4eb9d58efca7f85d8b32ef7..f518b8d7a5b5190eb01b741d0961f6b9fbf6cd33 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/completion.h>
 #include <linux/hyperv.h>
 #include <linux/kernel_stat.h>
+#include <linux/clockchips.h>
 #include <asm/hyperv.h>
 #include <asm/hypervisor.h>
 #include <asm/mshyperv.h>
@@ -578,6 +579,34 @@ static void vmbus_onmessage_work(struct work_struct *work)
        kfree(ctx);
 }
 
+static void hv_process_timer_expiration(struct hv_message *msg, int cpu)
+{
+       struct clock_event_device *dev = hv_context.clk_evt[cpu];
+
+       if (dev->event_handler)
+               dev->event_handler(dev);
+
+       msg->header.message_type = HVMSG_NONE;
+
+       /*
+        * Make sure the write to MessageType (ie set to
+        * HVMSG_NONE) happens before we read the
+        * MessagePending and EOMing. Otherwise, the EOMing
+        * will not deliver any more messages since there is
+        * no empty slot
+        */
+       mb();
+
+       if (msg->header.message_flags.msg_pending) {
+               /*
+                * This will cause message queue rescan to
+                * possibly deliver another msg from the
+                * hypervisor
+                */
+               wrmsrl(HV_X64_MSR_EOM, 0);
+       }
+}
+
 static void vmbus_on_msg_dpc(unsigned long data)
 {
        int cpu = smp_processor_id();
@@ -667,8 +696,12 @@ static void vmbus_isr(void)
        msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT;
 
        /* Check if there are actual msgs to be processed */
-       if (msg->header.message_type != HVMSG_NONE)
-               tasklet_schedule(&msg_dpc);
+       if (msg->header.message_type != HVMSG_NONE) {
+               if (msg->header.message_type == HVMSG_TIMER_EXPIRED)
+                       hv_process_timer_expiration(msg, cpu);
+               else
+                       tasklet_schedule(&msg_dpc);
+       }
 }
 
 /*
index 5e1bd5db02c8ee7f21e0de9b778d2d1bb17a2d6c..0af7361e377f61565258346f3f84a3933b9f15ba 100644 (file)
@@ -51,7 +51,7 @@ static int mcb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        priv->mapbase = pci_resource_start(pdev, 0);
        if (!priv->mapbase) {
                dev_err(&pdev->dev, "No PCI resource\n");
-               goto err_start;
+               goto out_disable;
        }
 
        res = request_mem_region(priv->mapbase, CHAM_HEADER_SIZE,
@@ -59,14 +59,14 @@ static int mcb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        if (IS_ERR(res)) {
                dev_err(&pdev->dev, "Failed to request PCI memory\n");
                ret = PTR_ERR(res);
-               goto err_start;
+               goto out_disable;
        }
 
        priv->base = ioremap(priv->mapbase, CHAM_HEADER_SIZE);
        if (!priv->base) {
                dev_err(&pdev->dev, "Cannot ioremap\n");
                ret = -ENOMEM;
-               goto err_ioremap;
+               goto out_release;
        }
 
        flags = pci_resource_flags(pdev, 0);
@@ -74,7 +74,7 @@ static int mcb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                ret = -ENOTSUPP;
                dev_err(&pdev->dev,
                        "IO mapped PCI devices are not supported\n");
-               goto err_ioremap;
+               goto out_release;
        }
 
        pci_set_drvdata(pdev, priv);
@@ -82,14 +82,14 @@ static int mcb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        priv->bus = mcb_alloc_bus(&pdev->dev);
        if (IS_ERR(priv->bus)) {
                ret = PTR_ERR(priv->bus);
-               goto err_drvdata;
+               goto out_iounmap;
        }
 
        priv->bus->get_irq = mcb_pci_get_irq;
 
        ret = chameleon_parse_cells(priv->bus, priv->mapbase, priv->base);
        if (ret < 0)
-               goto err_drvdata;
+               goto out_iounmap;
        num_cells = ret;
 
        dev_dbg(&pdev->dev, "Found %d cells\n", num_cells);
@@ -98,11 +98,11 @@ static int mcb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        return 0;
 
-err_drvdata:
+out_iounmap:
        iounmap(priv->base);
-err_ioremap:
+out_release:
        pci_release_region(pdev, 0);
-err_start:
+out_disable:
        pci_disable_device(pdev);
        return ret;
 }
index 9da04ede04f356aaef1495bd0cf01408e6556da5..f4c82eafa8e57a15cda2da73c6f276fb09f5c0b9 100644 (file)
 static int write8(void *client, u8 val)
 {
        u8 data = val;
+
        return spi_write(client, &data, 1);
 }
 
 static int write16(void *client, u8 reg, u8 val)
 {
        u8 data[2] = {reg, val};
+
        return spi_write(client, data, 2);
 }
 
 static int write24(void *client, u8 reg, u16 val)
 {
        u8 data[3] = {reg, val >> 8, val};
+
        return spi_write(client, data, 3);
 }
 
@@ -34,6 +37,7 @@ static int read8(void *client)
 {
        int ret;
        u8 data;
+
        ret = spi_read(client, &data, 1);
        if (ret < 0)
                return ret;
index a43053daad0ec6698e39475f02499b955a12f66a..15e88078ba1e6a70ec82b3c713fd8c19ebb425d7 100644 (file)
@@ -176,6 +176,7 @@ static s32 dpot_read_i2c(struct dpot_data *dpot, u8 reg)
 {
        int value;
        unsigned ctrl = 0;
+
        switch (dpot->uid) {
        case DPOT_UID(AD5246_ID):
        case DPOT_UID(AD5247_ID):
@@ -333,7 +334,6 @@ static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value)
        case DPOT_UID(AD5246_ID):
        case DPOT_UID(AD5247_ID):
                return dpot_write_d8(dpot, value);
-               break;
 
        case DPOT_UID(AD5245_ID):
        case DPOT_UID(AD5241_ID):
@@ -345,7 +345,6 @@ static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value)
                ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?
                        0 : DPOT_AD5282_RDAC_AB;
                return dpot_write_r8d8(dpot, ctrl, value);
-               break;
        case DPOT_UID(AD5171_ID):
        case DPOT_UID(AD5273_ID):
                if (reg & DPOT_ADDR_OTP) {
@@ -355,7 +354,6 @@ static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value)
                        ctrl = DPOT_AD5273_FUSE;
                }
                return dpot_write_r8d8(dpot, ctrl, value);
-               break;
        case DPOT_UID(AD5172_ID):
        case DPOT_UID(AD5173_ID):
                ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?
@@ -367,7 +365,6 @@ static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value)
                        ctrl |= DPOT_AD5170_2_3_FUSE;
                }
                return dpot_write_r8d8(dpot, ctrl, value);
-               break;
        case DPOT_UID(AD5170_ID):
                if (reg & DPOT_ADDR_OTP) {
                        tmp = dpot_read_r8d16(dpot, tmp);
@@ -376,7 +373,6 @@ static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value)
                        ctrl = DPOT_AD5170_2_3_FUSE;
                }
                return dpot_write_r8d8(dpot, ctrl, value);
-               break;
        case DPOT_UID(AD5272_ID):
        case DPOT_UID(AD5274_ID):
                dpot_write_r8d8(dpot, DPOT_AD5270_1_2_4_CTRLREG << 2,
@@ -391,7 +387,6 @@ static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value)
 
                return dpot_write_r8d8(dpot, (DPOT_AD5270_1_2_4_RDAC << 2) |
                                       (value >> 8), value & 0xFF);
-               break;
        default:
                if (reg & DPOT_ADDR_CMD)
                        return dpot_write_d8(dpot, reg);
index c64d7cad10855eaa15ffcaca562b514deade7a97..e7353449874ba9d584d28d8601314521536489e5 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/semaphore.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
-#include <linux/version.h>
 #include <linux/debugfs.h>
 #include <linux/slab.h>
 
index 2c33fbca9225ef0ed92f2c3be4d468aa751718f9..6ab31eff0536a2a2572bb6e39a952931959c958d 100644 (file)
@@ -24,7 +24,6 @@
  * debugging, please also see the debugfs interfaces of this driver.
  */
 
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/module.h>
index 3336ddca45acc7e775794e4b239d2da113f354ef..8758d033db23d7b84c7be8b2170f6702b1c979a3 100644 (file)
@@ -144,9 +144,9 @@ ioc4_clock_calibrate(struct ioc4_driver_data *idd)
 {
        union ioc4_int_out int_out;
        union ioc4_gpcr gpcr;
-       unsigned int state, last_state = 1;
+       unsigned int state, last_state;
        uint64_t start, end, period;
-       unsigned int count = 0;
+       unsigned int count;
 
        /* Enable output */
        gpcr.raw = 0;
@@ -167,19 +167,20 @@ ioc4_clock_calibrate(struct ioc4_driver_data *idd)
        mmiowb();
 
        /* Check square wave period averaged over some number of cycles */
-       do {
-               int_out.raw = readl(&idd->idd_misc_regs->int_out.raw);
-               state = int_out.fields.int_out;
-               if (!last_state && state) {
-                       count++;
-                       if (count == IOC4_CALIBRATE_END) {
-                               end = ktime_get_ns();
-                               break;
-                       } else if (count == IOC4_CALIBRATE_DISCARD)
-                               start = ktime_get_ns();
-               }
-               last_state = state;
-       } while (1);
+       start = ktime_get_ns();
+       state = 1; /* make sure the first read isn't a rising edge */
+       for (count = 0; count <= IOC4_CALIBRATE_END; count++) {
+               do { /* wait for a rising edge */
+                       last_state = state;
+                       int_out.raw = readl(&idd->idd_misc_regs->int_out.raw);
+                       state = int_out.fields.int_out;
+               } while (last_state || !state);
+
+               /* discard the first few cycles */
+               if (count == IOC4_CALIBRATE_DISCARD)
+                       start = ktime_get_ns();
+       }
+       end = ktime_get_ns();
 
        /* Calculation rearranged to preserve intermediate precision.
         * Logically:
index 79f53941779d1f321d96ac6b6727cb13e4d5ded0..c4cb9a984a5fb3965bba581eab0dd5c9096ec851 100644 (file)
@@ -97,23 +97,25 @@ int mei_amthif_host_init(struct mei_device *dev)
        /* allocate storage for ME message buffer */
        msg_buf = kcalloc(dev->iamthif_mtu,
                        sizeof(unsigned char), GFP_KERNEL);
-       if (!msg_buf)
-               return -ENOMEM;
+       if (!msg_buf) {
+               ret = -ENOMEM;
+               goto out;
+       }
 
        dev->iamthif_msg_buf = msg_buf;
 
        ret = mei_cl_link(cl, MEI_IAMTHIF_HOST_CLIENT_ID);
-
        if (ret < 0) {
-               dev_err(dev->dev,
-                       "amthif: failed link client %d\n", ret);
-               return ret;
+               dev_err(dev->dev, "amthif: failed cl_link %d\n", ret);
+               goto out;
        }
 
        ret = mei_cl_connect(cl, NULL);
 
        dev->iamthif_state = MEI_IAMTHIF_IDLE;
 
+out:
+       mei_me_cl_put(me_cl);
        return ret;
 }
 
index b3a72bca5242ab0e5a65efda16e304f6b8181851..be767f4db26a137bb93043bf448891031428e9fe 100644 (file)
@@ -224,46 +224,53 @@ void mei_cl_driver_unregister(struct mei_cl_driver *driver)
 }
 EXPORT_SYMBOL_GPL(mei_cl_driver_unregister);
 
-static int ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
+static ssize_t ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
                        bool blocking)
 {
        struct mei_device *dev;
-       struct mei_me_client *me_cl;
-       struct mei_cl_cb *cb;
-       int rets;
+       struct mei_me_client *me_cl = NULL;
+       struct mei_cl_cb *cb = NULL;
+       ssize_t rets;
 
        if (WARN_ON(!cl || !cl->dev))
                return -ENODEV;
 
        dev = cl->dev;
 
-       if (cl->state != MEI_FILE_CONNECTED)
-               return -ENODEV;
+       mutex_lock(&dev->device_lock);
+       if (cl->state != MEI_FILE_CONNECTED) {
+               rets = -ENODEV;
+               goto out;
+       }
 
        /* Check if we have an ME client device */
        me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
-       if (!me_cl)
-               return -ENOTTY;
+       if (!me_cl) {
+               rets = -ENOTTY;
+               goto out;
+       }
 
-       if (length > me_cl->props.max_msg_length)
-               return -EFBIG;
+       if (length > me_cl->props.max_msg_length) {
+               rets = -EFBIG;
+               goto out;
+       }
 
        cb = mei_io_cb_init(cl, NULL);
-       if (!cb)
-               return -ENOMEM;
+       if (!cb) {
+               rets = -ENOMEM;
+               goto out;
+       }
 
        rets = mei_io_cb_alloc_req_buf(cb, length);
-       if (rets < 0) {
-               mei_io_cb_free(cb);
-               return rets;
-       }
+       if (rets < 0)
+               goto out;
 
        memcpy(cb->request_buffer.data, buf, length);
 
-       mutex_lock(&dev->device_lock);
-
        rets = mei_cl_write(cl, cb, blocking);
 
+out:
+       mei_me_cl_put(me_cl);
        mutex_unlock(&dev->device_lock);
        if (rets < 0)
                mei_io_cb_free(cb);
@@ -271,12 +278,12 @@ static int ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
        return rets;
 }
 
-int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
+ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
 {
        struct mei_device *dev;
        struct mei_cl_cb *cb;
        size_t r_length;
-       int err;
+       ssize_t rets;
 
        if (WARN_ON(!cl || !cl->dev))
                return -ENODEV;
@@ -286,11 +293,9 @@ int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
        mutex_lock(&dev->device_lock);
 
        if (!cl->read_cb) {
-               err = mei_cl_read_start(cl, length);
-               if (err < 0) {
-                       mutex_unlock(&dev->device_lock);
-                       return err;
-               }
+               rets = mei_cl_read_start(cl, length);
+               if (rets < 0)
+                       goto out;
        }
 
        if (cl->reading_state != MEI_READ_COMPLETE &&
@@ -313,13 +318,13 @@ int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
        cb = cl->read_cb;
 
        if (cl->reading_state != MEI_READ_COMPLETE) {
-               r_length = 0;
+               rets = 0;
                goto out;
        }
 
        r_length = min_t(size_t, length, cb->buf_idx);
-
        memcpy(buf, cb->response_buffer.data, r_length);
+       rets = r_length;
 
        mei_io_cb_free(cb);
        cl->reading_state = MEI_IDLE;
@@ -328,20 +333,20 @@ int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
 out:
        mutex_unlock(&dev->device_lock);
 
-       return r_length;
+       return rets;
 }
 
-inline int __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length)
+inline ssize_t __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length)
 {
        return ___mei_cl_send(cl, buf, length, 0);
 }
 
-inline int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length)
+inline ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length)
 {
        return ___mei_cl_send(cl, buf, length, 1);
 }
 
-int mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length)
+ssize_t mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length)
 {
        struct mei_cl *cl = device->cl;
 
@@ -355,7 +360,7 @@ int mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length)
 }
 EXPORT_SYMBOL_GPL(mei_cl_send);
 
-int mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length)
+ssize_t mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length)
 {
        struct mei_cl *cl =  device->cl;
 
index 1382d551d7ed676f2c0eeb0d417382c1ca9fac33..dfbddfe1c7a06f9e1ea435ffac42ab31b7a9511c 100644 (file)
 #include "hbm.h"
 #include "client.h"
 
+/**
+ * mei_me_cl_init - initialize me client
+ *
+ * @me_cl: me client
+ */
+void mei_me_cl_init(struct mei_me_client *me_cl)
+{
+       INIT_LIST_HEAD(&me_cl->list);
+       kref_init(&me_cl->refcnt);
+}
+
+/**
+ * mei_me_cl_get - increases me client refcount
+ *
+ * @me_cl: me client
+ *
+ * Locking: called under "dev->device_lock" lock
+ *
+ * Return: me client or NULL
+ */
+struct mei_me_client *mei_me_cl_get(struct mei_me_client *me_cl)
+{
+       if (me_cl)
+               kref_get(&me_cl->refcnt);
+
+       return me_cl;
+}
+
+/**
+ * mei_me_cl_release - unlink and free me client
+ *
+ * Locking: called under "dev->device_lock" lock
+ *
+ * @ref: me_client refcount
+ */
+static void mei_me_cl_release(struct kref *ref)
+{
+       struct mei_me_client *me_cl =
+               container_of(ref, struct mei_me_client, refcnt);
+       list_del(&me_cl->list);
+       kfree(me_cl);
+}
+/**
+ * mei_me_cl_put - decrease me client refcount and free client if necessary
+ *
+ * Locking: called under "dev->device_lock" lock
+ *
+ * @me_cl: me client
+ */
+void mei_me_cl_put(struct mei_me_client *me_cl)
+{
+       if (me_cl)
+               kref_put(&me_cl->refcnt, mei_me_cl_release);
+}
+
 /**
  * mei_me_cl_by_uuid - locate me client by uuid
+ *     increases ref count
  *
  * @dev: mei device
  * @uuid: me client uuid
@@ -43,13 +99,14 @@ struct mei_me_client *mei_me_cl_by_uuid(const struct mei_device *dev,
 
        list_for_each_entry(me_cl, &dev->me_clients, list)
                if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0)
-                       return me_cl;
+                       return mei_me_cl_get(me_cl);
 
        return NULL;
 }
 
 /**
  * mei_me_cl_by_id - locate me client by client id
+ *     increases ref count
  *
  * @dev: the device structure
  * @client_id: me client id
@@ -65,12 +122,14 @@ struct mei_me_client *mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
 
        list_for_each_entry(me_cl, &dev->me_clients, list)
                if (me_cl->client_id == client_id)
-                       return me_cl;
+                       return mei_me_cl_get(me_cl);
+
        return NULL;
 }
 
 /**
  * mei_me_cl_by_uuid_id - locate me client by client id and uuid
+ *     increases ref count
  *
  * @dev: the device structure
  * @uuid: me client uuid
@@ -88,31 +147,67 @@ struct mei_me_client *mei_me_cl_by_uuid_id(struct mei_device *dev,
        list_for_each_entry(me_cl, &dev->me_clients, list)
                if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0 &&
                    me_cl->client_id == client_id)
-                       return me_cl;
+                       return mei_me_cl_get(me_cl);
+
        return NULL;
 }
 
 /**
- * mei_me_cl_remove - remove me client matching uuid and client_id
+ * mei_me_cl_rm_by_uuid - remove all me clients matching uuid
  *
  * @dev: the device structure
  * @uuid: me client uuid
- * @client_id: me client address
+ *
+ * Locking: called under "dev->device_lock" lock
  */
-void mei_me_cl_remove(struct mei_device *dev, const uuid_le *uuid, u8 client_id)
+void mei_me_cl_rm_by_uuid(struct mei_device *dev, const uuid_le *uuid)
 {
        struct mei_me_client *me_cl, *next;
 
+       dev_dbg(dev->dev, "remove %pUl\n", uuid);
+       list_for_each_entry_safe(me_cl, next, &dev->me_clients, list)
+               if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0)
+                       mei_me_cl_put(me_cl);
+}
+
+/**
+ * mei_me_cl_rm_by_uuid_id - remove all me clients matching client id
+ *
+ * @dev: the device structure
+ * @uuid: me client uuid
+ * @id: me client id
+ *
+ * Locking: called under "dev->device_lock" lock
+ */
+void mei_me_cl_rm_by_uuid_id(struct mei_device *dev, const uuid_le *uuid, u8 id)
+{
+       struct mei_me_client *me_cl, *next;
+       const uuid_le *pn;
+
+       dev_dbg(dev->dev, "remove %pUl %d\n", uuid, id);
        list_for_each_entry_safe(me_cl, next, &dev->me_clients, list) {
-               if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0 &&
-                   me_cl->client_id == client_id) {
-                       list_del(&me_cl->list);
-                       kfree(me_cl);
-                       break;
-               }
+               pn =  &me_cl->props.protocol_name;
+               if (me_cl->client_id == id && uuid_le_cmp(*uuid, *pn) == 0)
+                       mei_me_cl_put(me_cl);
        }
 }
 
+/**
+ * mei_me_cl_rm_all - remove all me clients
+ *
+ * @dev: the device structure
+ *
+ * Locking: called under "dev->device_lock" lock
+ */
+void mei_me_cl_rm_all(struct mei_device *dev)
+{
+       struct mei_me_client *me_cl, *next;
+
+       list_for_each_entry_safe(me_cl, next, &dev->me_clients, list)
+                       mei_me_cl_put(me_cl);
+}
+
+
 
 /**
  * mei_cl_cmp_id - tells if the clients are the same
@@ -695,6 +790,7 @@ int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
 {
        struct mei_device *dev;
        struct mei_me_client *me_cl;
+       int rets = 0;
 
        if (WARN_ON(!cl || !cl->dev))
                return -EINVAL;
@@ -704,18 +800,19 @@ int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
        if (cl->mei_flow_ctrl_creds > 0)
                return 1;
 
-       me_cl = mei_me_cl_by_id(dev, cl->me_client_id);
+       me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
        if (!me_cl) {
                cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
                return -ENOENT;
        }
 
-       if (me_cl->mei_flow_ctrl_creds) {
+       if (me_cl->mei_flow_ctrl_creds > 0) {
+               rets = 1;
                if (WARN_ON(me_cl->props.single_recv_buf == 0))
-                       return -EINVAL;
-               return 1;
+                       rets = -EINVAL;
        }
-       return 0;
+       mei_me_cl_put(me_cl);
+       return rets;
 }
 
 /**
@@ -732,28 +829,36 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
 {
        struct mei_device *dev;
        struct mei_me_client *me_cl;
+       int rets;
 
        if (WARN_ON(!cl || !cl->dev))
                return -EINVAL;
 
        dev = cl->dev;
 
-       me_cl = mei_me_cl_by_id(dev, cl->me_client_id);
+       me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
        if (!me_cl) {
                cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
                return -ENOENT;
        }
 
        if (me_cl->props.single_recv_buf) {
-               if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0))
-                       return -EINVAL;
+               if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0)) {
+                       rets = -EINVAL;
+                       goto out;
+               }
                me_cl->mei_flow_ctrl_creds--;
        } else {
-               if (WARN_ON(cl->mei_flow_ctrl_creds <= 0))
-                       return -EINVAL;
+               if (WARN_ON(cl->mei_flow_ctrl_creds <= 0)) {
+                       rets = -EINVAL;
+                       goto out;
+               }
                cl->mei_flow_ctrl_creds--;
        }
-       return 0;
+       rets = 0;
+out:
+       mei_me_cl_put(me_cl);
+       return rets;
 }
 
 /**
@@ -788,6 +893,9 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length)
                cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
                return  -ENOTTY;
        }
+       /* always allocate at least client max message */
+       length = max_t(size_t, length, me_cl->props.max_msg_length);
+       mei_me_cl_put(me_cl);
 
        rets = pm_runtime_get(dev->dev);
        if (rets < 0 && rets != -EINPROGRESS) {
@@ -802,8 +910,6 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length)
                goto out;
        }
 
-       /* always allocate at least client max message */
-       length = max_t(size_t, length, me_cl->props.max_msg_length);
        rets = mei_io_cb_alloc_resp_buf(cb, length);
        if (rets)
                goto out;
index d9d0c1525259978b93c8866069bc24f31cac78a3..cfcde8e97fc489a3e0ba966d06def8f1fde2c0c4 100644 (file)
 
 #include "mei_dev.h"
 
+/*
+ * reference counting base function
+ */
+void mei_me_cl_init(struct mei_me_client *me_cl);
+void mei_me_cl_put(struct mei_me_client *me_cl);
+struct mei_me_client *mei_me_cl_get(struct mei_me_client *me_cl);
+
 struct mei_me_client *mei_me_cl_by_uuid(const struct mei_device *dev,
-                                       const uuid_le *cuuid);
+                                       const uuid_le *uuid);
 struct mei_me_client *mei_me_cl_by_id(struct mei_device *dev, u8 client_id);
-
 struct mei_me_client *mei_me_cl_by_uuid_id(struct mei_device *dev,
                                           const uuid_le *uuid, u8 client_id);
-
-void mei_me_cl_remove(struct mei_device *dev,
-                     const uuid_le *uuid, u8 client_id);
+void mei_me_cl_rm_by_uuid(struct mei_device *dev, const uuid_le *uuid);
+void mei_me_cl_rm_by_uuid_id(struct mei_device *dev,
+                            const uuid_le *uuid, u8 id);
+void mei_me_cl_rm_all(struct mei_device *dev);
 
 /*
  * MEI IO Functions
index b60b4263cf0f989a15733918c22fb53f0fface51..b125380ee8710162923bc246e0712bfca6d92690 100644 (file)
 #include <linux/mei.h>
 
 #include "mei_dev.h"
+#include "client.h"
 #include "hw.h"
 
 static ssize_t mei_dbgfs_read_meclients(struct file *fp, char __user *ubuf,
                                        size_t cnt, loff_t *ppos)
 {
        struct mei_device *dev = fp->private_data;
-       struct mei_me_client *me_cl;
+       struct mei_me_client *me_cl, *n;
        size_t bufsz = 1;
        char *buf;
        int i = 0;
        int pos = 0;
        int ret;
 
-#define HDR "  |id|fix|         UUID                       |con|msg len|sb|\n"
+#define HDR \
+"  |id|fix|         UUID                       |con|msg len|sb|refc|\n"
 
        mutex_lock(&dev->device_lock);
 
@@ -54,16 +56,22 @@ static ssize_t mei_dbgfs_read_meclients(struct file *fp, char __user *ubuf,
        if (dev->dev_state != MEI_DEV_ENABLED)
                goto out;
 
-       list_for_each_entry(me_cl, &dev->me_clients, list) {
-
-               pos += scnprintf(buf + pos, bufsz - pos,
-                       "%2d|%2d|%3d|%pUl|%3d|%7d|%2d|\n",
-                       i++, me_cl->client_id,
-                       me_cl->props.fixed_address,
-                       &me_cl->props.protocol_name,
-                       me_cl->props.max_number_of_connections,
-                       me_cl->props.max_msg_length,
-                       me_cl->props.single_recv_buf);
+       list_for_each_entry_safe(me_cl, n, &dev->me_clients, list) {
+
+               me_cl = mei_me_cl_get(me_cl);
+               if (me_cl) {
+                       pos += scnprintf(buf + pos, bufsz - pos,
+                               "%2d|%2d|%3d|%pUl|%3d|%7d|%2d|%4d|\n",
+                               i++, me_cl->client_id,
+                               me_cl->props.fixed_address,
+                               &me_cl->props.protocol_name,
+                               me_cl->props.max_number_of_connections,
+                               me_cl->props.max_msg_length,
+                               me_cl->props.single_recv_buf,
+                               atomic_read(&me_cl->refcnt.refcount));
+               }
+
+               mei_me_cl_put(me_cl);
        }
 out:
        mutex_unlock(&dev->device_lock);
index 239d7f5d6a92a851b48e381e5db05c9e94eb1c0f..c8412d41e4f163410b771dfcdd7126f201f3e937 100644 (file)
@@ -104,21 +104,6 @@ void mei_hbm_idle(struct mei_device *dev)
        dev->hbm_state = MEI_HBM_IDLE;
 }
 
-/**
- * mei_me_cl_remove_all - remove all me clients
- *
- * @dev: the device structure
- */
-static void mei_me_cl_remove_all(struct mei_device *dev)
-{
-       struct mei_me_client *me_cl, *next;
-
-       list_for_each_entry_safe(me_cl, next, &dev->me_clients, list) {
-                       list_del(&me_cl->list);
-                       kfree(me_cl);
-       }
-}
-
 /**
  * mei_hbm_reset - reset hbm counters and book keeping data structurs
  *
@@ -128,7 +113,7 @@ void mei_hbm_reset(struct mei_device *dev)
 {
        dev->me_client_index = 0;
 
-       mei_me_cl_remove_all(dev);
+       mei_me_cl_rm_all(dev);
 
        mei_hbm_idle(dev);
 }
@@ -339,11 +324,16 @@ static int mei_hbm_me_cl_add(struct mei_device *dev,
                             struct hbm_props_response *res)
 {
        struct mei_me_client *me_cl;
+       const uuid_le *uuid = &res->client_properties.protocol_name;
+
+       mei_me_cl_rm_by_uuid(dev, uuid);
 
        me_cl = kzalloc(sizeof(struct mei_me_client), GFP_KERNEL);
        if (!me_cl)
                return -ENOMEM;
 
+       mei_me_cl_init(me_cl);
+
        me_cl->props = res->client_properties;
        me_cl->client_id = res->me_addr;
        me_cl->mei_flow_ctrl_creds = 0;
@@ -484,6 +474,7 @@ static int mei_hbm_add_single_flow_creds(struct mei_device *dev,
                                  struct hbm_flow_control *flow)
 {
        struct mei_me_client *me_cl;
+       int rets;
 
        me_cl = mei_me_cl_by_id(dev, flow->me_addr);
        if (!me_cl) {
@@ -492,14 +483,19 @@ static int mei_hbm_add_single_flow_creds(struct mei_device *dev,
                return -ENOENT;
        }
 
-       if (WARN_ON(me_cl->props.single_recv_buf == 0))
-               return -EINVAL;
+       if (WARN_ON(me_cl->props.single_recv_buf == 0)) {
+               rets = -EINVAL;
+               goto out;
+       }
 
        me_cl->mei_flow_ctrl_creds++;
        dev_dbg(dev->dev, "recv flow ctrl msg ME %d (single) creds = %d.\n",
            flow->me_addr, me_cl->mei_flow_ctrl_creds);
 
-       return 0;
+       rets = 0;
+out:
+       mei_me_cl_put(me_cl);
+       return rets;
 }
 
 /**
index 06ff0a2ec96071c5b2d1c2c5dffdff7a5c03d938..f8fd503dfbd69b09cc192c655127cf9aeb950e77 100644 (file)
@@ -242,7 +242,7 @@ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable)
        if ((hcsr & H_RST) == H_RST) {
                dev_warn(dev->dev, "H_RST is set = 0x%08X", hcsr);
                hcsr &= ~H_RST;
-               mei_me_reg_write(hw, H_CSR, hcsr);
+               mei_hcsr_set(hw, hcsr);
                hcsr = mei_hcsr_read(hw);
        }
 
@@ -335,6 +335,7 @@ static int mei_me_hw_ready_wait(struct mei_device *dev)
                return -ETIME;
        }
 
+       mei_me_hw_reset_release(dev);
        dev->recvd_hw_ready = false;
        return 0;
 }
@@ -731,9 +732,7 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
        /*  check if we need to start the dev */
        if (!mei_host_is_ready(dev)) {
                if (mei_hw_is_ready(dev)) {
-                       mei_me_hw_reset_release(dev);
                        dev_dbg(dev->dev, "we need to start the dev.\n");
-
                        dev->recvd_hw_ready = true;
                        wake_up(&dev->wait_hw_ready);
                } else {
index ae56ba6ca0e3615758953259c4223efab7322613..3c019c0e60eb859ede0621f26c4d71d72fca8abe 100644 (file)
@@ -303,7 +303,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
                         size_t length, loff_t *offset)
 {
        struct mei_cl *cl = file->private_data;
-       struct mei_me_client *me_cl;
+       struct mei_me_client *me_cl = NULL;
        struct mei_cl_cb *write_cb = NULL;
        struct mei_device *dev;
        unsigned long timeout = 0;
@@ -399,12 +399,14 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
                                "amthif write failed with status = %d\n", rets);
                        goto out;
                }
+               mei_me_cl_put(me_cl);
                mutex_unlock(&dev->device_lock);
                return length;
        }
 
        rets = mei_cl_write(cl, write_cb, false);
 out:
+       mei_me_cl_put(me_cl);
        mutex_unlock(&dev->device_lock);
        if (rets < 0)
                mei_io_cb_free(write_cb);
@@ -433,24 +435,19 @@ static int mei_ioctl_connect_client(struct file *file,
        cl = file->private_data;
        dev = cl->dev;
 
-       if (dev->dev_state != MEI_DEV_ENABLED) {
-               rets = -ENODEV;
-               goto end;
-       }
+       if (dev->dev_state != MEI_DEV_ENABLED)
+               return -ENODEV;
 
        if (cl->state != MEI_FILE_INITIALIZING &&
-           cl->state != MEI_FILE_DISCONNECTED) {
-               rets = -EBUSY;
-               goto end;
-       }
+           cl->state != MEI_FILE_DISCONNECTED)
+               return  -EBUSY;
 
        /* find ME client we're trying to connect to */
        me_cl = mei_me_cl_by_uuid(dev, &data->in_client_uuid);
        if (!me_cl || me_cl->props.fixed_address) {
                dev_dbg(dev->dev, "Cannot connect to FW Client UUID = %pUl\n",
                                &data->in_client_uuid);
-               rets = -ENOTTY;
-               goto end;
+               return  -ENOTTY;
        }
 
        cl->me_client_id = me_cl->client_id;
@@ -487,17 +484,16 @@ static int mei_ioctl_connect_client(struct file *file,
                goto end;
        }
 
-
        /* prepare the output buffer */
        client = &data->out_client_properties;
        client->max_msg_length = me_cl->props.max_msg_length;
        client->protocol_version = me_cl->props.protocol_version;
        dev_dbg(dev->dev, "Can connect?\n");
 
-
        rets = mei_cl_connect(cl, file);
 
 end:
+       mei_me_cl_put(me_cl);
        return rets;
 }
 
index 3dad74a8d496697a968c3cb21724cf5c15ba0c98..6c6ce9381535151a437612ad83bae65b08dfed2e 100644 (file)
@@ -172,12 +172,14 @@ struct mei_fw_status {
  * struct mei_me_client - representation of me (fw) client
  *
  * @list: link in me client list
+ * @refcnt: struct reference count
  * @props: client properties
  * @client_id: me client id
  * @mei_flow_ctrl_creds: flow control credits
  */
 struct mei_me_client {
        struct list_head list;
+       struct kref refcnt;
        struct mei_client_properties props;
        u8 client_id;
        u8 mei_flow_ctrl_creds;
@@ -345,9 +347,9 @@ struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
                                        struct mei_cl_ops *ops);
 void mei_cl_remove_device(struct mei_cl_device *device);
 
-int __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length);
-int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length);
-int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length);
+ssize_t __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length);
+ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length);
+ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length);
 void mei_cl_bus_rx_event(struct mei_cl *cl);
 void mei_cl_bus_remove_devices(struct mei_device *dev);
 int mei_cl_bus_init(void);
index 60ca9240368e525e48bf13b0f0bb79fdf758d6f1..bb61a119b8bbb4fdd8ee7d09da5fb520bab72573 100644 (file)
@@ -521,6 +521,7 @@ int mei_nfc_host_init(struct mei_device *dev)
 
        cl_info->me_client_id = me_cl->client_id;
        cl_info->cl_uuid = me_cl->props.protocol_name;
+       mei_me_cl_put(me_cl);
 
        ret = mei_cl_link(cl_info, MEI_HOST_CLIENT_ID_ANY);
        if (ret)
@@ -539,6 +540,7 @@ int mei_nfc_host_init(struct mei_device *dev)
 
        cl->me_client_id = me_cl->client_id;
        cl->cl_uuid = me_cl->props.protocol_name;
+       mei_me_cl_put(me_cl);
 
        ret = mei_cl_link(cl, MEI_HOST_CLIENT_ID_ANY);
        if (ret)
index b1d892cea94da2f0733670392429fa09bb1a58ed..475f1dea45bfd06c5ecfa9e2fdb40da2da32b34f 100644 (file)
@@ -76,6 +76,7 @@ int mei_wd_host_init(struct mei_device *dev)
 
        cl->me_client_id = me_cl->client_id;
        cl->cl_uuid = me_cl->props.protocol_name;
+       mei_me_cl_put(me_cl);
 
        ret = mei_cl_link(cl, MEI_WD_HOST_CLIENT_ID);
 
index 54be83d3efdd682e8025577c5464f2c3807739c0..c8c6a363069cc189b799bcf376fcf6991cc05e6e 100644 (file)
@@ -343,12 +343,26 @@ void st_int_recv(void *disc_data,
                        /* Unknow packet? */
                default:
                        type = *ptr;
-                       if (st_gdata->list[type] == NULL) {
-                               pr_err("chip/interface misbehavior dropping"
-                                       " frame starting with 0x%02x", type);
-                               goto done;
 
+                       /* Default case means non-HCILL packets,
+                        * possibilities are packets for:
+                        * (a) valid protocol -  Supported Protocols within
+                        *     the ST_MAX_CHANNELS.
+                        * (b) registered protocol - Checked by
+                        *     "st_gdata->list[type] == NULL)" are supported
+                        *     protocols only.
+                        *  Rules out any invalid protocol and
+                        *  unregistered protocols with channel ID < 16.
+                        */
+
+                       if ((type >= ST_MAX_CHANNELS) ||
+                                       (st_gdata->list[type] == NULL)) {
+                               pr_err("chip/interface misbehavior: "
+                                               "dropping frame starting "
+                                               "with 0x%02x\n", type);
+                               goto done;
                        }
+
                        st_gdata->rx_skb = alloc_skb(
                                        st_gdata->list[type]->max_frame_size,
                                        GFP_ATOMIC);
@@ -893,5 +907,3 @@ void st_core_exit(struct st_data_s *st_gdata)
                kfree(st_gdata);
        }
 }
-
-
index e4b7ee4f57b845a32af6e2778baebc13b9836dba..18e7a03985d4cc601ecbbb511dc3665d217cce88 100644 (file)
@@ -36,7 +36,8 @@
 #include <linux/skbuff.h>
 #include <linux/ti_wilink_st.h>
 #include <linux/module.h>
-
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #define MAX_ST_DEVICES 3       /* Imagine 1 on each UART for now */
 static struct platform_device *st_kim_devices[MAX_ST_DEVICES];
@@ -44,6 +45,9 @@ static struct platform_device *st_kim_devices[MAX_ST_DEVICES];
 /**********************************************************************/
 /* internal functions */
 
+struct ti_st_plat_data *dt_pdata;
+static struct ti_st_plat_data *get_platform_data(struct device *dev);
+
 /**
  * st_get_plat_device -
  *     function which returns the reference to the platform device
@@ -215,6 +219,7 @@ static long read_local_version(struct kim_data_s *kim_gdata, char *bts_scr_name)
 {
        unsigned short version = 0, chip = 0, min_ver = 0, maj_ver = 0;
        const char read_ver_cmd[] = { 0x01, 0x01, 0x10, 0x00 };
+       long timeout;
 
        pr_debug("%s", __func__);
 
@@ -224,10 +229,11 @@ static long read_local_version(struct kim_data_s *kim_gdata, char *bts_scr_name)
                return -EIO;
        }
 
-       if (!wait_for_completion_interruptible_timeout(
-               &kim_gdata->kim_rcvd, msecs_to_jiffies(CMD_RESP_TIME))) {
-               pr_err(" waiting for ver info- timed out ");
-               return -ETIMEDOUT;
+       timeout = wait_for_completion_interruptible_timeout(
+               &kim_gdata->kim_rcvd, msecs_to_jiffies(CMD_RESP_TIME));
+       if (timeout <= 0) {
+               pr_err(" waiting for ver info- timed out or received signal");
+               return timeout ? -ERESTARTSYS : -ETIMEDOUT;
        }
        reinit_completion(&kim_gdata->kim_rcvd);
        /* the positions 12 & 13 in the response buffer provide with the
@@ -391,13 +397,14 @@ static long download_firmware(struct kim_data_s *kim_gdata)
                        break;
                case ACTION_WAIT_EVENT:  /* wait */
                        pr_debug("W");
-                       if (!wait_for_completion_interruptible_timeout(
+                       err = wait_for_completion_interruptible_timeout(
                                        &kim_gdata->kim_rcvd,
-                                       msecs_to_jiffies(CMD_RESP_TIME))) {
-                               pr_err("response timeout during fw download ");
+                                       msecs_to_jiffies(CMD_RESP_TIME));
+                       if (err <= 0) {
+                               pr_err("response timeout/signaled during fw download ");
                                /* timed out */
                                release_firmware(kim_gdata->fw_entry);
-                               return -ETIMEDOUT;
+                               return err ? -ERESTARTSYS : -ETIMEDOUT;
                        }
                        reinit_completion(&kim_gdata->kim_rcvd);
                        break;
@@ -462,7 +469,12 @@ long st_kim_start(void *kim_data)
        struct kim_data_s       *kim_gdata = (struct kim_data_s *)kim_data;
 
        pr_info(" %s", __func__);
-       pdata = kim_gdata->kim_pdev->dev.platform_data;
+       if (kim_gdata->kim_pdev->dev.of_node) {
+               pr_debug("use device tree data");
+               pdata = dt_pdata;
+       } else {
+               pdata = kim_gdata->kim_pdev->dev.platform_data;
+       }
 
        do {
                /* platform specific enabling code here */
@@ -522,12 +534,18 @@ long st_kim_stop(void *kim_data)
 {
        long err = 0;
        struct kim_data_s       *kim_gdata = (struct kim_data_s *)kim_data;
-       struct ti_st_plat_data  *pdata =
-               kim_gdata->kim_pdev->dev.platform_data;
+       struct ti_st_plat_data  *pdata;
        struct tty_struct       *tty = kim_gdata->core_data->tty;
 
        reinit_completion(&kim_gdata->ldisc_installed);
 
+       if (kim_gdata->kim_pdev->dev.of_node) {
+               pr_debug("use device tree data");
+               pdata = dt_pdata;
+       } else
+               pdata = kim_gdata->kim_pdev->dev.platform_data;
+
+
        if (tty) {      /* can be called before ldisc is installed */
                /* Flush any pending characters in the driver and discipline. */
                tty_ldisc_flush(tty);
@@ -620,7 +638,7 @@ static ssize_t show_baud_rate(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
        struct kim_data_s *kim_data = dev_get_drvdata(dev);
-       return sprintf(buf, "%ld\n", kim_data->baud_rate);
+       return sprintf(buf, "%d\n", kim_data->baud_rate);
 }
 
 static ssize_t show_flow_cntrl(struct device *dev,
@@ -676,12 +694,16 @@ void st_kim_ref(struct st_data_s **core_data, int id)
        struct kim_data_s       *kim_gdata;
        /* get kim_gdata reference from platform device */
        pdev = st_get_plat_device(id);
-       if (!pdev) {
-               *core_data = NULL;
-               return;
-       }
+       if (!pdev)
+               goto err;
        kim_gdata = platform_get_drvdata(pdev);
+       if (!kim_gdata)
+               goto err;
+
        *core_data = kim_gdata->core_data;
+       return;
+err:
+       *core_data = NULL;
 }
 
 static int kim_version_open(struct inode *i, struct file *f)
@@ -715,13 +737,53 @@ static const struct file_operations list_debugfs_fops = {
  * board-*.c file
  */
 
+static const struct of_device_id kim_of_match[] = {
+{
+       .compatible = "kim",
+       },
+       {}
+};
+MODULE_DEVICE_TABLE(of, kim_of_match);
+
+static struct ti_st_plat_data *get_platform_data(struct device *dev)
+{
+       struct device_node *np = dev->of_node;
+       const u32 *dt_property;
+       int len;
+
+       dt_pdata = kzalloc(sizeof(*dt_pdata), GFP_KERNEL);
+
+       if (!dt_pdata)
+               pr_err("Can't allocate device_tree platform data\n");
+
+       dt_property = of_get_property(np, "dev_name", &len);
+       if (dt_property)
+               memcpy(&dt_pdata->dev_name, dt_property, len);
+       of_property_read_u32(np, "nshutdown_gpio",
+                            &dt_pdata->nshutdown_gpio);
+       of_property_read_u32(np, "flow_cntrl", &dt_pdata->flow_cntrl);
+       of_property_read_u32(np, "baud_rate", &dt_pdata->baud_rate);
+
+       return dt_pdata;
+}
+
 static struct dentry *kim_debugfs_dir;
 static int kim_probe(struct platform_device *pdev)
 {
        struct kim_data_s       *kim_gdata;
-       struct ti_st_plat_data  *pdata = pdev->dev.platform_data;
+       struct ti_st_plat_data  *pdata;
        int err;
 
+       if (pdev->dev.of_node)
+               pdata = get_platform_data(&pdev->dev);
+       else
+               pdata = pdev->dev.platform_data;
+
+       if (pdata == NULL) {
+               dev_err(&pdev->dev, "Platform Data is missing\n");
+               return -ENXIO;
+       }
+
        if ((pdev->id != -1) && (pdev->id < MAX_ST_DEVICES)) {
                /* multiple devices could exist */
                st_kim_devices[pdev->id] = pdev;
@@ -750,14 +812,14 @@ static int kim_probe(struct platform_device *pdev)
        kim_gdata->nshutdown = pdata->nshutdown_gpio;
        err = gpio_request(kim_gdata->nshutdown, "kim");
        if (unlikely(err)) {
-               pr_err(" gpio %ld request failed ", kim_gdata->nshutdown);
+               pr_err(" gpio %d request failed ", kim_gdata->nshutdown);
                return err;
        }
 
        /* Configure nShutdown GPIO as output=0 */
        err = gpio_direction_output(kim_gdata->nshutdown, 0);
        if (unlikely(err)) {
-               pr_err(" unable to configure gpio %ld", kim_gdata->nshutdown);
+               pr_err(" unable to configure gpio %d", kim_gdata->nshutdown);
                return err;
        }
        /* get reference of pdev for request_firmware
@@ -781,8 +843,7 @@ static int kim_probe(struct platform_device *pdev)
        kim_debugfs_dir = debugfs_create_dir("ti-st", NULL);
        if (!kim_debugfs_dir) {
                pr_err(" debugfs entries creation failed ");
-               err = -EIO;
-               goto err_debugfs_dir;
+               return 0;
        }
 
        debugfs_create_file("version", S_IRUGO, kim_debugfs_dir,
@@ -791,9 +852,6 @@ static int kim_probe(struct platform_device *pdev)
                                kim_gdata, &list_debugfs_fops);
        return 0;
 
-err_debugfs_dir:
-       sysfs_remove_group(&pdev->dev.kobj, &uim_attr_grp);
-
 err_sysfs_group:
        st_core_exit(kim_gdata->core_data);
 
@@ -806,9 +864,16 @@ err_core_init:
 static int kim_remove(struct platform_device *pdev)
 {
        /* free the GPIOs requested */
-       struct ti_st_plat_data  *pdata = pdev->dev.platform_data;
+       struct ti_st_plat_data  *pdata;
        struct kim_data_s       *kim_gdata;
 
+       if (pdev->dev.of_node) {
+               pr_debug("use device tree data");
+               pdata = dt_pdata;
+       } else {
+               pdata = pdev->dev.platform_data;
+       }
+
        kim_gdata = platform_get_drvdata(pdev);
 
        /* Free the Bluetooth/FM/GPIO
@@ -826,27 +891,44 @@ static int kim_remove(struct platform_device *pdev)
 
        kfree(kim_gdata);
        kim_gdata = NULL;
+       kfree(dt_pdata);
+       dt_pdata = NULL;
+
        return 0;
 }
 
 static int kim_suspend(struct platform_device *pdev, pm_message_t state)
 {
-       struct ti_st_plat_data  *pdata = pdev->dev.platform_data;
+       struct ti_st_plat_data  *pdata;
+
+       if (pdev->dev.of_node) {
+               pr_debug("use device tree data");
+               pdata = dt_pdata;
+       } else {
+               pdata = pdev->dev.platform_data;
+       }
 
        if (pdata->suspend)
                return pdata->suspend(pdev, state);
 
-       return -EOPNOTSUPP;
+       return 0;
 }
 
 static int kim_resume(struct platform_device *pdev)
 {
-       struct ti_st_plat_data  *pdata = pdev->dev.platform_data;
+       struct ti_st_plat_data  *pdata;
+
+       if (pdev->dev.of_node) {
+               pr_debug("use device tree data");
+               pdata = dt_pdata;
+       } else {
+               pdata = pdev->dev.platform_data;
+       }
 
        if (pdata->resume)
                return pdata->resume(pdev);
 
-       return -EOPNOTSUPP;
+       return 0;
 }
 
 /**********************************************************************/
@@ -858,6 +940,8 @@ static struct platform_driver kim_platform_driver = {
        .resume = kim_resume,
        .driver = {
                .name = "kim",
+               .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(kim_of_match),
        },
 };
 
index 93b4d67cc4a3a6bc30197acf709d4f73faaad070..518e1b7f2f95a58c2611cb20640de7228e8a8504 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/ti_wilink_st.h>
 
 /**********************************************************************/
+
 /* internal functions */
 static void send_ll_cmd(struct st_data_s *st_data,
        unsigned char cmd)
@@ -53,7 +54,13 @@ static void ll_device_want_to_sleep(struct st_data_s *st_data)
 
        /* communicate to platform about chip asleep */
        kim_data = st_data->kim_data;
-       pdata = kim_data->kim_pdev->dev.platform_data;
+       if (kim_data->kim_pdev->dev.of_node) {
+               pr_debug("use device tree data");
+               pdata = dt_pdata;
+       } else {
+               pdata = kim_data->kim_pdev->dev.platform_data;
+       }
+
        if (pdata->chip_asleep)
                pdata->chip_asleep(NULL);
 }
@@ -86,7 +93,13 @@ static void ll_device_want_to_wakeup(struct st_data_s *st_data)
 
        /* communicate to platform about chip wakeup */
        kim_data = st_data->kim_data;
-       pdata = kim_data->kim_pdev->dev.platform_data;
+       if (kim_data->kim_pdev->dev.of_node) {
+               pr_debug("use device tree data");
+               pdata = dt_pdata;
+       } else {
+               pdata = kim_data->kim_pdev->dev.platform_data;
+       }
+
        if (pdata->chip_awake)
                pdata->chip_awake(NULL);
 }
index 3dee7ae123e7c1e2ec8e8133d37c47385bcfc945..032d35cf93ca97dfaed554e6e77832672cfbca29 100644 (file)
@@ -113,5 +113,5 @@ module_exit(vmci_drv_exit);
 
 MODULE_AUTHOR("VMware, Inc.");
 MODULE_DESCRIPTION("VMware Virtual Machine Communication Interface.");
-MODULE_VERSION("1.1.0.0-k");
+MODULE_VERSION("1.1.1.0-k");
 MODULE_LICENSE("GPL v2");
index 1723a6e4f2e8ea97b70e3d151f0bc0e29dc29c15..66fc9921fc85d22b927ea2b297fde5ca199866ee 100644 (file)
@@ -218,13 +218,12 @@ static int drv_cp_harray_to_user(void __user *user_buf_uva,
 }
 
 /*
- * Sets up a given context for notify to work.  Calls drv_map_bool_ptr()
- * which maps the notify boolean in user VA in kernel space.
+ * Sets up a given context for notify to work. Maps the notify
+ * boolean in user VA into kernel space.
  */
 static int vmci_host_setup_notify(struct vmci_ctx *context,
                                  unsigned long uva)
 {
-       struct page *page;
        int retval;
 
        if (context->notify_page) {
@@ -243,14 +242,16 @@ static int vmci_host_setup_notify(struct vmci_ctx *context,
        /*
         * Lock physical page backing a given user VA.
         */
-       retval = get_user_pages_fast(PAGE_ALIGN(uva), 1, 1, &page);
-       if (retval != 1)
+       retval = get_user_pages_fast(uva, 1, 1, &context->notify_page);
+       if (retval != 1) {
+               context->notify_page = NULL;
                return VMCI_ERROR_GENERIC;
+       }
 
        /*
         * Map the locked page and set up notify pointer.
         */
-       context->notify = kmap(page) + (uva & (PAGE_SIZE - 1));
+       context->notify = kmap(context->notify_page) + (uva & (PAGE_SIZE - 1));
        vmci_ctx_check_signal_notify(context);
 
        return VMCI_SUCCESS;
index 910e90bf16c6f2a8a0bb685a688d498d89067b05..8843a678f2008d32f250a4fb694b30886c2dfaef 100644 (file)
@@ -69,7 +69,8 @@ config YENTA
        tristate "CardBus yenta-compatible bridge support"
        depends on PCI
        select CARDBUS if !EXPERT
-       select PCCARD_NONSTATIC if PCMCIA != n
+       select PCCARD_NONSTATIC if PCMCIA != n && ISA
+       select PCCARD_PCI if PCMCIA !=n && !ISA
        ---help---
          This option enables support for CardBus host bridges.  Virtually
          all modern PCMCIA bridges are CardBus compatible.  A "bridge" is
@@ -109,7 +110,8 @@ config YENTA_TOSHIBA
 config PD6729
        tristate "Cirrus PD6729 compatible bridge support"
        depends on PCMCIA && PCI
-       select PCCARD_NONSTATIC
+       select PCCARD_NONSTATIC if PCMCIA != n && ISA
+       select PCCARD_PCI if PCMCIA !=n && !ISA
        help
          This provides support for the Cirrus PD6729 PCI-to-PCMCIA bridge
          device, found in some older laptops and PCMCIA card readers.
@@ -117,7 +119,8 @@ config PD6729
 config I82092
        tristate "i82092 compatible bridge support"
        depends on PCMCIA && PCI
-       select PCCARD_NONSTATIC
+       select PCCARD_NONSTATIC if PCMCIA != n && ISA
+       select PCCARD_PCI if PCMCIA !=n && !ISA
        help
          This provides support for the Intel I82092AA PCI-to-PCMCIA bridge device,
          found in some older laptops and more commonly in evaluation boards for the
@@ -287,6 +290,9 @@ config ELECTRA_CF
          Say Y here to support the CompactFlash controller on the
          PA Semi Electra eval board.
 
+config PCCARD_PCI
+       bool
+
 config PCCARD_NONSTATIC
        bool
 
index 27e94b30cf9625b8da99d67b74308651b8077dc6..f1a7ca04d89e9b743fc3f82e545c52521fedef81 100644 (file)
@@ -12,6 +12,7 @@ obj-$(CONFIG_PCMCIA)                          += pcmcia.o
 pcmcia_rsrc-y                                  += rsrc_mgr.o
 pcmcia_rsrc-$(CONFIG_PCCARD_NONSTATIC)         += rsrc_nonstatic.o
 pcmcia_rsrc-$(CONFIG_PCCARD_IODYN)             += rsrc_iodyn.o
+pcmcia_rsrc-$(CONFIG_PCCARD_PCI)               += rsrc_pci.o
 obj-$(CONFIG_PCCARD)                           += pcmcia_rsrc.o
 
 
index 884a984216febe247dee1bdcad69d47d1cd1adf2..64d0515b76bd5ade5136b46a566f78d9c23ba831 100644 (file)
@@ -168,9 +168,12 @@ int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
        } else {
                u_int inc = 1, card_offset, flags;
 
-               if (addr > CISTPL_MAX_CIS_SIZE)
+               if (addr > CISTPL_MAX_CIS_SIZE) {
                        dev_dbg(&s->dev,
                                "attempt to read CIS mem at addr %#x", addr);
+                       memset(ptr, 0xff, len);
+                       return -1;
+               }
 
                flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0);
                if (attr) {
@@ -1383,7 +1386,7 @@ int pccard_validate_cis(struct pcmcia_socket *s, unsigned int *info)
        if (!s)
                return -EINVAL;
 
-       if (s->functions) {
+       if (s->functions || !(s->state & SOCKET_PRESENT)) {
                WARN_ON(1);
                return -EINVAL;
        }
@@ -1448,10 +1451,26 @@ int pccard_validate_cis(struct pcmcia_socket *s, unsigned int *info)
 done:
        /* invalidate CIS cache on failure */
        if (!dev_ok || !ident_ok || !count) {
-               mutex_lock(&s->ops_mutex);
-               destroy_cis_cache(s);
-               mutex_unlock(&s->ops_mutex);
-               ret = -EIO;
+#if defined(CONFIG_MTD_PCMCIA_ANONYMOUS)
+               /* Set up as an anonymous card. If we don't have anonymous
+                  memory support then just error the card as there is no
+                  point trying to second guess.
+
+                  Note: some cards have just a device entry, it may be
+                  worth extending support to cover these in future */
+               if (!dev_ok || !ident_ok) {
+                       dev_info(&s->dev, "no CIS, assuming an anonymous memory card.\n");
+                       pcmcia_replace_cis(s, "\xFF", 1);
+                       count = 1;
+                       ret = 0;
+               } else
+#endif
+               {
+                       mutex_lock(&s->ops_mutex);
+                       destroy_cis_cache(s);
+                       mutex_unlock(&s->ops_mutex);
+                       ret = -EIO;
+               }
        }
 
        if (info)
index 7f1953f78b12b906421a4c8f130d4094e49c6d74..e86cd6b31773ba7fdc9d9b3662bc4fc97b0c4d00 100644 (file)
@@ -80,9 +80,9 @@ struct pccard_resource_ops {
  * Stuff internal to module "pcmcia_rsrc":
  */
 extern int static_init(struct pcmcia_socket *s);
-extern struct resource *pcmcia_make_resource(unsigned long start,
-                                       unsigned long end,
-                                       int flags, const char *name);
+extern struct resource *pcmcia_make_resource(resource_size_t start,
+                                       resource_size_t end,
+                                       unsigned long flags, const char *name);
 
 /*
  * Stuff internal to module "pcmcia_core":
index 757119b87146cbc5219527c8e7c584795c34174e..d3baf0bfca9f0692f9a2789465f727c911e0f7f2 100644 (file)
@@ -667,6 +667,9 @@ static void pcmcia_requery(struct pcmcia_socket *s)
 {
        int has_pfc;
 
+       if (!(s->state & SOCKET_PRESENT))
+               return;
+
        if (s->functions == 0) {
                pcmcia_card_add(s);
                return;
index aa628ed0e9f48178ca3ac9b1fbba39a370877228..df2cb70aef5b6791ad5b9989af76805f64346722 100644 (file)
@@ -30,8 +30,9 @@ int static_init(struct pcmcia_socket *s)
        return 0;
 }
 
-struct resource *pcmcia_make_resource(unsigned long start, unsigned long end,
-                               int flags, const char *name)
+struct resource *pcmcia_make_resource(resource_size_t start,
+                                       resource_size_t end,
+                                       unsigned long flags, const char *name)
 {
        struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
 
diff --git a/drivers/pcmcia/rsrc_pci.c b/drivers/pcmcia/rsrc_pci.c
new file mode 100644 (file)
index 0000000..1f67b3b
--- /dev/null
@@ -0,0 +1,173 @@
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+#include <pcmcia/ss.h>
+#include <pcmcia/cistpl.h>
+#include "cs_internal.h"
+
+
+struct pcmcia_align_data {
+       unsigned long   mask;
+       unsigned long   offset;
+};
+
+static resource_size_t pcmcia_align(void *align_data,
+                               const struct resource *res,
+                               resource_size_t size, resource_size_t align)
+{
+       struct pcmcia_align_data *data = align_data;
+       resource_size_t start;
+
+       start = (res->start & ~data->mask) + data->offset;
+       if (start < res->start)
+               start += data->mask + 1;
+       return start;
+}
+
+static struct resource *find_io_region(struct pcmcia_socket *s,
+                                       unsigned long base, int num,
+                                       unsigned long align)
+{
+       struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_IO,
+                                               dev_name(&s->dev));
+       struct pcmcia_align_data data;
+       int ret;
+
+       data.mask = align - 1;
+       data.offset = base & data.mask;
+
+       ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1,
+                                            base, 0, pcmcia_align, &data);
+       if (ret != 0) {
+               kfree(res);
+               res = NULL;
+       }
+       return res;
+}
+
+static int res_pci_find_io(struct pcmcia_socket *s, unsigned int attr,
+                       unsigned int *base, unsigned int num,
+                       unsigned int align, struct resource **parent)
+{
+       int i, ret = 0;
+
+       /* Check for an already-allocated window that must conflict with
+        * what was asked for.  It is a hack because it does not catch all
+        * potential conflicts, just the most obvious ones.
+        */
+       for (i = 0; i < MAX_IO_WIN; i++) {
+               if (!s->io[i].res)
+                       continue;
+
+               if (!*base)
+                       continue;
+
+               if ((s->io[i].res->start & (align-1)) == *base)
+                       return -EBUSY;
+       }
+
+       for (i = 0; i < MAX_IO_WIN; i++) {
+               struct resource *res = s->io[i].res;
+               unsigned int try;
+
+               if (res && (res->flags & IORESOURCE_BITS) !=
+                       (attr & IORESOURCE_BITS))
+                       continue;
+
+               if (!res) {
+                       if (align == 0)
+                               align = 0x10000;
+
+                       res = s->io[i].res = find_io_region(s, *base, num,
+                                                               align);
+                       if (!res)
+                               return -EINVAL;
+
+                       *base = res->start;
+                       s->io[i].res->flags =
+                               ((res->flags & ~IORESOURCE_BITS) |
+                                       (attr & IORESOURCE_BITS));
+                       s->io[i].InUse = num;
+                       *parent = res;
+                       return 0;
+               }
+
+               /* Try to extend top of window */
+               try = res->end + 1;
+               if ((*base == 0) || (*base == try)) {
+                       ret = adjust_resource(s->io[i].res, res->start,
+                                             resource_size(res) + num);
+                       if (ret)
+                               continue;
+                       *base = try;
+                       s->io[i].InUse += num;
+                       *parent = res;
+                       return 0;
+               }
+
+               /* Try to extend bottom of window */
+               try = res->start - num;
+               if ((*base == 0) || (*base == try)) {
+                       ret = adjust_resource(s->io[i].res,
+                                             res->start - num,
+                                             resource_size(res) + num);
+                       if (ret)
+                               continue;
+                       *base = try;
+                       s->io[i].InUse += num;
+                       *parent = res;
+                       return 0;
+               }
+       }
+       return -EINVAL;
+}
+
+static struct resource *res_pci_find_mem(u_long base, u_long num,
+               u_long align, int low, struct pcmcia_socket *s)
+{
+       struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_MEM,
+                                               dev_name(&s->dev));
+       struct pcmcia_align_data data;
+       unsigned long min;
+       int ret;
+
+       if (align < 0x20000)
+               align = 0x20000;
+       data.mask = align - 1;
+       data.offset = base & data.mask;
+
+       min = 0;
+       if (!low)
+               min = 0x100000UL;
+
+       ret = pci_bus_alloc_resource(s->cb_dev->bus,
+                       res, num, 1, min, 0,
+                       pcmcia_align, &data);
+
+       if (ret != 0) {
+               kfree(res);
+               res = NULL;
+       }
+       return res;
+}
+
+
+static int res_pci_init(struct pcmcia_socket *s)
+{
+       if (!s->cb_dev || !(s->features & SS_CAP_PAGE_REGS)) {
+               dev_err(&s->dev, "not supported by res_pci\n");
+               return -EOPNOTSUPP;
+       }
+       return 0;
+}
+
+struct pccard_resource_ops pccard_nonstatic_ops = {
+       .validate_mem = NULL,
+       .find_io = res_pci_find_io,
+       .find_mem = res_pci_find_mem,
+       .init = res_pci_init,
+       .exit = NULL,
+};
+EXPORT_SYMBOL(pccard_nonstatic_ops);
index 074569e77d22ef09784aca56d63714fbf051afcc..facd43b8516cf7af1178772f9e62fc9054fcd82a 100644 (file)
@@ -181,7 +181,8 @@ static int pnp_dock_thread(void *unused)
                        break;
                default:
                        pnpbios_print_status("pnp_dock_thread", status);
-                       continue;
+                       printk(KERN_WARNING "PnPBIOS: disabling dock monitoring.\n");
+                       complete_and_exit(&unload_sem, 0);
                }
                if (d != docked) {
                        if (pnp_dock_event(d, &now) == 0) {
index 5a90914d856d21648027de61e9f9123d9ead9a6d..8a15c323c030f566a03ae56502b0fe331fd09d04 100644 (file)
@@ -104,6 +104,26 @@ config UIO_NETX
          To compile this driver as a module, choose M here; the module
          will be called uio_netx.
 
+config UIO_FSL_ELBC_GPCM
+       tristate "eLBC/GPCM driver"
+       depends on FSL_LBC
+       help
+         Generic driver for accessing a peripheral connected to an eLBC port
+         that is running in GPCM mode. GPCM is an interface for simple lower
+         performance memories and memory-mapped devices. For devices using
+         FCM or UPM eLBC modes, other device-specific drivers are available.
+
+config UIO_FSL_ELBC_GPCM_NETX5152
+       bool "eLBC/GPCM netX 51/52 support"
+       depends on UIO_FSL_ELBC_GPCM
+       help
+         This will add support for netX 51/52 devices connected via eLBC/GPCM.
+         In particular, it implements interrupt handling. This can be used
+         together with the userspace netX stack from Hilscher.
+
+         Information about this hardware can be found at:
+         http://www.hilscher.com/netx
+
 config UIO_PRUSS
        tristate "Texas Instruments PRUSS driver"
        depends on ARCH_DAVINCI_DA850
index d3218bde3aeb658948a8675ac62f0ebbbfcaec9b..8560dad52d0f2934d4c67b7aac8d96e929de458a 100644 (file)
@@ -8,3 +8,4 @@ obj-$(CONFIG_UIO_PCI_GENERIC)   += uio_pci_generic.o
 obj-$(CONFIG_UIO_NETX) += uio_netx.o
 obj-$(CONFIG_UIO_PRUSS)         += uio_pruss.o
 obj-$(CONFIG_UIO_MF624)         += uio_mf624.o
+obj-$(CONFIG_UIO_FSL_ELBC_GPCM)        += uio_fsl_elbc_gpcm.o
diff --git a/drivers/uio/uio_fsl_elbc_gpcm.c b/drivers/uio/uio_fsl_elbc_gpcm.c
new file mode 100644 (file)
index 0000000..b6cac91
--- /dev/null
@@ -0,0 +1,499 @@
+/* uio_fsl_elbc_gpcm: UIO driver for eLBC/GPCM peripherals
+
+   Copyright (C) 2014 Linutronix GmbH
+     Author: John Ogness <john.ogness@linutronix.de>
+
+   This driver provides UIO access to memory of a peripheral connected
+   to the Freescale enhanced local bus controller (eLBC) interface
+   using the general purpose chip-select mode (GPCM).
+
+   Here is an example of the device tree entries:
+
+       localbus@ffe05000 {
+               ranges = <0x2 0x0 0x0 0xff810000 0x10000>;
+
+               dpm@2,0 {
+                       compatible = "fsl,elbc-gpcm-uio";
+                       reg = <0x2 0x0 0x10000>;
+                       elbc-gpcm-br = <0xff810800>;
+                       elbc-gpcm-or = <0xffff09f7>;
+                       interrupt-parent = <&mpic>;
+                       interrupts = <4 1>;
+                       device_type = "netx5152";
+                       uio_name = "netx_custom";
+                       netx5152,init-win0-offset = <0x0>;
+               };
+       };
+
+   Only the entries reg (to identify bank) and elbc-gpcm-* (initial BR/OR
+   values) are required. The entries interrupt*, device_type, and uio_name
+   are optional (as well as any type-specific options such as
+   netx5152,init-win0-offset). As long as no interrupt handler is needed,
+   this driver can be used without any type-specific implementation.
+
+   The netx5152 type has been tested to work with the netX 51/52 hardware
+   from Hilscher using the Hilscher userspace netX stack.
+
+   The netx5152 type should serve as a model to add new type-specific
+   devices as needed.
+*/
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/uio_driver.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#include <asm/fsl_lbc.h>
+
+#define MAX_BANKS 8
+
+struct fsl_elbc_gpcm {
+       struct device *dev;
+       struct fsl_lbc_regs __iomem *lbc;
+       u32 bank;
+       const char *name;
+
+       void (*init)(struct uio_info *info);
+       void (*shutdown)(struct uio_info *info, bool init_err);
+       irqreturn_t (*irq_handler)(int irq, struct uio_info *info);
+};
+
+static ssize_t reg_show(struct device *dev, struct device_attribute *attr,
+                       char *buf);
+static ssize_t reg_store(struct device *dev, struct device_attribute *attr,
+                        const char *buf, size_t count);
+
+DEVICE_ATTR(reg_br, S_IRUGO|S_IWUSR|S_IWGRP, reg_show, reg_store);
+DEVICE_ATTR(reg_or, S_IRUGO|S_IWUSR|S_IWGRP, reg_show, reg_store);
+
+static ssize_t reg_show(struct device *dev, struct device_attribute *attr,
+                       char *buf)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct uio_info *info = platform_get_drvdata(pdev);
+       struct fsl_elbc_gpcm *priv = info->priv;
+       struct fsl_lbc_bank *bank = &priv->lbc->bank[priv->bank];
+
+       if (attr == &dev_attr_reg_br) {
+               return scnprintf(buf, PAGE_SIZE, "0x%08x\n",
+                                in_be32(&bank->br));
+
+       } else if (attr == &dev_attr_reg_or) {
+               return scnprintf(buf, PAGE_SIZE, "0x%08x\n",
+                                in_be32(&bank->or));
+       }
+
+       return 0;
+}
+
+static ssize_t reg_store(struct device *dev, struct device_attribute *attr,
+                        const char *buf, size_t count)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct uio_info *info = platform_get_drvdata(pdev);
+       struct fsl_elbc_gpcm *priv = info->priv;
+       struct fsl_lbc_bank *bank = &priv->lbc->bank[priv->bank];
+       unsigned long val;
+       u32 reg_br_cur;
+       u32 reg_or_cur;
+       u32 reg_new;
+
+       /* parse use input */
+       if (kstrtoul(buf, 0, &val) != 0)
+               return -EINVAL;
+       reg_new = (u32)val;
+
+       /* read current values */
+       reg_br_cur = in_be32(&bank->br);
+       reg_or_cur = in_be32(&bank->or);
+
+       if (attr == &dev_attr_reg_br) {
+               /* not allowed to change effective base address */
+               if ((reg_br_cur & reg_or_cur & BR_BA) !=
+                   (reg_new & reg_or_cur & BR_BA)) {
+                       return -EINVAL;
+               }
+
+               /* not allowed to change mode */
+               if ((reg_new & BR_MSEL) != BR_MS_GPCM)
+                       return -EINVAL;
+
+               /* write new value (force valid) */
+               out_be32(&bank->br, reg_new | BR_V);
+
+       } else if (attr == &dev_attr_reg_or) {
+               /* not allowed to change access mask */
+               if ((reg_or_cur & OR_GPCM_AM) != (reg_new & OR_GPCM_AM))
+                       return -EINVAL;
+
+               /* write new value */
+               out_be32(&bank->or, reg_new);
+
+       } else {
+               return -EINVAL;
+       }
+
+       return count;
+}
+
+#ifdef CONFIG_UIO_FSL_ELBC_GPCM_NETX5152
+#define DPM_HOST_WIN0_OFFSET   0xff00
+#define DPM_HOST_INT_STAT0     0xe0
+#define DPM_HOST_INT_EN0       0xf0
+#define DPM_HOST_INT_MASK      0xe600ffff
+#define DPM_HOST_INT_GLOBAL_EN 0x80000000
+
+static irqreturn_t netx5152_irq_handler(int irq, struct uio_info *info)
+{
+       void __iomem *reg_int_en = info->mem[0].internal_addr +
+                                       DPM_HOST_WIN0_OFFSET +
+                                       DPM_HOST_INT_EN0;
+       void __iomem *reg_int_stat = info->mem[0].internal_addr +
+                                       DPM_HOST_WIN0_OFFSET +
+                                       DPM_HOST_INT_STAT0;
+
+       /* check if an interrupt is enabled and active */
+       if ((ioread32(reg_int_en) & ioread32(reg_int_stat) &
+            DPM_HOST_INT_MASK) == 0) {
+               return IRQ_NONE;
+       }
+
+       /* disable interrupts */
+       iowrite32(ioread32(reg_int_en) & ~DPM_HOST_INT_GLOBAL_EN, reg_int_en);
+
+       return IRQ_HANDLED;
+}
+
+static void netx5152_init(struct uio_info *info)
+{
+       unsigned long win0_offset = DPM_HOST_WIN0_OFFSET;
+       struct fsl_elbc_gpcm *priv = info->priv;
+       const void *prop;
+
+       /* get an optional initial win0 offset */
+       prop = of_get_property(priv->dev->of_node,
+                              "netx5152,init-win0-offset", NULL);
+       if (prop)
+               win0_offset = of_read_ulong(prop, 1);
+
+       /* disable interrupts */
+       iowrite32(0, info->mem[0].internal_addr + win0_offset +
+                    DPM_HOST_INT_EN0);
+}
+
+static void netx5152_shutdown(struct uio_info *info, bool init_err)
+{
+       if (init_err)
+               return;
+
+       /* disable interrupts */
+       iowrite32(0, info->mem[0].internal_addr + DPM_HOST_WIN0_OFFSET +
+                    DPM_HOST_INT_EN0);
+}
+#endif
+
+static void setup_periph(struct fsl_elbc_gpcm *priv,
+                                  const char *type)
+{
+#ifdef CONFIG_UIO_FSL_ELBC_GPCM_NETX5152
+       if (strcmp(type, "netx5152") == 0) {
+               priv->irq_handler = netx5152_irq_handler;
+               priv->init = netx5152_init;
+               priv->shutdown = netx5152_shutdown;
+               priv->name = "netX 51/52";
+               return;
+       }
+#endif
+}
+
+static int check_of_data(struct fsl_elbc_gpcm *priv,
+                                  struct resource *res,
+                                  u32 reg_br, u32 reg_or)
+{
+       /* check specified bank */
+       if (priv->bank >= MAX_BANKS) {
+               dev_err(priv->dev, "invalid bank\n");
+               return -ENODEV;
+       }
+
+       /* check specified mode (BR_MS_GPCM is 0) */
+       if ((reg_br & BR_MSEL) != BR_MS_GPCM) {
+               dev_err(priv->dev, "unsupported mode\n");
+               return -ENODEV;
+       }
+
+       /* check specified mask vs. resource size */
+       if ((~(reg_or & OR_GPCM_AM) + 1) != resource_size(res)) {
+               dev_err(priv->dev, "address mask / size mismatch\n");
+               return -ENODEV;
+       }
+
+       /* check specified address */
+       if ((reg_br & reg_or & BR_BA) != fsl_lbc_addr(res->start)) {
+               dev_err(priv->dev, "base address mismatch\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static int get_of_data(struct fsl_elbc_gpcm *priv, struct device_node *node,
+                      struct resource *res, u32 *reg_br,
+                      u32 *reg_or, unsigned int *irq, char **name)
+{
+       const char *dt_name;
+       const char *type;
+       int ret;
+
+       /* get the memory resource */
+       ret = of_address_to_resource(node, 0, res);
+       if (ret) {
+               dev_err(priv->dev, "failed to get resource\n");
+               return ret;
+       }
+
+       /* get the bank number */
+       ret = of_property_read_u32(node, "reg", &priv->bank);
+       if (ret) {
+               dev_err(priv->dev, "failed to get bank number\n");
+               return ret;
+       }
+
+       /* get BR value to set */
+       ret = of_property_read_u32(node, "elbc-gpcm-br", reg_br);
+       if (ret) {
+               dev_err(priv->dev, "missing elbc-gpcm-br value\n");
+               return ret;
+       }
+
+       /* get OR value to set */
+       ret = of_property_read_u32(node, "elbc-gpcm-or", reg_or);
+       if (ret) {
+               dev_err(priv->dev, "missing elbc-gpcm-or value\n");
+               return ret;
+       }
+
+       /* get optional peripheral type */
+       priv->name = "generic";
+       if (of_property_read_string(node, "device_type", &type) == 0)
+               setup_periph(priv, type);
+
+       /* get optional irq value */
+       *irq = irq_of_parse_and_map(node, 0);
+
+       /* sanity check device tree data */
+       ret = check_of_data(priv, res, *reg_br, *reg_or);
+       if (ret)
+               return ret;
+
+       /* get optional uio name */
+       if (of_property_read_string(node, "uio_name", &dt_name) != 0)
+               dt_name = "eLBC_GPCM";
+       *name = kstrdup(dt_name, GFP_KERNEL);
+       if (!*name)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static int uio_fsl_elbc_gpcm_probe(struct platform_device *pdev)
+{
+       struct device_node *node = pdev->dev.of_node;
+       struct fsl_elbc_gpcm *priv;
+       struct uio_info *info;
+       char *uio_name = NULL;
+       struct resource res;
+       unsigned int irq;
+       u32 reg_br_cur;
+       u32 reg_or_cur;
+       u32 reg_br_new;
+       u32 reg_or_new;
+       int ret;
+
+       if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
+               return -ENODEV;
+
+       /* allocate private data */
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+       priv->dev = &pdev->dev;
+       priv->lbc = fsl_lbc_ctrl_dev->regs;
+
+       /* get device tree data */
+       ret = get_of_data(priv, node, &res, &reg_br_new, &reg_or_new,
+                         &irq, &uio_name);
+       if (ret)
+               goto out_err0;
+
+       /* allocate UIO structure */
+       info = kzalloc(sizeof(*info), GFP_KERNEL);
+       if (!info) {
+               ret = -ENOMEM;
+               goto out_err0;
+       }
+
+       /* get current BR/OR values */
+       reg_br_cur = in_be32(&priv->lbc->bank[priv->bank].br);
+       reg_or_cur = in_be32(&priv->lbc->bank[priv->bank].or);
+
+       /* if bank already configured, make sure it matches */
+       if ((reg_br_cur & BR_V)) {
+               if ((reg_br_cur & BR_MSEL) != BR_MS_GPCM ||
+                   (reg_br_cur & reg_or_cur & BR_BA)
+                    != fsl_lbc_addr(res.start)) {
+                       dev_err(priv->dev,
+                               "bank in use by another peripheral\n");
+                       ret = -ENODEV;
+                       goto out_err1;
+               }
+
+               /* warn if behavior settings changing */
+               if ((reg_br_cur & ~(BR_BA | BR_V)) !=
+                   (reg_br_new & ~(BR_BA | BR_V))) {
+                       dev_warn(priv->dev,
+                                "modifying BR settings: 0x%08x -> 0x%08x",
+                                reg_br_cur, reg_br_new);
+               }
+               if ((reg_or_cur & ~OR_GPCM_AM) != (reg_or_new & ~OR_GPCM_AM)) {
+                       dev_warn(priv->dev,
+                                "modifying OR settings: 0x%08x -> 0x%08x",
+                                reg_or_cur, reg_or_new);
+               }
+       }
+
+       /* configure the bank (force base address and GPCM) */
+       reg_br_new &= ~(BR_BA | BR_MSEL);
+       reg_br_new |= fsl_lbc_addr(res.start) | BR_MS_GPCM | BR_V;
+       out_be32(&priv->lbc->bank[priv->bank].or, reg_or_new);
+       out_be32(&priv->lbc->bank[priv->bank].br, reg_br_new);
+
+       /* map the memory resource */
+       info->mem[0].internal_addr = ioremap(res.start, resource_size(&res));
+       if (!info->mem[0].internal_addr) {
+               dev_err(priv->dev, "failed to map chip region\n");
+               ret = -ENODEV;
+               goto out_err1;
+       }
+
+       /* set all UIO data */
+       if (node->name)
+               info->mem[0].name = kstrdup(node->name, GFP_KERNEL);
+       info->mem[0].addr = res.start;
+       info->mem[0].size = resource_size(&res);
+       info->mem[0].memtype = UIO_MEM_PHYS;
+       info->priv = priv;
+       info->name = uio_name;
+       info->version = "0.0.1";
+       if (irq != NO_IRQ) {
+               if (priv->irq_handler) {
+                       info->irq = irq;
+                       info->irq_flags = IRQF_SHARED;
+                       info->handler = priv->irq_handler;
+               } else {
+                       irq = NO_IRQ;
+                       dev_warn(priv->dev, "ignoring irq, no handler\n");
+               }
+       }
+
+       if (priv->init)
+               priv->init(info);
+
+       /* register UIO device */
+       if (uio_register_device(priv->dev, info) != 0) {
+               dev_err(priv->dev, "UIO registration failed\n");
+               ret = -ENODEV;
+               goto out_err2;
+       }
+
+       /* store private data */
+       platform_set_drvdata(pdev, info);
+
+       /* create sysfs files */
+       ret = device_create_file(priv->dev, &dev_attr_reg_br);
+       if (ret)
+               goto out_err3;
+       ret = device_create_file(priv->dev, &dev_attr_reg_or);
+       if (ret)
+               goto out_err4;
+
+       dev_info(priv->dev,
+                "eLBC/GPCM device (%s) at 0x%llx, bank %d, irq=%d\n",
+                priv->name, (unsigned long long)res.start, priv->bank,
+                irq != NO_IRQ ? irq : -1);
+
+       return 0;
+out_err4:
+       device_remove_file(priv->dev, &dev_attr_reg_br);
+out_err3:
+       platform_set_drvdata(pdev, NULL);
+       uio_unregister_device(info);
+out_err2:
+       if (priv->shutdown)
+               priv->shutdown(info, true);
+       iounmap(info->mem[0].internal_addr);
+out_err1:
+       kfree(info->mem[0].name);
+       kfree(info);
+out_err0:
+       kfree(uio_name);
+       kfree(priv);
+       return ret;
+}
+
+static int uio_fsl_elbc_gpcm_remove(struct platform_device *pdev)
+{
+       struct uio_info *info = platform_get_drvdata(pdev);
+       struct fsl_elbc_gpcm *priv = info->priv;
+
+       device_remove_file(priv->dev, &dev_attr_reg_or);
+       device_remove_file(priv->dev, &dev_attr_reg_br);
+       platform_set_drvdata(pdev, NULL);
+       uio_unregister_device(info);
+       if (priv->shutdown)
+               priv->shutdown(info, false);
+       iounmap(info->mem[0].internal_addr);
+       kfree(info->mem[0].name);
+       kfree(info->name);
+       kfree(info);
+       kfree(priv);
+
+       return 0;
+
+}
+
+static const struct of_device_id uio_fsl_elbc_gpcm_match[] = {
+       { .compatible = "fsl,elbc-gpcm-uio", },
+       {}
+};
+
+static struct platform_driver uio_fsl_elbc_gpcm_driver = {
+       .driver = {
+               .name = "fsl,elbc-gpcm-uio",
+               .owner = THIS_MODULE,
+               .of_match_table = uio_fsl_elbc_gpcm_match,
+       },
+       .probe = uio_fsl_elbc_gpcm_probe,
+       .remove = uio_fsl_elbc_gpcm_remove,
+};
+
+static int __init uio_fsl_elbc_gpcm_init(void)
+{
+       return platform_driver_register(&uio_fsl_elbc_gpcm_driver);
+}
+
+static void __exit uio_fsl_elbc_gpcm_exit(void)
+{
+       platform_driver_unregister(&uio_fsl_elbc_gpcm_driver);
+}
+
+module_init(uio_fsl_elbc_gpcm_init);
+module_exit(uio_fsl_elbc_gpcm_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Ogness <john.ogness@linutronix.de>");
+MODULE_DESCRIPTION("Freescale Enhanced Local Bus Controller GPCM driver");
index 077ae12269ce3a99fcc35ee099e6453a102484de..d0b508b68f3c3e4969bf46036510255d01ae7dd9 100644 (file)
@@ -91,7 +91,8 @@ static int probe(struct pci_dev *pdev,
        gdev->info.handler = irqhandler;
        gdev->pdev = pdev;
 
-       if (uio_register_device(&pdev->dev, &gdev->info))
+       err = uio_register_device(&pdev->dev, &gdev->info);
+       if (err)
                goto err_register;
        pci_set_drvdata(pdev, gdev);
 
index 7516030037a16e18082908b41af76a7308c85cb9..d95fb848dd03368c26c4d0b59020e5ac02a0b893 100644 (file)
@@ -502,7 +502,7 @@ int vme_master_get(struct vme_resource *resource, int *enabled,
        image = list_entry(resource->entry, struct vme_master_resource, list);
 
        if (bridge->master_get == NULL) {
-               printk(KERN_WARNING "vme_master_set not supported\n");
+               printk(KERN_WARNING "%s not supported\n", __func__);
                return -EINVAL;
        }
 
index 5d3c54311f7a30f16fe37e9c5dc8edd2d48100eb..3486b9082adbcf885d62d0011f32e1ac2709eb11 100644 (file)
@@ -179,15 +179,6 @@ struct coresight_device {
 #define sink_ops(csdev)                csdev->ops->sink_ops
 #define link_ops(csdev)                csdev->ops->link_ops
 
-#define CORESIGHT_DEBUGFS_ENTRY(__name, __entry_name,                  \
-                                __mode, __get, __set, __fmt)           \
-DEFINE_SIMPLE_ATTRIBUTE(__name ## _ops, __get, __set, __fmt);          \
-static const struct coresight_ops_entry __name ## _entry = {           \
-       .name = __entry_name,                                           \
-       .mode = __mode,                                                 \
-       .ops  = &__name ## _ops                                         \
-}
-
 /**
  * struct coresight_ops_sink - basic operations for a sink
  * Operations available for sinks
@@ -236,13 +227,8 @@ coresight_register(struct coresight_desc *desc);
 extern void coresight_unregister(struct coresight_device *csdev);
 extern int coresight_enable(struct coresight_device *csdev);
 extern void coresight_disable(struct coresight_device *csdev);
-extern int coresight_is_bit_set(u32 val, int position, int value);
 extern int coresight_timeout(void __iomem *addr, u32 offset,
                             int position, int value);
-#ifdef CONFIG_OF
-extern struct coresight_platform_data *of_get_coresight_platform_data(
-                               struct device *dev, struct device_node *node);
-#endif
 #else
 static inline struct coresight_device *
 coresight_register(struct coresight_desc *desc) { return NULL; }
@@ -250,14 +236,16 @@ static inline void coresight_unregister(struct coresight_device *csdev) {}
 static inline int
 coresight_enable(struct coresight_device *csdev) { return -ENOSYS; }
 static inline void coresight_disable(struct coresight_device *csdev) {}
-static inline int coresight_is_bit_set(u32 val, int position, int value)
-                                        { return 0; }
 static inline int coresight_timeout(void __iomem *addr, u32 offset,
                                     int position, int value) { return 1; }
+#endif
+
 #ifdef CONFIG_OF
+extern struct coresight_platform_data *of_get_coresight_platform_data(
+                               struct device *dev, struct device_node *node);
+#else
 static inline struct coresight_platform_data *of_get_coresight_platform_data(
        struct device *dev, struct device_node *node) { return NULL; }
 #endif
-#endif
 
 #endif
index 476c685ca6f9c5c6447944aee2fa98a85cdd14e4..5a2ba674795eaf2b2b281eaa17289748cbc84320 100644 (file)
@@ -57,6 +57,18 @@ struct hv_multipage_buffer {
        u64 pfn_array[MAX_MULTIPAGE_BUFFER_COUNT];
 };
 
+/*
+ * Multiple-page buffer array; the pfn array is variable size:
+ * The number of entries in the PFN array is determined by
+ * "len" and "offset".
+ */
+struct hv_mpb_array {
+       /* Length and Offset determines the # of pfns in the array */
+       u32 len;
+       u32 offset;
+       u64 pfn_array[];
+};
+
 /* 0x18 includes the proprietary packet header */
 #define MAX_PAGE_BUFFER_PACKET         (0x18 +                 \
                                        (sizeof(struct hv_page_buffer) * \
@@ -722,7 +734,12 @@ struct vmbus_channel {
         */
        void (*sc_creation_callback)(struct vmbus_channel *new_sc);
 
-       spinlock_t sc_lock;
+       /*
+        * The spinlock to protect the structure. It is being used to protect
+        * test-and-set access to various attributes of the structure as well
+        * as all sc_list operations.
+        */
+       spinlock_t lock;
        /*
         * All Sub-channels of a primary channel are linked here.
         */
@@ -814,6 +831,18 @@ struct vmbus_channel_packet_multipage_buffer {
        struct hv_multipage_buffer range;
 } __packed;
 
+/* The format must be the same as struct vmdata_gpa_direct */
+struct vmbus_packet_mpb_array {
+       u16 type;
+       u16 dataoffset8;
+       u16 length8;
+       u16 flags;
+       u64 transactionid;
+       u32 reserved;
+       u32 rangecount;         /* Always 1 in this case */
+       struct hv_mpb_array range;
+} __packed;
+
 
 extern int vmbus_open(struct vmbus_channel *channel,
                            u32 send_ringbuffersize,
@@ -845,6 +874,13 @@ extern int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel,
                                        u32 bufferlen,
                                        u64 requestid);
 
+extern int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel,
+                                    struct vmbus_packet_mpb_array *mpb,
+                                    u32 desc_size,
+                                    void *buffer,
+                                    u32 bufferlen,
+                                    u64 requestid);
+
 extern int vmbus_establish_gpadl(struct vmbus_channel *channel,
                                      void *kbuffer,
                                      u32 size,
index 164aad1f9f12172a3969035f9d484d501758157d..0819d36a3a742f63670f4ae953c5a3a66a3fa9d0 100644 (file)
@@ -25,8 +25,8 @@ int __mei_cl_driver_register(struct mei_cl_driver *driver,
 
 void mei_cl_driver_unregister(struct mei_cl_driver *driver);
 
-int mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length);
-int mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length);
+ssize_t mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length);
+ssize_t  mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length);
 
 typedef void (*mei_cl_event_cb_t)(struct mei_cl_device *device,
                               u32 events, void *context);
index ba96471c11bae88b6673faec4d4a268cf550db1b..a1b7dbd127ffc73c1c07f3935ed9cd9118cfec52 100644 (file)
@@ -1281,6 +1281,25 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *     @alter contains the flag indicating whether changes are to be made.
  *     Return 0 if permission is granted.
  *
+ * @binder_set_context_mgr
+ *     Check whether @mgr is allowed to be the binder context manager.
+ *     @mgr contains the task_struct for the task being registered.
+ *     Return 0 if permission is granted.
+ * @binder_transaction
+ *     Check whether @from is allowed to invoke a binder transaction call
+ *     to @to.
+ *     @from contains the task_struct for the sending task.
+ *     @to contains the task_struct for the receiving task.
+ * @binder_transfer_binder
+ *     Check whether @from is allowed to transfer a binder reference to @to.
+ *     @from contains the task_struct for the sending task.
+ *     @to contains the task_struct for the receiving task.
+ * @binder_transfer_file
+ *     Check whether @from is allowed to transfer @file to @to.
+ *     @from contains the task_struct for the sending task.
+ *     @file contains the struct file being transferred.
+ *     @to contains the task_struct for the receiving task.
+ *
  * @ptrace_access_check:
  *     Check permission before allowing the current process to trace the
  *     @child process.
@@ -1441,6 +1460,14 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
 struct security_operations {
        char name[SECURITY_NAME_MAX + 1];
 
+       int (*binder_set_context_mgr) (struct task_struct *mgr);
+       int (*binder_transaction) (struct task_struct *from,
+                                  struct task_struct *to);
+       int (*binder_transfer_binder) (struct task_struct *from,
+                                      struct task_struct *to);
+       int (*binder_transfer_file) (struct task_struct *from,
+                                    struct task_struct *to, struct file *file);
+
        int (*ptrace_access_check) (struct task_struct *child, unsigned int mode);
        int (*ptrace_traceme) (struct task_struct *parent);
        int (*capget) (struct task_struct *target,
@@ -1739,6 +1766,13 @@ extern void __init security_fixup_ops(struct security_operations *ops);
 
 
 /* Security operations */
+int security_binder_set_context_mgr(struct task_struct *mgr);
+int security_binder_transaction(struct task_struct *from,
+                               struct task_struct *to);
+int security_binder_transfer_binder(struct task_struct *from,
+                                   struct task_struct *to);
+int security_binder_transfer_file(struct task_struct *from,
+                                 struct task_struct *to, struct file *file);
 int security_ptrace_access_check(struct task_struct *child, unsigned int mode);
 int security_ptrace_traceme(struct task_struct *parent);
 int security_capget(struct task_struct *target,
@@ -1927,6 +1961,30 @@ static inline int security_init(void)
        return 0;
 }
 
+static inline int security_binder_set_context_mgr(struct task_struct *mgr)
+{
+       return 0;
+}
+
+static inline int security_binder_transaction(struct task_struct *from,
+                                             struct task_struct *to)
+{
+       return 0;
+}
+
+static inline int security_binder_transfer_binder(struct task_struct *from,
+                                                 struct task_struct *to)
+{
+       return 0;
+}
+
+static inline int security_binder_transfer_file(struct task_struct *from,
+                                               struct task_struct *to,
+                                               struct file *file)
+{
+       return 0;
+}
+
 static inline int security_ptrace_access_check(struct task_struct *child,
                                             unsigned int mode)
 {
index 884d6263e962499483f40b4dd29e9d99393ad799..c78dcfeaf25f846ce105274d7c905aa181a53174 100644 (file)
@@ -86,6 +86,7 @@ struct st_proto_s {
 extern long st_register(struct st_proto_s *);
 extern long st_unregister(struct st_proto_s *);
 
+extern struct ti_st_plat_data   *dt_pdata;
 
 /*
  * header information used by st_core.c
@@ -261,7 +262,7 @@ struct kim_data_s {
        struct completion kim_rcvd, ldisc_installed;
        char resp_buffer[30];
        const struct firmware *fw_entry;
-       long nshutdown;
+       unsigned nshutdown;
        unsigned long rx_state;
        unsigned long rx_count;
        struct sk_buff *rx_skb;
@@ -269,8 +270,8 @@ struct kim_data_s {
        struct chip_version version;
        unsigned char ldisc_install;
        unsigned char dev_name[UART_DEV_NAME_LEN + 1];
-       unsigned char flow_cntrl;
-       unsigned long baud_rate;
+       unsigned flow_cntrl;
+       unsigned baud_rate;
 };
 
 /**
@@ -436,10 +437,10 @@ struct gps_event_hdr {
  *
  */
 struct ti_st_plat_data {
-       long nshutdown_gpio;
+       u32 nshutdown_gpio;
        unsigned char dev_name[UART_DEV_NAME_LEN]; /* uart name */
-       unsigned char flow_cntrl; /* flow control flag */
-       unsigned long baud_rate;
+       u32 flow_cntrl; /* flow control flag */
+       u32 baud_rate;
        int (*suspend)(struct platform_device *, pm_message_t);
        int (*resume)(struct platform_device *);
        int (*chip_enable) (struct kim_data_s *);
index d68c57a62bcf72694b7705292ac3a61592dc67af..070dd46f62f4f57c7262211352775e121439e8a2 100644 (file)
 
 #include <linux/security.h>
 
+static int cap_binder_set_context_mgr(struct task_struct *mgr)
+{
+       return 0;
+}
+
+static int cap_binder_transaction(struct task_struct *from,
+                                 struct task_struct *to)
+{
+       return 0;
+}
+
+static int cap_binder_transfer_binder(struct task_struct *from,
+                                     struct task_struct *to)
+{
+       return 0;
+}
+
+static int cap_binder_transfer_file(struct task_struct *from,
+                                   struct task_struct *to, struct file *file)
+{
+       return 0;
+}
+
 static int cap_syslog(int type)
 {
        return 0;
@@ -930,6 +953,10 @@ static void cap_audit_rule_free(void *lsmrule)
 
 void __init security_fixup_ops(struct security_operations *ops)
 {
+       set_to_cap_if_null(ops, binder_set_context_mgr);
+       set_to_cap_if_null(ops, binder_transaction);
+       set_to_cap_if_null(ops, binder_transfer_binder);
+       set_to_cap_if_null(ops, binder_transfer_file);
        set_to_cap_if_null(ops, ptrace_access_check);
        set_to_cap_if_null(ops, ptrace_traceme);
        set_to_cap_if_null(ops, capget);
index a0442b20f001b80f6cf567c8aad4e9a038e901d3..e81d5bbe7363fc689199ea8db3a1a5fdc3e720e4 100644 (file)
@@ -135,6 +135,29 @@ int __init register_security(struct security_operations *ops)
 
 /* Security operations */
 
+int security_binder_set_context_mgr(struct task_struct *mgr)
+{
+       return security_ops->binder_set_context_mgr(mgr);
+}
+
+int security_binder_transaction(struct task_struct *from,
+                               struct task_struct *to)
+{
+       return security_ops->binder_transaction(from, to);
+}
+
+int security_binder_transfer_binder(struct task_struct *from,
+                                   struct task_struct *to)
+{
+       return security_ops->binder_transfer_binder(from, to);
+}
+
+int security_binder_transfer_file(struct task_struct *from,
+                                 struct task_struct *to, struct file *file)
+{
+       return security_ops->binder_transfer_file(from, to, file);
+}
+
 int security_ptrace_access_check(struct task_struct *child, unsigned int mode)
 {
 #ifdef CONFIG_SECURITY_YAMA_STACKED
index 87a915656eab61eb3c34638852ef2b91cdeee086..29c39e0b03ed7e3048d5fed858f31d40dc2f8d3d 100644 (file)
@@ -1920,6 +1920,74 @@ static inline u32 open_file_to_av(struct file *file)
 
 /* Hook functions begin here. */
 
+static int selinux_binder_set_context_mgr(struct task_struct *mgr)
+{
+       u32 mysid = current_sid();
+       u32 mgrsid = task_sid(mgr);
+
+       return avc_has_perm(mysid, mgrsid, SECCLASS_BINDER,
+                           BINDER__SET_CONTEXT_MGR, NULL);
+}
+
+static int selinux_binder_transaction(struct task_struct *from,
+                                     struct task_struct *to)
+{
+       u32 mysid = current_sid();
+       u32 fromsid = task_sid(from);
+       u32 tosid = task_sid(to);
+       int rc;
+
+       if (mysid != fromsid) {
+               rc = avc_has_perm(mysid, fromsid, SECCLASS_BINDER,
+                                 BINDER__IMPERSONATE, NULL);
+               if (rc)
+                       return rc;
+       }
+
+       return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__CALL,
+                           NULL);
+}
+
+static int selinux_binder_transfer_binder(struct task_struct *from,
+                                         struct task_struct *to)
+{
+       u32 fromsid = task_sid(from);
+       u32 tosid = task_sid(to);
+
+       return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__TRANSFER,
+                           NULL);
+}
+
+static int selinux_binder_transfer_file(struct task_struct *from,
+                                       struct task_struct *to,
+                                       struct file *file)
+{
+       u32 sid = task_sid(to);
+       struct file_security_struct *fsec = file->f_security;
+       struct inode *inode = file->f_path.dentry->d_inode;
+       struct inode_security_struct *isec = inode->i_security;
+       struct common_audit_data ad;
+       int rc;
+
+       ad.type = LSM_AUDIT_DATA_PATH;
+       ad.u.path = file->f_path;
+
+       if (sid != fsec->sid) {
+               rc = avc_has_perm(sid, fsec->sid,
+                                 SECCLASS_FD,
+                                 FD__USE,
+                                 &ad);
+               if (rc)
+                       return rc;
+       }
+
+       if (unlikely(IS_PRIVATE(inode)))
+               return 0;
+
+       return avc_has_perm(sid, isec->sid, isec->sclass, file_to_av(file),
+                           &ad);
+}
+
 static int selinux_ptrace_access_check(struct task_struct *child,
                                     unsigned int mode)
 {
@@ -5797,6 +5865,11 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer)
 static struct security_operations selinux_ops = {
        .name =                         "selinux",
 
+       .binder_set_context_mgr =       selinux_binder_set_context_mgr,
+       .binder_transaction =           selinux_binder_transaction,
+       .binder_transfer_binder =       selinux_binder_transfer_binder,
+       .binder_transfer_file =         selinux_binder_transfer_file,
+
        .ptrace_access_check =          selinux_ptrace_access_check,
        .ptrace_traceme =               selinux_ptrace_traceme,
        .capget =                       selinux_capget,
index be491a74c1edc4a279f76121dab615305c3a47f2..eccd61b3de8aa34f8c3664f0e62955eda52ce3c2 100644 (file)
@@ -151,5 +151,7 @@ struct security_class_mapping secclass_map[] = {
        { "kernel_service", { "use_as_override", "create_files_as", NULL } },
        { "tun_socket",
          { COMMON_SOCK_PERMS, "attach_queue", NULL } },
+       { "binder", { "impersonate", "call", "set_context_mgr", "transfer",
+                     NULL } },
        { NULL }
   };
index bd22f786a60c7738fac9c79843b003fe408b889b..99ffe61051a702ab386a45a13c364bc1a77f0f25 100644 (file)
@@ -5,9 +5,9 @@ PTHREAD_LIBS = -lpthread
 WARNINGS = -Wall -Wextra
 CFLAGS = $(WARNINGS) -g $(PTHREAD_LIBS)
 
-all: hv_kvp_daemon hv_vss_daemon
+all: hv_kvp_daemon hv_vss_daemon hv_fcopy_daemon
 %: %.c
        $(CC) $(CFLAGS) -o $@ $^
 
 clean:
-       $(RM) hv_kvp_daemon hv_vss_daemon
+       $(RM) hv_kvp_daemon hv_vss_daemon hv_fcopy_daemon
index f437d739f37da6fca68165b983e4137c2622f317..9445d8f264a4612fb4ebd2b5c4251b999a21a6c3 100644 (file)
@@ -43,15 +43,9 @@ static int hv_start_fcopy(struct hv_start_fcopy *smsg)
        int error = HV_E_FAIL;
        char *q, *p;
 
-       /*
-        * If possile append a path seperator to the path.
-        */
-       if (strlen((char *)smsg->path_name) < (W_MAX_PATH - 2))
-               strcat((char *)smsg->path_name, "/");
-
        p = (char *)smsg->path_name;
        snprintf(target_fname, sizeof(target_fname), "%s/%s",
-               (char *)smsg->path_name, smsg->file_name);
+                (char *)smsg->path_name, (char *)smsg->file_name);
 
        syslog(LOG_INFO, "Target file name: %s", target_fname);
        /*
@@ -137,7 +131,7 @@ void print_usage(char *argv[])
 
 int main(int argc, char *argv[])
 {
-       int fd, fcopy_fd, len;
+       int fcopy_fd, len;
        int error;
        int daemonize = 1, long_index = 0, opt;
        int version = FCOPY_CURRENT_VERSION;
index 6a6432a20a1dacced175e006f36fed4265e919a2..408bb076a23419e37ad604d0901496ae17745341 100644 (file)
@@ -147,7 +147,6 @@ static void kvp_release_lock(int pool)
 static void kvp_update_file(int pool)
 {
        FILE *filep;
-       size_t bytes_written;
 
        /*
         * We are going to write our in-memory registry out to
@@ -163,8 +162,7 @@ static void kvp_update_file(int pool)
                exit(EXIT_FAILURE);
        }
 
-       bytes_written = fwrite(kvp_file_info[pool].records,
-                               sizeof(struct kvp_record),
+       fwrite(kvp_file_info[pool].records, sizeof(struct kvp_record),
                                kvp_file_info[pool].num_records, filep);
 
        if (ferror(filep) || fclose(filep)) {
@@ -310,7 +308,7 @@ static int kvp_file_init(void)
        return 0;
 }
 
-static int kvp_key_delete(int pool, const char *key, int key_size)
+static int kvp_key_delete(int pool, const __u8 *key, int key_size)
 {
        int i;
        int j, k;
@@ -353,8 +351,8 @@ static int kvp_key_delete(int pool, const char *key, int key_size)
        return 1;
 }
 
-static int kvp_key_add_or_modify(int pool, const char *key, int key_size, const char *value,
-                       int value_size)
+static int kvp_key_add_or_modify(int pool, const __u8 *key, int key_size,
+                                const __u8 *value, int value_size)
 {
        int i;
        int num_records;
@@ -407,7 +405,7 @@ static int kvp_key_add_or_modify(int pool, const char *key, int key_size, const
        return 0;
 }
 
-static int kvp_get_value(int pool, const char *key, int key_size, char *value,
+static int kvp_get_value(int pool, const __u8 *key, int key_size, __u8 *value,
                        int value_size)
 {
        int i;
@@ -439,8 +437,8 @@ static int kvp_get_value(int pool, const char *key, int key_size, char *value,
        return 1;
 }
 
-static int kvp_pool_enumerate(int pool, int index, char *key, int key_size,
-                               char *value, int value_size)
+static int kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size,
+                               __u8 *value, int value_size)
 {
        struct kvp_record *record;
 
@@ -661,7 +659,7 @@ static char *kvp_if_name_to_mac(char *if_name)
        char    *p, *x;
        char    buf[256];
        char addr_file[256];
-       int i;
+       unsigned int i;
        char *mac_addr = NULL;
 
        snprintf(addr_file, sizeof(addr_file), "%s%s%s", "/sys/class/net/",
@@ -700,7 +698,7 @@ static char *kvp_mac_to_if_name(char *mac)
        char    buf[256];
        char *kvp_net_dir = "/sys/class/net/";
        char dev_id[256];
-       int i;
+       unsigned int i;
 
        dir = opendir(kvp_net_dir);
        if (dir == NULL)
@@ -750,7 +748,7 @@ static char *kvp_mac_to_if_name(char *mac)
 
 
 static void kvp_process_ipconfig_file(char *cmd,
-                                       char *config_buf, int len,
+                                       char *config_buf, unsigned int len,
                                        int element_size, int offset)
 {
        char buf[256];
@@ -768,7 +766,7 @@ static void kvp_process_ipconfig_file(char *cmd,
        if (offset == 0)
                memset(config_buf, 0, len);
        while ((p = fgets(buf, sizeof(buf), file)) != NULL) {
-               if ((len - strlen(config_buf)) < (element_size + 1))
+               if (len < strlen(config_buf) + element_size + 1)
                        break;
 
                x = strchr(p, '\n');
@@ -916,7 +914,7 @@ static int kvp_process_ip_address(void *addrp,
 
 static int
 kvp_get_ip_info(int family, char *if_name, int op,
-                void  *out_buffer, int length)
+                void  *out_buffer, unsigned int length)
 {
        struct ifaddrs *ifap;
        struct ifaddrs *curp;
@@ -1019,8 +1017,7 @@ kvp_get_ip_info(int family, char *if_name, int op,
                                        weight += hweight32(&w[i]);
 
                                sprintf(cidr_mask, "/%d", weight);
-                               if ((length - sn_offset) <
-                                       (strlen(cidr_mask) + 1))
+                               if (length < sn_offset + strlen(cidr_mask) + 1)
                                        goto gather_ipaddr;
 
                                if (sn_offset == 0)
@@ -1308,16 +1305,17 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
        if (error)
                goto setval_error;
 
+       /*
+        * The dhcp_enabled flag is only for IPv4. In the case the host only
+        * injects an IPv6 address, the flag is true, but we still need to
+        * proceed to parse and pass the IPv6 information to the
+        * disto-specific script hv_set_ifconfig.
+        */
        if (new_val->dhcp_enabled) {
                error = kvp_write_file(file, "BOOTPROTO", "", "dhcp");
                if (error)
                        goto setval_error;
 
-               /*
-                * We are done!.
-                */
-               goto setval_done;
-
        } else {
                error = kvp_write_file(file, "BOOTPROTO", "", "none");
                if (error)
@@ -1345,7 +1343,6 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
        if (error)
                goto setval_error;
 
-setval_done:
        fclose(file);
 
        /*