Merge tag 'pm+acpi-4.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 15 Apr 2015 03:21:54 +0000 (20:21 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 15 Apr 2015 03:21:54 +0000 (20:21 -0700)
Pull power management and ACPI updates from Rafael Wysocki:
 "These are mostly fixes and cleanups all over, although there are a few
  items that sort of fall into the new feature category.

  First off, we have new callbacks for PM domains that should help us to
  handle some issues related to device initialization in a better way.

  There also is some consolidation in the unified device properties API
  area allowing us to use that inferface for accessing data coming from
  platform initialization code in addition to firmware-provided data.

  We have some new device/CPU IDs in a few drivers, support for new
  chips and a new cpufreq driver too.

  Specifics:

   - Generic PM domains support update including new PM domain callbacks
     to handle device initialization better (Russell King, Rafael J
     Wysocki, Kevin Hilman)

   - Unified device properties API update including a new mechanism for
     accessing data provided by platform initialization code (Rafael J
     Wysocki, Adrian Hunter)

   - ARM cpuidle update including ARM32/ARM64 handling consolidation
     (Daniel Lezcano)

   - intel_idle update including support for the Silvermont Core in the
     Baytrail SOC and for the Airmont Core in the Cherrytrail and
     Braswell SOCs (Len Brown, Mathias Krause)

   - New cpufreq driver for Hisilicon ACPU (Leo Yan)

   - intel_pstate update including support for the Knights Landing chip
     (Dasaratharaman Chandramouli, Kristen Carlson Accardi)

   - QorIQ cpufreq driver update (Tang Yuantian, Arnd Bergmann)

   - powernv cpufreq driver update (Shilpasri G Bhat)

   - devfreq update including Tegra support changes (Tomeu Vizoso,
     MyungJoo Ham, Chanwoo Choi)

   - powercap RAPL (Running-Average Power Limit) driver update including
     support for Intel Broadwell server chips (Jacob Pan, Mathias Krause)

   - ACPI device enumeration update related to the handling of the
     special PRP0001 device ID allowing DT-style 'compatible' property
     to be used for ACPI device identification (Rafael J Wysocki)

   - ACPI EC driver update including limited _DEP support (Lan Tianyu,
     Lv Zheng)

   - ACPI backlight driver update including a new mechanism to allow
     native backlight handling to be forced on non-Windows 8 systems and
     a new quirk for Lenovo Ideapad Z570 (Aaron Lu, Hans de Goede)

   - New Windows Vista compatibility quirk for Sony VGN-SR19XN (Chen Yu)

   - Assorted ACPI fixes and cleanups (Aaron Lu, Martin Kepplinger,
     Masanari Iida, Mika Westerberg, Nan Li, Rafael J Wysocki)

   - Fixes related to suspend-to-idle for the iTCO watchdog driver and
     the ACPI core system suspend/resume code (Rafael J Wysocki, Chen Yu)

   - PM tracing support for the suspend phase of system suspend/resume
     transitions (Zhonghui Fu)

   - Configurable delay for the system suspend/resume testing facility
     (Brian Norris)

   - PNP subsystem cleanups (Peter Huewe, Rafael J Wysocki)"

* tag 'pm+acpi-4.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (74 commits)
  ACPI / scan: Fix NULL pointer dereference in acpi_companion_match()
  ACPI / scan: Rework modalias creation when "compatible" is present
  intel_idle: mark cpu id array as __initconst
  powercap / RAPL: mark rapl_ids array as __initconst
  powercap / RAPL: add ID for Broadwell server
  intel_pstate: Knights Landing support
  intel_pstate: remove MSR test
  cpufreq: fix qoriq uniprocessor build
  ACPI / scan: Take the PRP0001 position in the list of IDs into account
  ACPI / scan: Simplify acpi_match_device()
  ACPI / scan: Generalize of_compatible matching
  device property: Introduce firmware node type for platform data
  device property: Make it possible to use secondary firmware nodes
  PM / watchdog: iTCO: stop watchdog during system suspend
  cpufreq: hisilicon: add acpu driver
  ACPI / EC: Call acpi_walk_dep_device_list() after installing EC opregion handler
  cpufreq: powernv: Report cpu frequency throttling
  intel_idle: Add support for the Airmont Core in the Cherrytrail and Braswell SOCs
  intel_idle: Update support for Silvermont Core in Baytrail SOC
  PM / devfreq: tegra: Register governor on module init
  ...

100 files changed:
Documentation/acpi/enumeration.txt
Documentation/kernel-parameters.txt
Documentation/power/basic-pm-debugging.txt
MAINTAINERS
arch/arm/include/asm/cpuidle.h
arch/arm/kernel/cpuidle.c
arch/arm/mach-davinci/cpuidle.c
arch/arm/mach-imx/cpuidle-imx6q.c
arch/arm/mach-imx/cpuidle-imx6sl.c
arch/arm/mach-imx/cpuidle-imx6sx.c
arch/arm/mach-omap2/cpuidle44xx.c
arch/arm/mach-s3c64xx/cpuidle.c
arch/arm/mach-tegra/cpuidle-tegra20.c
arch/arm/mach-tegra/cpuidle-tegra30.c
arch/arm64/configs/defconfig
arch/arm64/include/asm/cpuidle.h
arch/arm64/kernel/cpuidle.c
arch/x86/include/asm/pm-trace.h [new file with mode: 0644]
arch/x86/include/asm/resume-trace.h [deleted file]
drivers/acpi/acpi_platform.c
drivers/acpi/battery.c
drivers/acpi/blacklist.c
drivers/acpi/dock.c
drivers/acpi/ec.c
drivers/acpi/glue.c
drivers/acpi/pmic/intel_pmic_crc.c
drivers/acpi/scan.c
drivers/acpi/sleep.c
drivers/acpi/sleep.h
drivers/acpi/sysfs.c
drivers/acpi/video.c
drivers/acpi/video_detect.c
drivers/ata/pata_isapnp.c
drivers/base/core.c
drivers/base/dd.c
drivers/base/platform.c
drivers/base/power/domain.c
drivers/base/power/main.c
drivers/base/power/trace.c
drivers/base/property.c
drivers/char/tpm/tpm_infineon.c
drivers/cpufreq/Kconfig
drivers/cpufreq/Kconfig.arm
drivers/cpufreq/Kconfig.powerpc
drivers/cpufreq/Makefile
drivers/cpufreq/hisi-acpu-cpufreq.c [new file with mode: 0644]
drivers/cpufreq/intel_pstate.c
drivers/cpufreq/powernv-cpufreq.c
drivers/cpufreq/ppc-corenet-cpufreq.c [deleted file]
drivers/cpufreq/qoriq-cpufreq.c [new file with mode: 0644]
drivers/cpuidle/Kconfig
drivers/cpuidle/Kconfig.arm
drivers/cpuidle/Kconfig.arm64 [deleted file]
drivers/cpuidle/Makefile
drivers/cpuidle/cpuidle-arm.c [new file with mode: 0644]
drivers/cpuidle/cpuidle-arm64.c [deleted file]
drivers/cpuidle/cpuidle-at91.c
drivers/cpuidle/cpuidle-exynos.c
drivers/cpuidle/cpuidle-kirkwood.c
drivers/cpuidle/cpuidle-ux500.c
drivers/cpuidle/cpuidle-zynq.c
drivers/devfreq/devfreq.c
drivers/devfreq/event/exynos-ppmu.c
drivers/devfreq/tegra-devfreq.c
drivers/gpio/gpiolib.h
drivers/i2c/busses/i2c-designware-platdrv.c
drivers/i2c/i2c-core.c
drivers/ide/ide-pnp.c
drivers/idle/intel_idle.c
drivers/iommu/intel-iommu.c
drivers/media/rc/ene_ir.c
drivers/media/rc/fintek-cir.c
drivers/media/rc/ite-cir.c
drivers/media/rc/nuvoton-cir.c
drivers/net/sb1000.c
drivers/platform/x86/apple-gmux.c
drivers/pnp/base.h
drivers/pnp/card.c
drivers/pnp/core.c
drivers/pnp/driver.c
drivers/pnp/pnpacpi/core.c
drivers/powercap/intel_rapl.c
drivers/tty/serial/8250/8250_fintek.c
drivers/watchdog/iTCO_wdt.c
include/acpi/acpi_bus.h
include/asm-generic/vmlinux.lds.h
include/linux/acpi.h
include/linux/devfreq-event.h
include/linux/device.h
include/linux/fwnode.h [new file with mode: 0644]
include/linux/i2c.h
include/linux/platform_device.h
include/linux/pm-trace.h [new file with mode: 0644]
include/linux/pm.h
include/linux/pm_domain.h
include/linux/pnp.h
include/linux/property.h
include/linux/resume-trace.h [deleted file]
kernel/power/main.c
kernel/power/suspend.c

index 9b121a569ab4397841ac9611aad90502fefb16b7..750401f9134190a210c8c24089a08ca9cb16559c 100644 (file)
@@ -254,8 +254,13 @@ GPIO support
 ~~~~~~~~~~~~
 ACPI 5 introduced two new resources to describe GPIO connections: GpioIo
 and GpioInt. These resources are used be used to pass GPIO numbers used by
-the device to the driver. For example:
+the device to the driver. ACPI 5.1 extended this with _DSD (Device
+Specific Data) which made it possible to name the GPIOs among other things.
 
+For example:
+
+Device (DEV)
+{
        Method (_CRS, 0, NotSerialized)
        {
                Name (SBUF, ResourceTemplate()
@@ -285,6 +290,18 @@ the device to the driver. For example:
                Return (SBUF)
        }
 
+       // ACPI 5.1 _DSD used for naming the GPIOs
+       Name (_DSD, Package ()
+       {
+               ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+               Package ()
+               {
+                       Package () {"power-gpios", Package() {^DEV, 0, 0, 0 }},
+                       Package () {"irq-gpios", Package() {^DEV, 1, 0, 0 }},
+               }
+       })
+       ...
+
 These GPIO numbers are controller relative and path "\\_SB.PCI0.GPI0"
 specifies the path to the controller. In order to use these GPIOs in Linux
 we need to translate them to the corresponding Linux GPIO descriptors.
@@ -300,11 +317,11 @@ a code like this:
 
        struct gpio_desc *irq_desc, *power_desc;
 
-       irq_desc = gpiod_get_index(dev, NULL, 1);
+       irq_desc = gpiod_get(dev, "irq");
        if (IS_ERR(irq_desc))
                /* handle error */
 
-       power_desc = gpiod_get_index(dev, NULL, 0);
+       power_desc = gpiod_get(dev, "power");
        if (IS_ERR(power_desc))
                /* handle error */
 
@@ -313,6 +330,9 @@ a code like this:
 There are also devm_* versions of these functions which release the
 descriptors once the device is released.
 
+See Documentation/acpi/gpio-properties.txt for more information about the
+_DSD binding related to GPIOs.
+
 MFD devices
 ~~~~~~~~~~~
 The MFD devices register their children as platform devices. For the child
index 32755634975708bf9dc511f36c6d3ec452ac3ef4..491bbd104b063143924647e566be5e7bfc8ac743 100644 (file)
@@ -3477,6 +3477,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        improve throughput, but will also increase the
                        amount of memory reserved for use by the client.
 
+       suspend.pm_test_delay=
+                       [SUSPEND]
+                       Sets the number of seconds to remain in a suspend test
+                       mode before resuming the system (see
+                       /sys/power/pm_test). Only available when CONFIG_PM_DEBUG
+                       is set. Default value is 5.
+
        swapaccount=[0|1]
                        [KNL] Enable accounting of swap in memory resource
                        controller if no parameter or 1 is given or disable
index edeecd447d23dc8ff26e66debe0d874b9482f087..b96098ccfe69208cf7491c1c4885563310398bf5 100644 (file)
@@ -75,12 +75,14 @@ you should do the following:
 # echo platform > /sys/power/disk
 # echo disk > /sys/power/state
 
-Then, the kernel will try to freeze processes, suspend devices, wait 5 seconds,
-resume devices and thaw processes.  If "platform" is written to
+Then, the kernel will try to freeze processes, suspend devices, wait a few
+seconds (5 by default, but configurable by the suspend.pm_test_delay module
+parameter), resume devices and thaw processes.  If "platform" is written to
 /sys/power/pm_test , then after suspending devices the kernel will additionally
 invoke the global control methods (eg. ACPI global control methods) used to
-prepare the platform firmware for hibernation.  Next, it will wait 5 seconds and
-invoke the platform (eg. ACPI) global methods used to cancel hibernation etc.
+prepare the platform firmware for hibernation.  Next, it will wait a
+configurable number of seconds and invoke the platform (eg. ACPI) global
+methods used to cancel hibernation etc.
 
 Writing "none" to /sys/power/pm_test causes the kernel to switch to the normal
 hibernation/suspend operations.  Also, when open for reading, /sys/power/pm_test
index 283d1145e6d8474a27f439dba841446822970810..40eaa356e35511c04984f5eca653ba783ce11162 100644 (file)
@@ -4331,6 +4331,15 @@ S:       Supported
 F:     drivers/phy/
 F:     include/linux/phy/
 
+GENERIC PM DOMAINS
+M:     "Rafael J. Wysocki" <rjw@rjwysocki.net>
+M:     Kevin Hilman <khilman@kernel.org>
+M:     Ulf Hansson <ulf.hansson@linaro.org>
+L:     linux-pm@vger.kernel.org
+S:     Supported
+F:     drivers/base/power/domain*.c
+F:     include/linux/pm_domain.h
+
 GENERIC UIO DRIVER FOR PCI DEVICES
 M:     "Michael S. Tsirkin" <mst@redhat.com>
 L:     kvm@vger.kernel.org
index af319ac4960c707d7e16a5635d2bce83c98761c4..0f842492490280b9d0b50fd1b25935a51b5a4c9d 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __ASM_ARM_CPUIDLE_H
 #define __ASM_ARM_CPUIDLE_H
 
+#include <asm/proc-fns.h>
+
 #ifdef CONFIG_CPU_IDLE
 extern int arm_cpuidle_simple_enter(struct cpuidle_device *dev,
                struct cpuidle_driver *drv, int index);
@@ -25,4 +27,25 @@ static inline int arm_cpuidle_simple_enter(struct cpuidle_device *dev,
  */
 #define ARM_CPUIDLE_WFI_STATE ARM_CPUIDLE_WFI_STATE_PWR(UINT_MAX)
 
+struct device_node;
+
+struct cpuidle_ops {
+       int (*suspend)(int cpu, unsigned long arg);
+       int (*init)(struct device_node *, int cpu);
+};
+
+struct of_cpuidle_method {
+       const char *method;
+       struct cpuidle_ops *ops;
+};
+
+#define CPUIDLE_METHOD_OF_DECLARE(name, _method, _ops)                 \
+       static const struct of_cpuidle_method __cpuidle_method_of_table_##name \
+       __used __section(__cpuidle_method_of_table)                     \
+       = { .method = _method, .ops = _ops }
+
+extern int arm_cpuidle_suspend(int index);
+
+extern int arm_cpuidle_init(int cpu);
+
 #endif
index 89545f6c840345ca8015231956df258c02fb3596..318da33465f413f8c207eb2dd9b3766e53ab5ad3 100644 (file)
  */
 
 #include <linux/cpuidle.h>
-#include <asm/proc-fns.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <asm/cpuidle.h>
 
+extern struct of_cpuidle_method __cpuidle_method_of_table[];
+
+static const struct of_cpuidle_method __cpuidle_method_of_table_sentinel
+       __used __section(__cpuidle_method_of_table_end);
+
+static struct cpuidle_ops cpuidle_ops[NR_CPUS];
+
+/**
+ * arm_cpuidle_simple_enter() - a wrapper to cpu_do_idle()
+ * @dev: not used
+ * @drv: not used
+ * @index: not used
+ *
+ * A trivial wrapper to allow the cpu_do_idle function to be assigned as a
+ * cpuidle callback by matching the function signature.
+ *
+ * Returns the index passed as parameter
+ */
 int arm_cpuidle_simple_enter(struct cpuidle_device *dev,
                struct cpuidle_driver *drv, int index)
 {
@@ -19,3 +39,114 @@ int arm_cpuidle_simple_enter(struct cpuidle_device *dev,
 
        return index;
 }
+
+/**
+ * arm_cpuidle_suspend() - function to enter low power idle states
+ * @index: an integer used as an identifier for the low level PM callbacks
+ *
+ * This function calls the underlying arch specific low level PM code as
+ * registered at the init time.
+ *
+ * Returns -EOPNOTSUPP if no suspend callback is defined, the result of the
+ * callback otherwise.
+ */
+int arm_cpuidle_suspend(int index)
+{
+       int ret = -EOPNOTSUPP;
+       int cpu = smp_processor_id();
+
+       if (cpuidle_ops[cpu].suspend)
+               ret = cpuidle_ops[cpu].suspend(cpu, index);
+
+       return ret;
+}
+
+/**
+ * arm_cpuidle_get_ops() - find a registered cpuidle_ops by name
+ * @method: the method name
+ *
+ * Search in the __cpuidle_method_of_table array the cpuidle ops matching the
+ * method name.
+ *
+ * Returns a struct cpuidle_ops pointer, NULL if not found.
+ */
+static struct cpuidle_ops *__init arm_cpuidle_get_ops(const char *method)
+{
+       struct of_cpuidle_method *m = __cpuidle_method_of_table;
+
+       for (; m->method; m++)
+               if (!strcmp(m->method, method))
+                       return m->ops;
+
+       return NULL;
+}
+
+/**
+ * arm_cpuidle_read_ops() - Initialize the cpuidle ops with the device tree
+ * @dn: a pointer to a struct device node corresponding to a cpu node
+ * @cpu: the cpu identifier
+ *
+ * Get the method name defined in the 'enable-method' property, retrieve the
+ * associated cpuidle_ops and do a struct copy. This copy is needed because all
+ * cpuidle_ops are tagged __initdata and will be unloaded after the init
+ * process.
+ *
+ * Return 0 on sucess, -ENOENT if no 'enable-method' is defined, -EOPNOTSUPP if
+ * no cpuidle_ops is registered for the 'enable-method'.
+ */
+static int __init arm_cpuidle_read_ops(struct device_node *dn, int cpu)
+{
+       const char *enable_method;
+       struct cpuidle_ops *ops;
+
+       enable_method = of_get_property(dn, "enable-method", NULL);
+       if (!enable_method)
+               return -ENOENT;
+
+       ops = arm_cpuidle_get_ops(enable_method);
+       if (!ops) {
+               pr_warn("%s: unsupported enable-method property: %s\n",
+                       dn->full_name, enable_method);
+               return -EOPNOTSUPP;
+       }
+
+       cpuidle_ops[cpu] = *ops; /* structure copy */
+
+       pr_notice("cpuidle: enable-method property '%s'"
+                 " found operations\n", enable_method);
+
+       return 0;
+}
+
+/**
+ * arm_cpuidle_init() - Initialize cpuidle_ops for a specific cpu
+ * @cpu: the cpu to be initialized
+ *
+ * Initialize the cpuidle ops with the device for the cpu and then call
+ * the cpu's idle initialization callback. This may fail if the underlying HW
+ * is not operational.
+ *
+ * Returns:
+ *  0 on success,
+ *  -ENODEV if it fails to find the cpu node in the device tree,
+ *  -EOPNOTSUPP if it does not find a registered cpuidle_ops for this cpu,
+ *  -ENOENT if it fails to find an 'enable-method' property,
+ *  -ENXIO if the HW reports a failure or a misconfiguration,
+ *  -ENOMEM if the HW report an memory allocation failure 
+ */
+int __init arm_cpuidle_init(int cpu)
+{
+       struct device_node *cpu_node = of_cpu_device_node_get(cpu);
+       int ret;
+
+       if (!cpu_node)
+               return -ENODEV;
+
+       ret = arm_cpuidle_read_ops(cpu_node, cpu);
+       if (!ret && cpuidle_ops[cpu].init)
+               ret = cpuidle_ops[cpu].init(cpu_node, cpu);
+
+       of_node_put(cpu_node);
+
+       return ret;
+}
index e365c1bb1265334e9684a004097fd2a1fb5c4797..306ebc51599a2bb1e6e83983aa3e71017840c8ce 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/cpuidle.h>
 #include <linux/io.h>
 #include <linux/export.h>
-#include <asm/proc-fns.h>
 #include <asm/cpuidle.h>
 
 #include <mach/cpuidle.h>
index d76d08623f9f945ad95cb211f317c2d8c42f3c7c..8e21ccc1eda25a0c45109e2b20c5d63f02bf99f8 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/cpuidle.h>
 #include <linux/module.h>
 #include <asm/cpuidle.h>
-#include <asm/proc-fns.h>
 
 #include "common.h"
 #include "cpuidle.h"
index 7d92e658455162bcb6ce25d84f6b9894895d3834..5742a9fd1ef29c5d367924115ccb5fe859051633 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/cpuidle.h>
 #include <linux/module.h>
 #include <asm/cpuidle.h>
-#include <asm/proc-fns.h>
 
 #include "common.h"
 #include "cpuidle.h"
index 5a36722b089d60890448b7000e56301bff7d98e0..2c9f1a8bf24590cf21b6d8aea80938d1f966e77e 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/cpu_pm.h>
 #include <linux/module.h>
 #include <asm/cpuidle.h>
-#include <asm/proc-fns.h>
 #include <asm/suspend.h>
 
 #include "common.h"
index 57d429830e09b4ceffa71efc3b3b88f6a88c68cd..4b8e9f4d59eaddff4aebc18c4b404e9206bd41db 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/tick.h>
 
 #include <asm/cpuidle.h>
-#include <asm/proc-fns.h>
 
 #include "common.h"
 #include "pm.h"
index 2eb072440dfa7a9222250457ab0e26c278236920..93aa8cb701958115275cf723660fa2bbcd38008e 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/export.h>
 #include <linux/time.h>
 
-#include <asm/proc-fns.h>
+#include <asm/cpuidle.h>
 
 #include <mach/map.h>
 
index 48844ae6c3a119b8493aaffef1c805cf929c7111..88de2dce2e8722820644b752ae8c4cee0c129ec9 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/module.h>
 
 #include <asm/cpuidle.h>
-#include <asm/proc-fns.h>
 #include <asm/smp_plat.h>
 #include <asm/suspend.h>
 
index 84d809a3cba3b2f720d261ece0dc07df14ec72cf..4dbe1dae937c49e25e479f0ebbc89a80076dcb80 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/module.h>
 
 #include <asm/cpuidle.h>
-#include <asm/proc-fns.h>
 #include <asm/smp_plat.h>
 #include <asm/suspend.h>
 
index be1f12a5a5f03b787d7cd45867075b62aac30014..af6a452b1aac2b404a57c420ab86b5b8fb4f619f 100644 (file)
@@ -48,7 +48,7 @@ CONFIG_CMDLINE="console=ttyAMA0"
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 CONFIG_COMPAT=y
 CONFIG_CPU_IDLE=y
-CONFIG_ARM64_CPUIDLE=y
+CONFIG_ARM_CPUIDLE=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
index c60643f14cda97e7ba6dd9676f10b133af4b0627..141b2fcabaa67e50294ba85ad5f218dfc1acac0d 100644 (file)
@@ -4,10 +4,10 @@
 #include <asm/proc-fns.h>
 
 #ifdef CONFIG_CPU_IDLE
-extern int cpu_init_idle(unsigned int cpu);
+extern int arm_cpuidle_init(unsigned int cpu);
 extern int cpu_suspend(unsigned long arg);
 #else
-static inline int cpu_init_idle(unsigned int cpu)
+static inline int arm_cpuidle_init(unsigned int cpu)
 {
        return -EOPNOTSUPP;
 }
@@ -17,5 +17,8 @@ static inline int cpu_suspend(unsigned long arg)
        return -EOPNOTSUPP;
 }
 #endif
-
+static inline int arm_cpuidle_suspend(int index)
+{
+       return cpu_suspend(index);
+}
 #endif
index 5c0896647fd14e83e3d410e450e7085894c24484..a78143a5c99ffb2c9a7ae69267ef3c7f3256c024 100644 (file)
@@ -15,7 +15,7 @@
 #include <asm/cpuidle.h>
 #include <asm/cpu_ops.h>
 
-int cpu_init_idle(unsigned int cpu)
+int arm_cpuidle_init(unsigned int cpu)
 {
        int ret = -EOPNOTSUPP;
        struct device_node *cpu_node = of_cpu_device_node_get(cpu);
diff --git a/arch/x86/include/asm/pm-trace.h b/arch/x86/include/asm/pm-trace.h
new file mode 100644 (file)
index 0000000..7b7ac42
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef _ASM_X86_PM_TRACE_H
+#define _ASM_X86_PM_TRACE_H
+
+#include <asm/asm.h>
+
+#define TRACE_RESUME(user)                                     \
+do {                                                           \
+       if (pm_trace_enabled) {                                 \
+               const void *tracedata;                          \
+               asm volatile(_ASM_MOV " $1f,%0\n"               \
+                            ".section .tracedata,\"a\"\n"      \
+                            "1:\t.word %c1\n\t"                \
+                            _ASM_PTR " %c2\n"                  \
+                            ".previous"                        \
+                            :"=r" (tracedata)                  \
+                            : "i" (__LINE__), "i" (__FILE__)); \
+               generate_pm_trace(tracedata, user);             \
+       }                                                       \
+} while (0)
+
+#define TRACE_SUSPEND(user)    TRACE_RESUME(user)
+
+#endif /* _ASM_X86_PM_TRACE_H */
diff --git a/arch/x86/include/asm/resume-trace.h b/arch/x86/include/asm/resume-trace.h
deleted file mode 100644 (file)
index 3ff1c2c..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef _ASM_X86_RESUME_TRACE_H
-#define _ASM_X86_RESUME_TRACE_H
-
-#include <asm/asm.h>
-
-#define TRACE_RESUME(user)                                     \
-do {                                                           \
-       if (pm_trace_enabled) {                                 \
-               const void *tracedata;                          \
-               asm volatile(_ASM_MOV " $1f,%0\n"               \
-                            ".section .tracedata,\"a\"\n"      \
-                            "1:\t.word %c1\n\t"                \
-                            _ASM_PTR " %c2\n"                  \
-                            ".previous"                        \
-                            :"=r" (tracedata)                  \
-                            : "i" (__LINE__), "i" (__FILE__)); \
-               generate_resume_trace(tracedata, user);         \
-       }                                                       \
-} while (0)
-
-#endif /* _ASM_X86_RESUME_TRACE_H */
index 1284138e42ab486d584f61e3f90bbaf0320a1a5b..4bf75597f732e90def62ba607590e7eb8e451da4 100644 (file)
@@ -102,7 +102,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
        pdevinfo.id = -1;
        pdevinfo.res = resources;
        pdevinfo.num_res = count;
-       pdevinfo.acpi_node.companion = adev;
+       pdevinfo.fwnode = acpi_fwnode_handle(adev);
        pdevinfo.dma_mask = DMA_BIT_MASK(32);
        pdev = platform_device_register_full(&pdevinfo);
        if (IS_ERR(pdev))
index 672263a3832c819165f460a5570751fe2602bf30..63d43677f644bcc4c9d3aab0079167f35e7fdda8 100644 (file)
@@ -531,8 +531,8 @@ static int acpi_battery_get_state(struct acpi_battery *battery)
                battery->rate_now != ACPI_BATTERY_VALUE_UNKNOWN &&
                (s16)(battery->rate_now) < 0) {
                battery->rate_now = abs((s16)battery->rate_now);
-               printk_once(KERN_WARNING FW_BUG "battery: (dis)charge rate"
-                       " invalid.\n");
+               printk_once(KERN_WARNING FW_BUG
+                           "battery: (dis)charge rate invalid.\n");
        }
 
        if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags)
index 9b693d54c743edbca512fc7b37086a809de9ccd7..1d1791935c318c71148a5da573effe51f9031a15 100644 (file)
@@ -215,6 +215,14 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
        },
        {
        .callback = dmi_disable_osi_vista,
+       .ident = "VGN-SR19XN",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+                    DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR19XN"),
+               },
+       },
+       {
+       .callback = dmi_disable_osi_vista,
        .ident = "Toshiba Satellite L355",
        .matches = {
                     DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
index d9339b442a4ebdc6870d4dd0b4dac4db65ed8613..a688aa243f6c0452707f69250e5adb9379da68d3 100644 (file)
@@ -615,7 +615,7 @@ void acpi_dock_add(struct acpi_device *adev)
        memset(&pdevinfo, 0, sizeof(pdevinfo));
        pdevinfo.name = "dock";
        pdevinfo.id = dock_station_count;
-       pdevinfo.acpi_node.companion = adev;
+       pdevinfo.fwnode = acpi_fwnode_handle(adev);
        pdevinfo.data = &ds;
        pdevinfo.size_data = sizeof(ds);
        dd = platform_device_register_full(&pdevinfo);
index a8dd2f7633822b05f5fdeeaffe5a00496f4710be..220d6406c9e93cbd7ed269fca5adbd94e3303152 100644 (file)
@@ -136,6 +136,50 @@ static int EC_FLAGS_SKIP_DSDT_SCAN; /* Not all BIOS survive early DSDT scan */
 static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */
 static int EC_FLAGS_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */
 
+/* --------------------------------------------------------------------------
+ *                           Logging/Debugging
+ * -------------------------------------------------------------------------- */
+
+/*
+ * Splitters used by the developers to track the boundary of the EC
+ * handling processes.
+ */
+#ifdef DEBUG
+#define EC_DBG_SEP     " "
+#define EC_DBG_DRV     "+++++"
+#define EC_DBG_STM     "====="
+#define EC_DBG_REQ     "*****"
+#define EC_DBG_EVT     "#####"
+#else
+#define EC_DBG_SEP     ""
+#define EC_DBG_DRV
+#define EC_DBG_STM
+#define EC_DBG_REQ
+#define EC_DBG_EVT
+#endif
+
+#define ec_log_raw(fmt, ...) \
+       pr_info(fmt "\n", ##__VA_ARGS__)
+#define ec_dbg_raw(fmt, ...) \
+       pr_debug(fmt "\n", ##__VA_ARGS__)
+#define ec_log(filter, fmt, ...) \
+       ec_log_raw(filter EC_DBG_SEP fmt EC_DBG_SEP filter, ##__VA_ARGS__)
+#define ec_dbg(filter, fmt, ...) \
+       ec_dbg_raw(filter EC_DBG_SEP fmt EC_DBG_SEP filter, ##__VA_ARGS__)
+
+#define ec_log_drv(fmt, ...) \
+       ec_log(EC_DBG_DRV, fmt, ##__VA_ARGS__)
+#define ec_dbg_drv(fmt, ...) \
+       ec_dbg(EC_DBG_DRV, fmt, ##__VA_ARGS__)
+#define ec_dbg_stm(fmt, ...) \
+       ec_dbg(EC_DBG_STM, fmt, ##__VA_ARGS__)
+#define ec_dbg_req(fmt, ...) \
+       ec_dbg(EC_DBG_REQ, fmt, ##__VA_ARGS__)
+#define ec_dbg_evt(fmt, ...) \
+       ec_dbg(EC_DBG_EVT, fmt, ##__VA_ARGS__)
+#define ec_dbg_ref(ec, fmt, ...) \
+       ec_dbg_raw("%lu: " fmt, ec->reference_count, ## __VA_ARGS__)
+
 /* --------------------------------------------------------------------------
  *                           Device Flags
  * -------------------------------------------------------------------------- */
@@ -159,14 +203,14 @@ static inline u8 acpi_ec_read_status(struct acpi_ec *ec)
 {
        u8 x = inb(ec->command_addr);
 
-       pr_debug("EC_SC(R) = 0x%2.2x "
-                "SCI_EVT=%d BURST=%d CMD=%d IBF=%d OBF=%d\n",
-                x,
-                !!(x & ACPI_EC_FLAG_SCI),
-                !!(x & ACPI_EC_FLAG_BURST),
-                !!(x & ACPI_EC_FLAG_CMD),
-                !!(x & ACPI_EC_FLAG_IBF),
-                !!(x & ACPI_EC_FLAG_OBF));
+       ec_dbg_raw("EC_SC(R) = 0x%2.2x "
+                  "SCI_EVT=%d BURST=%d CMD=%d IBF=%d OBF=%d",
+                  x,
+                  !!(x & ACPI_EC_FLAG_SCI),
+                  !!(x & ACPI_EC_FLAG_BURST),
+                  !!(x & ACPI_EC_FLAG_CMD),
+                  !!(x & ACPI_EC_FLAG_IBF),
+                  !!(x & ACPI_EC_FLAG_OBF));
        return x;
 }
 
@@ -175,20 +219,20 @@ static inline u8 acpi_ec_read_data(struct acpi_ec *ec)
        u8 x = inb(ec->data_addr);
 
        ec->curr->timestamp = jiffies;
-       pr_debug("EC_DATA(R) = 0x%2.2x\n", x);
+       ec_dbg_raw("EC_DATA(R) = 0x%2.2x", x);
        return x;
 }
 
 static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command)
 {
-       pr_debug("EC_SC(W) = 0x%2.2x\n", command);
+       ec_dbg_raw("EC_SC(W) = 0x%2.2x", command);
        outb(command, ec->command_addr);
        ec->curr->timestamp = jiffies;
 }
 
 static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
 {
-       pr_debug("EC_DATA(W) = 0x%2.2x\n", data);
+       ec_dbg_raw("EC_DATA(W) = 0x%2.2x", data);
        outb(data, ec->data_addr);
        ec->curr->timestamp = jiffies;
 }
@@ -240,7 +284,7 @@ static inline void acpi_ec_enable_gpe(struct acpi_ec *ec, bool open)
                 * software need to manually trigger a pseudo GPE event on
                 * EN=1 writes.
                 */
-               pr_debug("***** Polling quirk *****\n");
+               ec_dbg_raw("Polling quirk");
                advance_transaction(ec);
        }
 }
@@ -299,7 +343,7 @@ static void acpi_ec_set_storm(struct acpi_ec *ec, u8 flag)
 {
        if (!test_bit(flag, &ec->flags)) {
                acpi_ec_disable_gpe(ec, false);
-               pr_debug("+++++ Polling enabled +++++\n");
+               ec_dbg_drv("Polling enabled");
                set_bit(flag, &ec->flags);
        }
 }
@@ -309,7 +353,7 @@ static void acpi_ec_clear_storm(struct acpi_ec *ec, u8 flag)
        if (test_bit(flag, &ec->flags)) {
                clear_bit(flag, &ec->flags);
                acpi_ec_enable_gpe(ec, false);
-               pr_debug("+++++ Polling disabled +++++\n");
+               ec_dbg_drv("Polling disabled");
        }
 }
 
@@ -335,7 +379,7 @@ static bool acpi_ec_submit_flushable_request(struct acpi_ec *ec)
 static void acpi_ec_submit_query(struct acpi_ec *ec)
 {
        if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
-               pr_debug("***** Event started *****\n");
+               ec_dbg_req("Event started");
                schedule_work(&ec->work);
        }
 }
@@ -344,7 +388,7 @@ static void acpi_ec_complete_query(struct acpi_ec *ec)
 {
        if (ec->curr->command == ACPI_EC_COMMAND_QUERY) {
                clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
-               pr_debug("***** Event stopped *****\n");
+               ec_dbg_req("Event stopped");
        }
 }
 
@@ -366,8 +410,8 @@ static void advance_transaction(struct acpi_ec *ec)
        u8 status;
        bool wakeup = false;
 
-       pr_debug("===== %s (%d) =====\n",
-                in_interrupt() ? "IRQ" : "TASK", smp_processor_id());
+       ec_dbg_stm("%s (%d)", in_interrupt() ? "IRQ" : "TASK",
+                  smp_processor_id());
        /*
         * By always clearing STS before handling all indications, we can
         * ensure a hardware STS 0->1 change after this clearing can always
@@ -390,8 +434,8 @@ static void advance_transaction(struct acpi_ec *ec)
                                if (t->rlen == t->ri) {
                                        t->flags |= ACPI_EC_COMMAND_COMPLETE;
                                        if (t->command == ACPI_EC_COMMAND_QUERY)
-                                               pr_debug("***** Command(%s) hardware completion *****\n",
-                                                        acpi_ec_cmd_string(t->command));
+                                               ec_dbg_req("Command(%s) hardware completion",
+                                                          acpi_ec_cmd_string(t->command));
                                        wakeup = true;
                                }
                        } else
@@ -410,8 +454,8 @@ static void advance_transaction(struct acpi_ec *ec)
                        acpi_ec_complete_query(ec);
                        t->rdata[t->ri++] = 0x00;
                        t->flags |= ACPI_EC_COMMAND_COMPLETE;
-                       pr_debug("***** Command(%s) software completion *****\n",
-                                acpi_ec_cmd_string(t->command));
+                       ec_dbg_req("Command(%s) software completion",
+                                  acpi_ec_cmd_string(t->command));
                        wakeup = true;
                } else if ((status & ACPI_EC_FLAG_IBF) == 0) {
                        acpi_ec_write_cmd(ec, t->command);
@@ -502,21 +546,21 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
                ret = -EINVAL;
                goto unlock;
        }
+       ec_dbg_ref(ec, "Increase command");
        /* following two actions should be kept atomic */
        ec->curr = t;
-       pr_debug("***** Command(%s) started *****\n",
-                acpi_ec_cmd_string(t->command));
+       ec_dbg_req("Command(%s) started", acpi_ec_cmd_string(t->command));
        start_transaction(ec);
        spin_unlock_irqrestore(&ec->lock, tmp);
        ret = ec_poll(ec);
        spin_lock_irqsave(&ec->lock, tmp);
        if (t->irq_count == ec_storm_threshold)
                acpi_ec_clear_storm(ec, EC_FLAGS_COMMAND_STORM);
-       pr_debug("***** Command(%s) stopped *****\n",
-                acpi_ec_cmd_string(t->command));
+       ec_dbg_req("Command(%s) stopped", acpi_ec_cmd_string(t->command));
        ec->curr = NULL;
        /* Disable GPE for command processing (IBF=0/OBF=1) */
        acpi_ec_complete_request(ec);
+       ec_dbg_ref(ec, "Decrease command");
 unlock:
        spin_unlock_irqrestore(&ec->lock, tmp);
        return ret;
@@ -676,11 +720,13 @@ static void acpi_ec_start(struct acpi_ec *ec, bool resuming)
 
        spin_lock_irqsave(&ec->lock, flags);
        if (!test_and_set_bit(EC_FLAGS_STARTED, &ec->flags)) {
-               pr_debug("+++++ Starting EC +++++\n");
+               ec_dbg_drv("Starting EC");
                /* Enable GPE for event processing (SCI_EVT=1) */
-               if (!resuming)
+               if (!resuming) {
                        acpi_ec_submit_request(ec);
-               pr_debug("EC started\n");
+                       ec_dbg_ref(ec, "Increase driver");
+               }
+               ec_log_drv("EC started");
        }
        spin_unlock_irqrestore(&ec->lock, flags);
 }
@@ -702,17 +748,19 @@ static void acpi_ec_stop(struct acpi_ec *ec, bool suspending)
 
        spin_lock_irqsave(&ec->lock, flags);
        if (acpi_ec_started(ec)) {
-               pr_debug("+++++ Stopping EC +++++\n");
+               ec_dbg_drv("Stopping EC");
                set_bit(EC_FLAGS_STOPPED, &ec->flags);
                spin_unlock_irqrestore(&ec->lock, flags);
                wait_event(ec->wait, acpi_ec_stopped(ec));
                spin_lock_irqsave(&ec->lock, flags);
                /* Disable GPE for event processing (SCI_EVT=1) */
-               if (!suspending)
+               if (!suspending) {
                        acpi_ec_complete_request(ec);
+                       ec_dbg_ref(ec, "Decrease driver");
+               }
                clear_bit(EC_FLAGS_STARTED, &ec->flags);
                clear_bit(EC_FLAGS_STOPPED, &ec->flags);
-               pr_debug("EC stopped\n");
+               ec_log_drv("EC stopped");
        }
        spin_unlock_irqrestore(&ec->lock, flags);
 }
@@ -824,12 +872,12 @@ static void acpi_ec_run(void *cxt)
 
        if (!handler)
                return;
-       pr_debug("##### Query(0x%02x) started #####\n", handler->query_bit);
+       ec_dbg_evt("Query(0x%02x) started", handler->query_bit);
        if (handler->func)
                handler->func(handler->data);
        else if (handler->handle)
                acpi_evaluate_object(handler->handle, NULL, NULL, NULL);
-       pr_debug("##### Query(0x%02x) stopped #####\n", handler->query_bit);
+       ec_dbg_evt("Query(0x%02x) stopped", handler->query_bit);
        acpi_ec_put_query_handler(handler);
 }
 
@@ -861,8 +909,8 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 *data)
                if (value == handler->query_bit) {
                        /* have custom handler for this bit */
                        handler = acpi_ec_get_query_handler(handler);
-                       pr_debug("##### Query(0x%02x) scheduled #####\n",
-                                handler->query_bit);
+                       ec_dbg_evt("Query(0x%02x) scheduled",
+                                  handler->query_bit);
                        status = acpi_os_execute((handler->func) ?
                                OSL_NOTIFY_HANDLER : OSL_GPE_HANDLER,
                                acpi_ec_run, handler);
@@ -1099,6 +1147,9 @@ static int acpi_ec_add(struct acpi_device *device)
 
        ret = ec_install_handlers(ec);
 
+       /* Reprobe devices depending on the EC */
+       acpi_walk_dep_device_list(ec->handle);
+
        /* EC is fully operational, allow queries */
        clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
 
index f774c65ecb8bb03065ba406e658710aead5d02c0..39c485b0c25c0d6ddccabb35e3c7014fb92788a9 100644 (file)
@@ -168,7 +168,7 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
        unsigned int node_id;
        int retval = -EINVAL;
 
-       if (ACPI_COMPANION(dev)) {
+       if (has_acpi_companion(dev)) {
                if (acpi_dev) {
                        dev_warn(dev, "ACPI companion already set\n");
                        return -EINVAL;
@@ -220,7 +220,7 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
        list_add(&physical_node->node, physnode_list);
        acpi_dev->physical_node_count++;
 
-       if (!ACPI_COMPANION(dev))
+       if (!has_acpi_companion(dev))
                ACPI_COMPANION_SET(dev, acpi_dev);
 
        acpi_physnode_link_name(physical_node_name, node_id);
index ef7d8ff95abe000002bd49d74f5da28858200c5a..42df46a86c25ade48ee506e3c1bf1a4182cd1e33 100644 (file)
@@ -207,5 +207,5 @@ static int __init intel_crc_pmic_opregion_driver_init(void)
 }
 module_init(intel_crc_pmic_opregion_driver_init);
 
-MODULE_DESCRIPTION("CrystalCove ACPI opration region driver");
+MODULE_DESCRIPTION("CrystalCove ACPI operation region driver");
 MODULE_LICENSE("GPL");
index bbca7830e18a717cd129a9bdddb2f312ae18bb9f..69bc0d888c012523d03f15267c3ca75a1d4a10e3 100644 (file)
@@ -114,7 +114,12 @@ int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler,
        return 0;
 }
 
-/*
+/**
+ * create_pnp_modalias - Create hid/cid(s) string for modalias and uevent
+ * @acpi_dev: ACPI device object.
+ * @modalias: Buffer to print into.
+ * @size: Size of the buffer.
+ *
  * Creates hid/cid(s) string needed for modalias and uevent
  * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get:
  * char *modalias: "acpi:IBM0001:ACPI0001"
@@ -122,68 +127,98 @@ int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler,
  *         -EINVAL: output error
  *         -ENOMEM: output is truncated
 */
-static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
-                          int size)
+static int create_pnp_modalias(struct acpi_device *acpi_dev, char *modalias,
+                              int size)
 {
        int len;
        int count;
        struct acpi_hardware_id *id;
 
-       if (list_empty(&acpi_dev->pnp.ids))
-               return 0;
-
        /*
-        * If the device has PRP0001 we expose DT compatible modalias
-        * instead in form of of:NnameTCcompatible.
+        * Since we skip PRP0001 from the modalias below, 0 should be returned
+        * if PRP0001 is the only ACPI/PNP ID in the device's list.
         */
-       if (acpi_dev->data.of_compatible) {
-               struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
-               const union acpi_object *of_compatible, *obj;
-               int i, nval;
-               char *c;
-
-               acpi_get_name(acpi_dev->handle, ACPI_SINGLE_NAME, &buf);
-               /* DT strings are all in lower case */
-               for (c = buf.pointer; *c != '\0'; c++)
-                       *c = tolower(*c);
-
-               len = snprintf(modalias, size, "of:N%sT", (char *)buf.pointer);
-               ACPI_FREE(buf.pointer);
-
-               of_compatible = acpi_dev->data.of_compatible;
-               if (of_compatible->type == ACPI_TYPE_PACKAGE) {
-                       nval = of_compatible->package.count;
-                       obj = of_compatible->package.elements;
-               } else { /* Must be ACPI_TYPE_STRING. */
-                       nval = 1;
-                       obj = of_compatible;
-               }
-               for (i = 0; i < nval; i++, obj++) {
-                       count = snprintf(&modalias[len], size, "C%s",
-                                        obj->string.pointer);
-                       if (count < 0)
-                               return -EINVAL;
-                       if (count >= size)
-                               return -ENOMEM;
-
-                       len += count;
-                       size -= count;
-               }
-       } else {
-               len = snprintf(modalias, size, "acpi:");
-               size -= len;
+       count = 0;
+       list_for_each_entry(id, &acpi_dev->pnp.ids, list)
+               if (strcmp(id->id, "PRP0001"))
+                       count++;
 
-               list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
-                       count = snprintf(&modalias[len], size, "%s:", id->id);
-                       if (count < 0)
-                               return -EINVAL;
-                       if (count >= size)
-                               return -ENOMEM;
-                       len += count;
-                       size -= count;
-               }
+       if (!count)
+               return 0;
+
+       len = snprintf(modalias, size, "acpi:");
+       if (len <= 0)
+               return len;
+
+       size -= len;
+
+       list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
+               if (!strcmp(id->id, "PRP0001"))
+                       continue;
+
+               count = snprintf(&modalias[len], size, "%s:", id->id);
+               if (count < 0)
+                       return -EINVAL;
+
+               if (count >= size)
+                       return -ENOMEM;
+
+               len += count;
+               size -= count;
+       }
+       modalias[len] = '\0';
+       return len;
+}
+
+/**
+ * create_of_modalias - Creates DT compatible string for modalias and uevent
+ * @acpi_dev: ACPI device object.
+ * @modalias: Buffer to print into.
+ * @size: Size of the buffer.
+ *
+ * Expose DT compatible modalias as of:NnameTCcompatible.  This function should
+ * only be called for devices having PRP0001 in their list of ACPI/PNP IDs.
+ */
+static int create_of_modalias(struct acpi_device *acpi_dev, char *modalias,
+                             int size)
+{
+       struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
+       const union acpi_object *of_compatible, *obj;
+       int len, count;
+       int i, nval;
+       char *c;
+
+       acpi_get_name(acpi_dev->handle, ACPI_SINGLE_NAME, &buf);
+       /* DT strings are all in lower case */
+       for (c = buf.pointer; *c != '\0'; c++)
+               *c = tolower(*c);
+
+       len = snprintf(modalias, size, "of:N%sT", (char *)buf.pointer);
+       ACPI_FREE(buf.pointer);
+
+       if (len <= 0)
+               return len;
+
+       of_compatible = acpi_dev->data.of_compatible;
+       if (of_compatible->type == ACPI_TYPE_PACKAGE) {
+               nval = of_compatible->package.count;
+               obj = of_compatible->package.elements;
+       } else { /* Must be ACPI_TYPE_STRING. */
+               nval = 1;
+               obj = of_compatible;
        }
+       for (i = 0; i < nval; i++, obj++) {
+               count = snprintf(&modalias[len], size, "C%s",
+                                obj->string.pointer);
+               if (count < 0)
+                       return -EINVAL;
 
+               if (count >= size)
+                       return -ENOMEM;
+
+               len += count;
+               size -= count;
+       }
        modalias[len] = '\0';
        return len;
 }
@@ -194,7 +229,8 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
  *
  * Check if the given device has an ACPI companion and if that companion has
  * a valid list of PNP IDs, and if the device is the first (primary) physical
- * device associated with it.
+ * device associated with it.  Return the companion pointer if that's the case
+ * or NULL otherwise.
  *
  * If multiple physical devices are attached to a single ACPI companion, we need
  * to be careful.  The usage scenario for this kind of relationship is that all
@@ -208,88 +244,129 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
  * resources available from it but they will be matched normally using functions
  * provided by their bus types (and analogously for their modalias).
  */
-static bool acpi_companion_match(const struct device *dev)
+static struct acpi_device *acpi_companion_match(const struct device *dev)
 {
        struct acpi_device *adev;
-       bool ret;
+       struct mutex *physical_node_lock;
 
        adev = ACPI_COMPANION(dev);
        if (!adev)
-               return false;
+               return NULL;
 
        if (list_empty(&adev->pnp.ids))
-               return false;
+               return NULL;
 
-       mutex_lock(&adev->physical_node_lock);
+       physical_node_lock = &adev->physical_node_lock;
+       mutex_lock(physical_node_lock);
        if (list_empty(&adev->physical_node_list)) {
-               ret = false;
+               adev = NULL;
        } else {
                const struct acpi_device_physical_node *node;
 
                node = list_first_entry(&adev->physical_node_list,
                                        struct acpi_device_physical_node, node);
-               ret = node->dev == dev;
+               if (node->dev != dev)
+                       adev = NULL;
        }
-       mutex_unlock(&adev->physical_node_lock);
+       mutex_unlock(physical_node_lock);
 
-       return ret;
+       return adev;
 }
 
-/*
- * Creates uevent modalias field for ACPI enumerated devices.
- * Because the other buses does not support ACPI HIDs & CIDs.
- * e.g. for a device with hid:IBM0001 and cid:ACPI0001 you get:
- * "acpi:IBM0001:ACPI0001"
- */
-int acpi_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env)
+static int __acpi_device_uevent_modalias(struct acpi_device *adev,
+                                        struct kobj_uevent_env *env)
 {
        int len;
 
-       if (!acpi_companion_match(dev))
+       if (!adev)
                return -ENODEV;
 
+       if (list_empty(&adev->pnp.ids))
+               return 0;
+
        if (add_uevent_var(env, "MODALIAS="))
                return -ENOMEM;
-       len = create_modalias(ACPI_COMPANION(dev), &env->buf[env->buflen - 1],
-                               sizeof(env->buf) - env->buflen);
-       if (len <= 0)
+
+       len = create_pnp_modalias(adev, &env->buf[env->buflen - 1],
+                                 sizeof(env->buf) - env->buflen);
+       if (len < 0)
+               return len;
+
+       env->buflen += len;
+       if (!adev->data.of_compatible)
+               return 0;
+
+       if (len > 0 && add_uevent_var(env, "MODALIAS="))
+               return -ENOMEM;
+
+       len = create_of_modalias(adev, &env->buf[env->buflen - 1],
+                                sizeof(env->buf) - env->buflen);
+       if (len < 0)
                return len;
+
        env->buflen += len;
+
        return 0;
 }
-EXPORT_SYMBOL_GPL(acpi_device_uevent_modalias);
 
 /*
- * Creates modalias sysfs attribute for ACPI enumerated devices.
+ * Creates uevent modalias field for ACPI enumerated devices.
  * Because the other buses does not support ACPI HIDs & CIDs.
  * e.g. for a device with hid:IBM0001 and cid:ACPI0001 you get:
  * "acpi:IBM0001:ACPI0001"
  */
-int acpi_device_modalias(struct device *dev, char *buf, int size)
+int acpi_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env)
 {
-       int len;
+       return __acpi_device_uevent_modalias(acpi_companion_match(dev), env);
+}
+EXPORT_SYMBOL_GPL(acpi_device_uevent_modalias);
 
-       if (!acpi_companion_match(dev))
+static int __acpi_device_modalias(struct acpi_device *adev, char *buf, int size)
+{
+       int len, count;
+
+       if (!adev)
                return -ENODEV;
 
-       len = create_modalias(ACPI_COMPANION(dev), buf, size -1);
-       if (len <= 0)
+       if (list_empty(&adev->pnp.ids))
+               return 0;
+
+       len = create_pnp_modalias(adev, buf, size - 1);
+       if (len < 0) {
+               return len;
+       } else if (len > 0) {
+               buf[len++] = '\n';
+               size -= len;
+       }
+       if (!adev->data.of_compatible)
                return len;
-       buf[len++] = '\n';
+
+       count = create_of_modalias(adev, buf + len, size - 1);
+       if (count < 0) {
+               return count;
+       } else if (count > 0) {
+               len += count;
+               buf[len++] = '\n';
+       }
+
        return len;
 }
+
+/*
+ * Creates modalias sysfs attribute for ACPI enumerated devices.
+ * Because the other buses does not support ACPI HIDs & CIDs.
+ * e.g. for a device with hid:IBM0001 and cid:ACPI0001 you get:
+ * "acpi:IBM0001:ACPI0001"
+ */
+int acpi_device_modalias(struct device *dev, char *buf, int size)
+{
+       return __acpi_device_modalias(acpi_companion_match(dev), buf, size);
+}
 EXPORT_SYMBOL_GPL(acpi_device_modalias);
 
 static ssize_t
 acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, char *buf) {
-       struct acpi_device *acpi_dev = to_acpi_device(dev);
-       int len;
-
-       len = create_modalias(acpi_dev, buf, 1024);
-       if (len <= 0)
-               return len;
-       buf[len++] = '\n';
-       return len;
+       return __acpi_device_modalias(to_acpi_device(dev), buf, 1024);
 }
 static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
 
@@ -894,8 +971,51 @@ static void acpi_device_remove_files(struct acpi_device *dev)
                        ACPI Bus operations
    -------------------------------------------------------------------------- */
 
+/**
+ * acpi_of_match_device - Match device object using the "compatible" property.
+ * @adev: ACPI device object to match.
+ * @of_match_table: List of device IDs to match against.
+ *
+ * If @dev has an ACPI companion which has the special PRP0001 device ID in its
+ * list of identifiers and a _DSD object with the "compatible" property, use
+ * that property to match against the given list of identifiers.
+ */
+static bool acpi_of_match_device(struct acpi_device *adev,
+                                const struct of_device_id *of_match_table)
+{
+       const union acpi_object *of_compatible, *obj;
+       int i, nval;
+
+       if (!adev)
+               return false;
+
+       of_compatible = adev->data.of_compatible;
+       if (!of_match_table || !of_compatible)
+               return false;
+
+       if (of_compatible->type == ACPI_TYPE_PACKAGE) {
+               nval = of_compatible->package.count;
+               obj = of_compatible->package.elements;
+       } else { /* Must be ACPI_TYPE_STRING. */
+               nval = 1;
+               obj = of_compatible;
+       }
+       /* Now we can look for the driver DT compatible strings */
+       for (i = 0; i < nval; i++, obj++) {
+               const struct of_device_id *id;
+
+               for (id = of_match_table; id->compatible[0]; id++)
+                       if (!strcasecmp(obj->string.pointer, id->compatible))
+                               return true;
+       }
+
+       return false;
+}
+
 static const struct acpi_device_id *__acpi_match_device(
-       struct acpi_device *device, const struct acpi_device_id *ids)
+       struct acpi_device *device,
+       const struct acpi_device_id *ids,
+       const struct of_device_id *of_ids)
 {
        const struct acpi_device_id *id;
        struct acpi_hardware_id *hwid;
@@ -904,14 +1024,27 @@ static const struct acpi_device_id *__acpi_match_device(
         * If the device is not present, it is unnecessary to load device
         * driver for it.
         */
-       if (!device->status.present)
+       if (!device || !device->status.present)
                return NULL;
 
-       for (id = ids; id->id[0]; id++)
-               list_for_each_entry(hwid, &device->pnp.ids, list)
+       list_for_each_entry(hwid, &device->pnp.ids, list) {
+               /* First, check the ACPI/PNP IDs provided by the caller. */
+               for (id = ids; id->id[0]; id++)
                        if (!strcmp((char *) id->id, hwid->id))
                                return id;
 
+               /*
+                * Next, check the special "PRP0001" ID and try to match the
+                * "compatible" property if found.
+                *
+                * The id returned by the below is not valid, but the only
+                * caller passing non-NULL of_ids here is only interested in
+                * whether or not the return value is NULL.
+                */
+               if (!strcmp("PRP0001", hwid->id)
+                   && acpi_of_match_device(device, of_ids))
+                       return id;
+       }
        return NULL;
 }
 
@@ -929,68 +1062,26 @@ static const struct acpi_device_id *__acpi_match_device(
 const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids,
                                               const struct device *dev)
 {
-       struct acpi_device *adev;
-       acpi_handle handle = ACPI_HANDLE(dev);
-
-       if (!ids || !handle || acpi_bus_get_device(handle, &adev))
-               return NULL;
-
-       if (!acpi_companion_match(dev))
-               return NULL;
-
-       return __acpi_match_device(adev, ids);
+       return __acpi_match_device(acpi_companion_match(dev), ids, NULL);
 }
 EXPORT_SYMBOL_GPL(acpi_match_device);
 
 int acpi_match_device_ids(struct acpi_device *device,
                          const struct acpi_device_id *ids)
 {
-       return __acpi_match_device(device, ids) ? 0 : -ENOENT;
+       return __acpi_match_device(device, ids, NULL) ? 0 : -ENOENT;
 }
 EXPORT_SYMBOL(acpi_match_device_ids);
 
-/* Performs match against special "PRP0001" shoehorn ACPI ID */
-static bool acpi_of_driver_match_device(struct device *dev,
-                                       const struct device_driver *drv)
-{
-       const union acpi_object *of_compatible, *obj;
-       struct acpi_device *adev;
-       int i, nval;
-
-       adev = ACPI_COMPANION(dev);
-       if (!adev)
-               return false;
-
-       of_compatible = adev->data.of_compatible;
-       if (!drv->of_match_table || !of_compatible)
-               return false;
-
-       if (of_compatible->type == ACPI_TYPE_PACKAGE) {
-               nval = of_compatible->package.count;
-               obj = of_compatible->package.elements;
-       } else { /* Must be ACPI_TYPE_STRING. */
-               nval = 1;
-               obj = of_compatible;
-       }
-       /* Now we can look for the driver DT compatible strings */
-       for (i = 0; i < nval; i++, obj++) {
-               const struct of_device_id *id;
-
-               for (id = drv->of_match_table; id->compatible[0]; id++)
-                       if (!strcasecmp(obj->string.pointer, id->compatible))
-                               return true;
-       }
-
-       return false;
-}
-
 bool acpi_driver_match_device(struct device *dev,
                              const struct device_driver *drv)
 {
        if (!drv->acpi_match_table)
-               return acpi_of_driver_match_device(dev, drv);
+               return acpi_of_match_device(ACPI_COMPANION(dev),
+                                           drv->of_match_table);
 
-       return !!acpi_match_device(drv->acpi_match_table, dev);
+       return !!__acpi_match_device(acpi_companion_match(dev),
+                                    drv->acpi_match_table, drv->of_match_table);
 }
 EXPORT_SYMBOL_GPL(acpi_driver_match_device);
 
@@ -1031,20 +1122,7 @@ static int acpi_bus_match(struct device *dev, struct device_driver *drv)
 
 static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
-       struct acpi_device *acpi_dev = to_acpi_device(dev);
-       int len;
-
-       if (list_empty(&acpi_dev->pnp.ids))
-               return 0;
-
-       if (add_uevent_var(env, "MODALIAS="))
-               return -ENOMEM;
-       len = create_modalias(acpi_dev, &env->buf[env->buflen - 1],
-                             sizeof(env->buf) - env->buflen);
-       if (len <= 0)
-               return len;
-       env->buflen += len;
-       return 0;
+       return __acpi_device_uevent_modalias(to_acpi_device(dev), env);
 }
 
 static void acpi_device_notify(acpi_handle handle, u32 event, void *data)
@@ -1062,10 +1140,10 @@ static void acpi_device_notify_fixed(void *data)
        acpi_device_notify(NULL, ACPI_FIXED_HARDWARE_EVENT, device);
 }
 
-static acpi_status acpi_device_fixed_event(void *data)
+static u32 acpi_device_fixed_event(void *data)
 {
        acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_device_notify_fixed, data);
-       return AE_OK;
+       return ACPI_INTERRUPT_HANDLED;
 }
 
 static int acpi_device_install_notify_handler(struct acpi_device *device)
index 7f251dd1a6870df8e21c4b3e87d8ec6b193c5663..2f0d4db40a9e8aa078787b177d138322fdd6c0b9 100644 (file)
@@ -629,6 +629,7 @@ static int acpi_freeze_begin(void)
 
 static int acpi_freeze_prepare(void)
 {
+       acpi_enable_wakeup_devices(ACPI_STATE_S0);
        acpi_enable_all_wakeup_gpes();
        acpi_os_wait_events_complete();
        enable_irq_wake(acpi_gbl_FADT.sci_interrupt);
@@ -637,6 +638,7 @@ static int acpi_freeze_prepare(void)
 
 static void acpi_freeze_restore(void)
 {
+       acpi_disable_wakeup_devices(ACPI_STATE_S0);
        disable_irq_wake(acpi_gbl_FADT.sci_interrupt);
        acpi_enable_all_runtime_gpes();
 }
@@ -806,21 +808,6 @@ static void acpi_sleep_hibernate_setup(void)
 static inline void acpi_sleep_hibernate_setup(void) {}
 #endif /* !CONFIG_HIBERNATION */
 
-int acpi_suspend(u32 acpi_state)
-{
-       suspend_state_t states[] = {
-               [1] = PM_SUSPEND_STANDBY,
-               [3] = PM_SUSPEND_MEM,
-               [5] = PM_SUSPEND_MAX
-       };
-
-       if (acpi_state < 6 && states[acpi_state])
-               return pm_suspend(states[acpi_state]);
-       if (acpi_state == 4)
-               return hibernate();
-       return -EINVAL;
-}
-
 static void acpi_power_off_prepare(void)
 {
        /* Prepare to power off the system */
index 0143540a251979a4dd0ad1b21cce60d7cf47e815..c797ffa568d513c6533b576072f9967ed49f6c42 100644 (file)
@@ -1,6 +1,4 @@
 
-extern int acpi_suspend(u32 state);
-
 extern void acpi_enable_wakeup_devices(u8 sleep_state);
 extern void acpi_disable_wakeup_devices(u8 sleep_state);
 
index 13e577c80201bb1ce4341f9b99007e28d1a0a261..0876d77b320627507c945c9591026f6c0db60dcc 100644 (file)
@@ -527,7 +527,7 @@ static ssize_t counter_show(struct kobject *kobj,
            acpi_irq_not_handled;
        all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_GPE].count =
            acpi_gpe_count;
-       size = sprintf(buf, "%8d", all_counters[index].count);
+       size = sprintf(buf, "%8u", all_counters[index].count);
 
        /* "gpe_all" or "sci" */
        if (index >= num_gpes + ACPI_NUM_FIXED_EVENTS)
index 26eb70c8f5184f878ae489c4130e1b382d7394a2..cc79d3fedfb2a33aa8ca273865c1bf84ec2b190b 100644 (file)
@@ -82,9 +82,15 @@ module_param(allow_duplicates, bool, 0644);
  * For Windows 8 systems: used to decide if video module
  * should skip registering backlight interface of its own.
  */
-static int use_native_backlight_param = -1;
+enum {
+       NATIVE_BACKLIGHT_NOT_SET = -1,
+       NATIVE_BACKLIGHT_OFF,
+       NATIVE_BACKLIGHT_ON,
+};
+
+static int use_native_backlight_param = NATIVE_BACKLIGHT_NOT_SET;
 module_param_named(use_native_backlight, use_native_backlight_param, int, 0444);
-static bool use_native_backlight_dmi = true;
+static int use_native_backlight_dmi = NATIVE_BACKLIGHT_NOT_SET;
 
 static int register_count;
 static struct mutex video_list_lock;
@@ -237,15 +243,16 @@ static void acpi_video_switch_brightness(struct work_struct *work);
 
 static bool acpi_video_use_native_backlight(void)
 {
-       if (use_native_backlight_param != -1)
+       if (use_native_backlight_param != NATIVE_BACKLIGHT_NOT_SET)
                return use_native_backlight_param;
-       else
+       else if (use_native_backlight_dmi != NATIVE_BACKLIGHT_NOT_SET)
                return use_native_backlight_dmi;
+       return acpi_osi_is_win8();
 }
 
 bool acpi_video_verify_backlight_support(void)
 {
-       if (acpi_osi_is_win8() && acpi_video_use_native_backlight() &&
+       if (acpi_video_use_native_backlight() &&
            backlight_device_registered(BACKLIGHT_RAW))
                return false;
        return acpi_video_backlight_support();
@@ -414,7 +421,13 @@ static int __init video_set_bqc_offset(const struct dmi_system_id *d)
 
 static int __init video_disable_native_backlight(const struct dmi_system_id *d)
 {
-       use_native_backlight_dmi = false;
+       use_native_backlight_dmi = NATIVE_BACKLIGHT_OFF;
+       return 0;
+}
+
+static int __init video_enable_native_backlight(const struct dmi_system_id *d)
+{
+       use_native_backlight_dmi = NATIVE_BACKLIGHT_ON;
        return 0;
 }
 
@@ -559,6 +572,17 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
                DMI_MATCH(DMI_PRODUCT_NAME, "XPS L521X"),
                },
        },
+
+       /* Non win8 machines which need native backlight nevertheless */
+       {
+        /* https://bugzilla.redhat.com/show_bug.cgi?id=1187004 */
+        .callback = video_enable_native_backlight,
+        .ident = "Lenovo Ideapad Z570",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "102434U"),
+               },
+       },
        {}
 };
 
index 27c43499977a2a6236e1c3675bf2bb42a314e42f..c42feb2bacd0eb783bc94f0e10187d08ea907eea 100644 (file)
@@ -174,14 +174,6 @@ static struct dmi_system_id video_detect_dmi_table[] = {
                DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 5737"),
                },
        },
-       {
-       .callback = video_detect_force_vendor,
-       .ident = "Lenovo IdeaPad Z570",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-               DMI_MATCH(DMI_PRODUCT_VERSION, "Ideapad Z570"),
-               },
-       },
        { },
 };
 
index b33d1f99b3a44bb40e76a529a8eddbc2268bdc20..994f168b54a804184ebb01b20b8acda16230e62d 100644 (file)
@@ -128,20 +128,8 @@ static struct pnp_driver isapnp_driver = {
        .remove         = isapnp_remove_one,
 };
 
-static int __init isapnp_init(void)
-{
-       return pnp_register_driver(&isapnp_driver);
-}
-
-static void __exit isapnp_exit(void)
-{
-       pnp_unregister_driver(&isapnp_driver);
-}
-
+module_pnp_driver(isapnp_driver);
 MODULE_AUTHOR("Alan Cox");
 MODULE_DESCRIPTION("low-level driver for ISA PnP ATA");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
-
-module_init(isapnp_init);
-module_exit(isapnp_exit);
index cadf165651d8c5a507a32492fb78b7cff3e0b993..21d13038534e347f4fcccfc10f532659e2444928 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <linux/device.h>
 #include <linux/err.h>
+#include <linux/fwnode.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/slab.h>
@@ -2144,3 +2145,53 @@ define_dev_printk_level(dev_notice, KERN_NOTICE);
 define_dev_printk_level(_dev_info, KERN_INFO);
 
 #endif
+
+static inline bool fwnode_is_primary(struct fwnode_handle *fwnode)
+{
+       return fwnode && !IS_ERR(fwnode->secondary);
+}
+
+/**
+ * set_primary_fwnode - Change the primary firmware node of a given device.
+ * @dev: Device to handle.
+ * @fwnode: New primary firmware node of the device.
+ *
+ * Set the device's firmware node pointer to @fwnode, but if a secondary
+ * firmware node of the device is present, preserve it.
+ */
+void set_primary_fwnode(struct device *dev, struct fwnode_handle *fwnode)
+{
+       if (fwnode) {
+               struct fwnode_handle *fn = dev->fwnode;
+
+               if (fwnode_is_primary(fn))
+                       fn = fn->secondary;
+
+               fwnode->secondary = fn;
+               dev->fwnode = fwnode;
+       } else {
+               dev->fwnode = fwnode_is_primary(dev->fwnode) ?
+                       dev->fwnode->secondary : NULL;
+       }
+}
+EXPORT_SYMBOL_GPL(set_primary_fwnode);
+
+/**
+ * set_secondary_fwnode - Change the secondary firmware node of a given device.
+ * @dev: Device to handle.
+ * @fwnode: New secondary firmware node of the device.
+ *
+ * If a primary firmware node of the device is present, set its secondary
+ * pointer to @fwnode.  Otherwise, set the device's firmware node pointer to
+ * @fwnode.
+ */
+void set_secondary_fwnode(struct device *dev, struct fwnode_handle *fwnode)
+{
+       if (fwnode)
+               fwnode->secondary = ERR_PTR(-ENODEV);
+
+       if (fwnode_is_primary(dev->fwnode))
+               dev->fwnode->secondary = fwnode;
+       else
+               dev->fwnode = fwnode;
+}
index 49a4a12fafef176506a46063b390a194b29e9db4..e843fdbe492514d83fd1f66cfc8678b10099e877 100644 (file)
@@ -298,6 +298,12 @@ static int really_probe(struct device *dev, struct device_driver *drv)
                goto probe_failed;
        }
 
+       if (dev->pm_domain && dev->pm_domain->activate) {
+               ret = dev->pm_domain->activate(dev);
+               if (ret)
+                       goto probe_failed;
+       }
+
        if (dev->bus->probe) {
                ret = dev->bus->probe(dev);
                if (ret)
@@ -308,6 +314,9 @@ static int really_probe(struct device *dev, struct device_driver *drv)
                        goto probe_failed;
        }
 
+       if (dev->pm_domain && dev->pm_domain->sync)
+               dev->pm_domain->sync(dev);
+
        driver_bound(dev);
        ret = 1;
        pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
@@ -319,6 +328,8 @@ probe_failed:
        driver_sysfs_remove(dev);
        dev->driver = NULL;
        dev_set_drvdata(dev, NULL);
+       if (dev->pm_domain && dev->pm_domain->dismiss)
+               dev->pm_domain->dismiss(dev);
 
        switch (ret) {
        case -EPROBE_DEFER:
@@ -529,6 +540,9 @@ static void __device_release_driver(struct device *dev)
                devres_release_all(dev);
                dev->driver = NULL;
                dev_set_drvdata(dev, NULL);
+               if (dev->pm_domain && dev->pm_domain->dismiss)
+                       dev->pm_domain->dismiss(dev);
+
                klist_remove(&dev->p->knode_driver);
                if (dev->bus)
                        blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
index e68ab79df28bbc9e84c3e2f6f17f92369144c96d..ebf034b97278592ab57cbd24ef0f53d3cfc56e0a 100644 (file)
@@ -463,7 +463,7 @@ struct platform_device *platform_device_register_full(
                goto err_alloc;
 
        pdev->dev.parent = pdevinfo->parent;
-       ACPI_COMPANION_SET(&pdev->dev, pdevinfo->acpi_node.companion);
+       pdev->dev.fwnode = pdevinfo->fwnode;
 
        if (pdevinfo->dma_mask) {
                /*
index 45937f88e77c88893f6f05430efcd2dd88449e9f..2327613d453929db41e605df6614bc94a9b91067 100644 (file)
@@ -68,7 +68,36 @@ static struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
        return genpd;
 }
 
-struct generic_pm_domain *dev_to_genpd(struct device *dev)
+/*
+ * Get the generic PM domain for a particular struct device.
+ * This validates the struct device pointer, the PM domain pointer,
+ * and checks that the PM domain pointer is a real generic PM domain.
+ * Any failure results in NULL being returned.
+ */
+struct generic_pm_domain *pm_genpd_lookup_dev(struct device *dev)
+{
+       struct generic_pm_domain *genpd = NULL, *gpd;
+
+       if (IS_ERR_OR_NULL(dev) || IS_ERR_OR_NULL(dev->pm_domain))
+               return NULL;
+
+       mutex_lock(&gpd_list_lock);
+       list_for_each_entry(gpd, &gpd_list, gpd_list_node) {
+               if (&gpd->domain == dev->pm_domain) {
+                       genpd = gpd;
+                       break;
+               }
+       }
+       mutex_unlock(&gpd_list_lock);
+
+       return genpd;
+}
+
+/*
+ * This should only be used where we are certain that the pm_domain
+ * attached to the device is a genpd domain.
+ */
+static struct generic_pm_domain *dev_to_genpd(struct device *dev)
 {
        if (IS_ERR_OR_NULL(dev->pm_domain))
                return ERR_PTR(-EINVAL);
@@ -173,8 +202,8 @@ static int genpd_power_on(struct generic_pm_domain *genpd)
        genpd->power_on_latency_ns = elapsed_ns;
        genpd->max_off_time_changed = true;
        genpd_recalc_cpu_exit_latency(genpd);
-       pr_warn("%s: Power-%s latency exceeded, new value %lld ns\n",
-               genpd->name, "on", elapsed_ns);
+       pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n",
+                genpd->name, "on", elapsed_ns);
 
        return ret;
 }
@@ -199,8 +228,8 @@ static int genpd_power_off(struct generic_pm_domain *genpd)
 
        genpd->power_off_latency_ns = elapsed_ns;
        genpd->max_off_time_changed = true;
-       pr_warn("%s: Power-%s latency exceeded, new value %lld ns\n",
-               genpd->name, "off", elapsed_ns);
+       pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n",
+                genpd->name, "off", elapsed_ns);
 
        return ret;
 }
@@ -1513,9 +1542,7 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
 
        dev_dbg(dev, "%s()\n", __func__);
 
-       if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev)
-           ||  IS_ERR_OR_NULL(dev->pm_domain)
-           ||  pd_to_genpd(dev->pm_domain) != genpd)
+       if (!genpd || genpd != pm_genpd_lookup_dev(dev))
                return -EINVAL;
 
        /* The above validation also means we have existing domain_data. */
@@ -2093,21 +2120,10 @@ EXPORT_SYMBOL_GPL(of_genpd_get_from_provider);
  */
 static void genpd_dev_pm_detach(struct device *dev, bool power_off)
 {
-       struct generic_pm_domain *pd = NULL, *gpd;
+       struct generic_pm_domain *pd;
        int ret = 0;
 
-       if (!dev->pm_domain)
-               return;
-
-       mutex_lock(&gpd_list_lock);
-       list_for_each_entry(gpd, &gpd_list, gpd_list_node) {
-               if (&gpd->domain == dev->pm_domain) {
-                       pd = gpd;
-                       break;
-               }
-       }
-       mutex_unlock(&gpd_list_lock);
-
+       pd = pm_genpd_lookup_dev(dev);
        if (!pd)
                return;
 
@@ -2130,6 +2146,17 @@ static void genpd_dev_pm_detach(struct device *dev, bool power_off)
        genpd_queue_power_off_work(pd);
 }
 
+static void genpd_dev_pm_sync(struct device *dev)
+{
+       struct generic_pm_domain *pd;
+
+       pd = dev_to_genpd(dev);
+       if (IS_ERR(pd))
+               return;
+
+       genpd_queue_power_off_work(pd);
+}
+
 /**
  * genpd_dev_pm_attach - Attach a device to its PM domain using DT.
  * @dev: Device to attach.
@@ -2196,6 +2223,7 @@ int genpd_dev_pm_attach(struct device *dev)
        }
 
        dev->pm_domain->detach = genpd_dev_pm_detach;
+       dev->pm_domain->sync = genpd_dev_pm_sync;
        pm_genpd_poweron(pd);
 
        return 0;
index 9717d5f20139018e8485ae6dcd7fdb79d1d37acf..3d874eca71046dcf0eb983ff3ac2ec170a82d969 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/mutex.h>
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
-#include <linux/resume-trace.h>
+#include <linux/pm-trace.h>
 #include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <linux/async.h>
@@ -1017,6 +1017,9 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a
        char *info = NULL;
        int error = 0;
 
+       TRACE_DEVICE(dev);
+       TRACE_SUSPEND(0);
+
        if (async_error)
                goto Complete;
 
@@ -1057,6 +1060,7 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a
 
 Complete:
        complete_all(&dev->power.completion);
+       TRACE_SUSPEND(error);
        return error;
 }
 
@@ -1078,7 +1082,7 @@ static int device_suspend_noirq(struct device *dev)
 {
        reinit_completion(&dev->power.completion);
 
-       if (pm_async_enabled && dev->power.async_suspend) {
+       if (is_async(dev)) {
                get_device(dev);
                async_schedule(async_suspend_noirq, dev);
                return 0;
@@ -1157,6 +1161,9 @@ static int __device_suspend_late(struct device *dev, pm_message_t state, bool as
        char *info = NULL;
        int error = 0;
 
+       TRACE_DEVICE(dev);
+       TRACE_SUSPEND(0);
+
        __pm_runtime_disable(dev, false);
 
        if (async_error)
@@ -1198,6 +1205,7 @@ static int __device_suspend_late(struct device *dev, pm_message_t state, bool as
                async_error = error;
 
 Complete:
+       TRACE_SUSPEND(error);
        complete_all(&dev->power.completion);
        return error;
 }
@@ -1219,7 +1227,7 @@ static int device_suspend_late(struct device *dev)
 {
        reinit_completion(&dev->power.completion);
 
-       if (pm_async_enabled && dev->power.async_suspend) {
+       if (is_async(dev)) {
                get_device(dev);
                async_schedule(async_suspend_late, dev);
                return 0;
@@ -1338,6 +1346,9 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
        int error = 0;
        DECLARE_DPM_WATCHDOG_ON_STACK(wd);
 
+       TRACE_DEVICE(dev);
+       TRACE_SUSPEND(0);
+
        dpm_wait_for_children(dev, async);
 
        if (async_error)
@@ -1444,6 +1455,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
        if (error)
                async_error = error;
 
+       TRACE_SUSPEND(error);
        return error;
 }
 
@@ -1465,7 +1477,7 @@ static int device_suspend(struct device *dev)
 {
        reinit_completion(&dev->power.completion);
 
-       if (pm_async_enabled && dev->power.async_suspend) {
+       if (is_async(dev)) {
                get_device(dev);
                async_schedule(async_suspend, dev);
                return 0;
index d94a1f5121cf2292b5032ced369b0d6308faee72..a311cfa4c5bd7ca45e944293e0dd8c8a30cbf947 100644 (file)
@@ -7,7 +7,7 @@
  * devices may be working.
  */
 
-#include <linux/resume-trace.h>
+#include <linux/pm-trace.h>
 #include <linux/export.h>
 #include <linux/rtc.h>
 
@@ -154,7 +154,7 @@ EXPORT_SYMBOL(set_trace_device);
  * it's not any guarantee, but it's a high _likelihood_ that
  * the match is valid).
  */
-void generate_resume_trace(const void *tracedata, unsigned int user)
+void generate_pm_trace(const void *tracedata, unsigned int user)
 {
        unsigned short lineno = *(unsigned short *)tracedata;
        const char *file = *(const char **)(tracedata + 2);
@@ -164,7 +164,7 @@ void generate_resume_trace(const void *tracedata, unsigned int user)
        file_hash_value = hash_string(lineno, file, FILEHASH);
        set_magic_time(user_hash_value, file_hash_value, dev_hash_value);
 }
-EXPORT_SYMBOL(generate_resume_trace);
+EXPORT_SYMBOL(generate_pm_trace);
 
 extern char __tracedata_start, __tracedata_end;
 static int show_file_hash(unsigned int value)
index 423df593f262b1e0defaa087599781dad8ee4b8a..1d0b116cae959041682eaf6bb7ea91895b390e58 100644 (file)
  * published by the Free Software Foundation.
  */
 
-#include <linux/property.h>
-#include <linux/export.h>
 #include <linux/acpi.h>
+#include <linux/export.h>
+#include <linux/kernel.h>
 #include <linux/of.h>
+#include <linux/property.h>
+
+/**
+ * device_add_property_set - Add a collection of properties to a device object.
+ * @dev: Device to add properties to.
+ * @pset: Collection of properties to add.
+ *
+ * Associate a collection of device properties represented by @pset with @dev
+ * as its secondary firmware node.
+ */
+void device_add_property_set(struct device *dev, struct property_set *pset)
+{
+       if (pset)
+               pset->fwnode.type = FWNODE_PDATA;
+
+       set_secondary_fwnode(dev, &pset->fwnode);
+}
+EXPORT_SYMBOL_GPL(device_add_property_set);
+
+static inline bool is_pset(struct fwnode_handle *fwnode)
+{
+       return fwnode && fwnode->type == FWNODE_PDATA;
+}
+
+static inline struct property_set *to_pset(struct fwnode_handle *fwnode)
+{
+       return is_pset(fwnode) ?
+               container_of(fwnode, struct property_set, fwnode) : NULL;
+}
+
+static struct property_entry *pset_prop_get(struct property_set *pset,
+                                           const char *name)
+{
+       struct property_entry *prop;
+
+       if (!pset || !pset->properties)
+               return NULL;
+
+       for (prop = pset->properties; prop->name; prop++)
+               if (!strcmp(name, prop->name))
+                       return prop;
+
+       return NULL;
+}
+
+static int pset_prop_read_array(struct property_set *pset, const char *name,
+                               enum dev_prop_type type, void *val, size_t nval)
+{
+       struct property_entry *prop;
+       unsigned int item_size;
+
+       prop = pset_prop_get(pset, name);
+       if (!prop)
+               return -ENODATA;
+
+       if (prop->type != type)
+               return -EPROTO;
+
+       if (!val)
+               return prop->nval;
+
+       if (prop->nval < nval)
+               return -EOVERFLOW;
+
+       switch (type) {
+       case DEV_PROP_U8:
+               item_size = sizeof(u8);
+               break;
+       case DEV_PROP_U16:
+               item_size = sizeof(u16);
+               break;
+       case DEV_PROP_U32:
+               item_size = sizeof(u32);
+               break;
+       case DEV_PROP_U64:
+               item_size = sizeof(u64);
+               break;
+       case DEV_PROP_STRING:
+               item_size = sizeof(const char *);
+               break;
+       default:
+               return -EINVAL;
+       }
+       memcpy(val, prop->value.raw_data, nval * item_size);
+       return 0;
+}
+
+static inline struct fwnode_handle *dev_fwnode(struct device *dev)
+{
+       return IS_ENABLED(CONFIG_OF) && dev->of_node ?
+               &dev->of_node->fwnode : dev->fwnode;
+}
 
 /**
  * device_property_present - check if a property of a device is present
  */
 bool device_property_present(struct device *dev, const char *propname)
 {
-       if (IS_ENABLED(CONFIG_OF) && dev->of_node)
-               return of_property_read_bool(dev->of_node, propname);
-
-       return !acpi_dev_prop_get(ACPI_COMPANION(dev), propname, NULL);
+       return fwnode_property_present(dev_fwnode(dev), propname);
 }
 EXPORT_SYMBOL_GPL(device_property_present);
 
@@ -43,32 +132,22 @@ bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname)
        else if (is_acpi_node(fwnode))
                return !acpi_dev_prop_get(acpi_node(fwnode), propname, NULL);
 
-       return false;
+       return !!pset_prop_get(to_pset(fwnode), propname);
 }
 EXPORT_SYMBOL_GPL(fwnode_property_present);
 
-#define OF_DEV_PROP_READ_ARRAY(node, propname, type, val, nval) \
-       (val) ? of_property_read_##type##_array((node), (propname), (val), (nval)) \
-             : of_property_count_elems_of_size((node), (propname), sizeof(type))
-
-#define DEV_PROP_READ_ARRAY(_dev_, _propname_, _type_, _proptype_, _val_, _nval_) \
-       IS_ENABLED(CONFIG_OF) && _dev_->of_node ? \
-               (OF_DEV_PROP_READ_ARRAY(_dev_->of_node, _propname_, _type_, \
-                                       _val_, _nval_)) : \
-               acpi_dev_prop_read(ACPI_COMPANION(_dev_), _propname_, \
-                                  _proptype_, _val_, _nval_)
-
 /**
  * device_property_read_u8_array - return a u8 array property of a device
  * @dev: Device to get the property of
  * @propname: Name of the property
- * @val: The values are stored here
+ * @val: The values are stored here or %NULL to return the number of values
  * @nval: Size of the @val array
  *
  * Function reads an array of u8 properties with @propname from the device
  * firmware description and stores them to @val if found.
  *
- * Return: %0 if the property was found (success),
+ * Return: number of values if @val was %NULL,
+ *         %0 if the property was found (success),
  *        %-EINVAL if given arguments are not valid,
  *        %-ENODATA if the property does not have a value,
  *        %-EPROTO if the property is not an array of numbers,
@@ -77,7 +156,7 @@ EXPORT_SYMBOL_GPL(fwnode_property_present);
 int device_property_read_u8_array(struct device *dev, const char *propname,
                                  u8 *val, size_t nval)
 {
-       return DEV_PROP_READ_ARRAY(dev, propname, u8, DEV_PROP_U8, val, nval);
+       return fwnode_property_read_u8_array(dev_fwnode(dev), propname, val, nval);
 }
 EXPORT_SYMBOL_GPL(device_property_read_u8_array);
 
@@ -85,13 +164,14 @@ EXPORT_SYMBOL_GPL(device_property_read_u8_array);
  * device_property_read_u16_array - return a u16 array property of a device
  * @dev: Device to get the property of
  * @propname: Name of the property
- * @val: The values are stored here
+ * @val: The values are stored here or %NULL to return the number of values
  * @nval: Size of the @val array
  *
  * Function reads an array of u16 properties with @propname from the device
  * firmware description and stores them to @val if found.
  *
- * Return: %0 if the property was found (success),
+ * Return: number of values if @val was %NULL,
+ *         %0 if the property was found (success),
  *        %-EINVAL if given arguments are not valid,
  *        %-ENODATA if the property does not have a value,
  *        %-EPROTO if the property is not an array of numbers,
@@ -100,7 +180,7 @@ EXPORT_SYMBOL_GPL(device_property_read_u8_array);
 int device_property_read_u16_array(struct device *dev, const char *propname,
                                   u16 *val, size_t nval)
 {
-       return DEV_PROP_READ_ARRAY(dev, propname, u16, DEV_PROP_U16, val, nval);
+       return fwnode_property_read_u16_array(dev_fwnode(dev), propname, val, nval);
 }
 EXPORT_SYMBOL_GPL(device_property_read_u16_array);
 
@@ -108,13 +188,14 @@ EXPORT_SYMBOL_GPL(device_property_read_u16_array);
  * device_property_read_u32_array - return a u32 array property of a device
  * @dev: Device to get the property of
  * @propname: Name of the property
- * @val: The values are stored here
+ * @val: The values are stored here or %NULL to return the number of values
  * @nval: Size of the @val array
  *
  * Function reads an array of u32 properties with @propname from the device
  * firmware description and stores them to @val if found.
  *
- * Return: %0 if the property was found (success),
+ * Return: number of values if @val was %NULL,
+ *         %0 if the property was found (success),
  *        %-EINVAL if given arguments are not valid,
  *        %-ENODATA if the property does not have a value,
  *        %-EPROTO if the property is not an array of numbers,
@@ -123,7 +204,7 @@ EXPORT_SYMBOL_GPL(device_property_read_u16_array);
 int device_property_read_u32_array(struct device *dev, const char *propname,
                                   u32 *val, size_t nval)
 {
-       return DEV_PROP_READ_ARRAY(dev, propname, u32, DEV_PROP_U32, val, nval);
+       return fwnode_property_read_u32_array(dev_fwnode(dev), propname, val, nval);
 }
 EXPORT_SYMBOL_GPL(device_property_read_u32_array);
 
@@ -131,13 +212,14 @@ EXPORT_SYMBOL_GPL(device_property_read_u32_array);
  * device_property_read_u64_array - return a u64 array property of a device
  * @dev: Device to get the property of
  * @propname: Name of the property
- * @val: The values are stored here
+ * @val: The values are stored here or %NULL to return the number of values
  * @nval: Size of the @val array
  *
  * Function reads an array of u64 properties with @propname from the device
  * firmware description and stores them to @val if found.
  *
- * Return: %0 if the property was found (success),
+ * Return: number of values if @val was %NULL,
+ *         %0 if the property was found (success),
  *        %-EINVAL if given arguments are not valid,
  *        %-ENODATA if the property does not have a value,
  *        %-EPROTO if the property is not an array of numbers,
@@ -146,7 +228,7 @@ EXPORT_SYMBOL_GPL(device_property_read_u32_array);
 int device_property_read_u64_array(struct device *dev, const char *propname,
                                   u64 *val, size_t nval)
 {
-       return DEV_PROP_READ_ARRAY(dev, propname, u64, DEV_PROP_U64, val, nval);
+       return fwnode_property_read_u64_array(dev_fwnode(dev), propname, val, nval);
 }
 EXPORT_SYMBOL_GPL(device_property_read_u64_array);
 
@@ -154,13 +236,14 @@ EXPORT_SYMBOL_GPL(device_property_read_u64_array);
  * device_property_read_string_array - return a string array property of device
  * @dev: Device to get the property of
  * @propname: Name of the property
- * @val: The values are stored here
+ * @val: The values are stored here or %NULL to return the number of values
  * @nval: Size of the @val array
  *
  * Function reads an array of string properties with @propname from the device
  * firmware description and stores them to @val if found.
  *
- * Return: %0 if the property was found (success),
+ * Return: number of values if @val was %NULL,
+ *         %0 if the property was found (success),
  *        %-EINVAL if given arguments are not valid,
  *        %-ENODATA if the property does not have a value,
  *        %-EPROTO or %-EILSEQ if the property is not an array of strings,
@@ -169,10 +252,7 @@ EXPORT_SYMBOL_GPL(device_property_read_u64_array);
 int device_property_read_string_array(struct device *dev, const char *propname,
                                      const char **val, size_t nval)
 {
-       return IS_ENABLED(CONFIG_OF) && dev->of_node ?
-               of_property_read_string_array(dev->of_node, propname, val, nval) :
-               acpi_dev_prop_read(ACPI_COMPANION(dev), propname,
-                                  DEV_PROP_STRING, val, nval);
+       return fwnode_property_read_string_array(dev_fwnode(dev), propname, val, nval);
 }
 EXPORT_SYMBOL_GPL(device_property_read_string_array);
 
@@ -193,13 +273,14 @@ EXPORT_SYMBOL_GPL(device_property_read_string_array);
 int device_property_read_string(struct device *dev, const char *propname,
                                const char **val)
 {
-       return IS_ENABLED(CONFIG_OF) && dev->of_node ?
-               of_property_read_string(dev->of_node, propname, val) :
-               acpi_dev_prop_read(ACPI_COMPANION(dev), propname,
-                                  DEV_PROP_STRING, val, 1);
+       return fwnode_property_read_string(dev_fwnode(dev), propname, val);
 }
 EXPORT_SYMBOL_GPL(device_property_read_string);
 
+#define OF_DEV_PROP_READ_ARRAY(node, propname, type, val, nval) \
+       (val) ? of_property_read_##type##_array((node), (propname), (val), (nval)) \
+             : of_property_count_elems_of_size((node), (propname), sizeof(type))
+
 #define FWNODE_PROP_READ_ARRAY(_fwnode_, _propname_, _type_, _proptype_, _val_, _nval_) \
 ({ \
        int _ret_; \
@@ -210,7 +291,8 @@ EXPORT_SYMBOL_GPL(device_property_read_string);
                _ret_ = acpi_dev_prop_read(acpi_node(_fwnode_), _propname_, \
                                           _proptype_, _val_, _nval_); \
        else \
-               _ret_ = -ENXIO; \
+               _ret_ = pset_prop_read_array(to_pset(_fwnode_), _propname_, \
+                                            _proptype_, _val_, _nval_); \
        _ret_; \
 })
 
@@ -218,13 +300,14 @@ EXPORT_SYMBOL_GPL(device_property_read_string);
  * fwnode_property_read_u8_array - return a u8 array property of firmware node
  * @fwnode: Firmware node to get the property of
  * @propname: Name of the property
- * @val: The values are stored here
+ * @val: The values are stored here or %NULL to return the number of values
  * @nval: Size of the @val array
  *
  * Read an array of u8 properties with @propname from @fwnode and stores them to
  * @val if found.
  *
- * Return: %0 if the property was found (success),
+ * Return: number of values if @val was %NULL,
+ *         %0 if the property was found (success),
  *        %-EINVAL if given arguments are not valid,
  *        %-ENODATA if the property does not have a value,
  *        %-EPROTO if the property is not an array of numbers,
@@ -243,13 +326,14 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_u8_array);
  * fwnode_property_read_u16_array - return a u16 array property of firmware node
  * @fwnode: Firmware node to get the property of
  * @propname: Name of the property
- * @val: The values are stored here
+ * @val: The values are stored here or %NULL to return the number of values
  * @nval: Size of the @val array
  *
  * Read an array of u16 properties with @propname from @fwnode and store them to
  * @val if found.
  *
- * Return: %0 if the property was found (success),
+ * Return: number of values if @val was %NULL,
+ *         %0 if the property was found (success),
  *        %-EINVAL if given arguments are not valid,
  *        %-ENODATA if the property does not have a value,
  *        %-EPROTO if the property is not an array of numbers,
@@ -268,13 +352,14 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_u16_array);
  * fwnode_property_read_u32_array - return a u32 array property of firmware node
  * @fwnode: Firmware node to get the property of
  * @propname: Name of the property
- * @val: The values are stored here
+ * @val: The values are stored here or %NULL to return the number of values
  * @nval: Size of the @val array
  *
  * Read an array of u32 properties with @propname from @fwnode store them to
  * @val if found.
  *
- * Return: %0 if the property was found (success),
+ * Return: number of values if @val was %NULL,
+ *         %0 if the property was found (success),
  *        %-EINVAL if given arguments are not valid,
  *        %-ENODATA if the property does not have a value,
  *        %-EPROTO if the property is not an array of numbers,
@@ -293,13 +378,14 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_u32_array);
  * fwnode_property_read_u64_array - return a u64 array property firmware node
  * @fwnode: Firmware node to get the property of
  * @propname: Name of the property
- * @val: The values are stored here
+ * @val: The values are stored here or %NULL to return the number of values
  * @nval: Size of the @val array
  *
  * Read an array of u64 properties with @propname from @fwnode and store them to
  * @val if found.
  *
- * Return: %0 if the property was found (success),
+ * Return: number of values if @val was %NULL,
+ *         %0 if the property was found (success),
  *        %-EINVAL if given arguments are not valid,
  *        %-ENODATA if the property does not have a value,
  *        %-EPROTO if the property is not an array of numbers,
@@ -318,13 +404,14 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_u64_array);
  * fwnode_property_read_string_array - return string array property of a node
  * @fwnode: Firmware node to get the property of
  * @propname: Name of the property
- * @val: The values are stored here
+ * @val: The values are stored here or %NULL to return the number of values
  * @nval: Size of the @val array
  *
  * Read an string list property @propname from the given firmware node and store
  * them to @val if found.
  *
- * Return: %0 if the property was found (success),
+ * Return: number of values if @val was %NULL,
+ *         %0 if the property was found (success),
  *        %-EINVAL if given arguments are not valid,
  *        %-ENODATA if the property does not have a value,
  *        %-EPROTO if the property is not an array of strings,
@@ -336,13 +423,16 @@ int fwnode_property_read_string_array(struct fwnode_handle *fwnode,
                                      size_t nval)
 {
        if (is_of_node(fwnode))
-               return of_property_read_string_array(of_node(fwnode), propname,
-                                                    val, nval);
+               return val ?
+                       of_property_read_string_array(of_node(fwnode), propname,
+                                                     val, nval) :
+                       of_property_count_strings(of_node(fwnode), propname);
        else if (is_acpi_node(fwnode))
                return acpi_dev_prop_read(acpi_node(fwnode), propname,
                                          DEV_PROP_STRING, val, nval);
 
-       return -ENXIO;
+       return pset_prop_read_array(to_pset(fwnode), propname,
+                                   DEV_PROP_STRING, val, nval);
 }
 EXPORT_SYMBOL_GPL(fwnode_property_read_string_array);
 
index 6d492132ad2b755da40d11d7ff99e5cff8a56bcb..29ba520ac24d2fb60cd8d2e788774fc69bdd40c2 100644 (file)
@@ -637,18 +637,7 @@ static struct pnp_driver tpm_inf_pnp_driver = {
        .remove = tpm_inf_pnp_remove
 };
 
-static int __init init_inf(void)
-{
-       return pnp_register_driver(&tpm_inf_pnp_driver);
-}
-
-static void __exit cleanup_inf(void)
-{
-       pnp_unregister_driver(&tpm_inf_pnp_driver);
-}
-
-module_init(init_inf);
-module_exit(cleanup_inf);
+module_pnp_driver(tpm_inf_pnp_driver);
 
 MODULE_AUTHOR("Marcel Selhorst <tpmdd@sirrix.com>");
 MODULE_DESCRIPTION("Driver for Infineon TPM SLD 9630 TT 1.1 / SLB 9635 TT 1.2");
index a171fef2c2b66d0732e01f349f9fa13b01f8af2e..659879a56dbac59c7f18e0d2f51393bf9a3e645f 100644 (file)
@@ -293,5 +293,13 @@ config SH_CPU_FREQ
          If unsure, say N.
 endif
 
+config QORIQ_CPUFREQ
+       tristate "CPU frequency scaling driver for Freescale QorIQ SoCs"
+       depends on OF && COMMON_CLK && (PPC_E500MC || ARM)
+       select CLK_QORIQ
+       help
+         This adds the CPUFreq driver support for Freescale QorIQ SoCs
+         which are capable of changing the CPU's frequency dynamically.
+
 endif
 endmenu
index 1b06fc4640e23c2840cda6011d7c061eedd64a49..4f3dbc8cf7292773d9fcc442edfc8ef695a4a432 100644 (file)
@@ -108,6 +108,15 @@ config ARM_HIGHBANK_CPUFREQ
 
          If in doubt, say N.
 
+config ARM_HISI_ACPU_CPUFREQ
+       tristate "Hisilicon ACPU CPUfreq driver"
+       depends on ARCH_HISI && CPUFREQ_DT
+       select PM_OPP
+       help
+         This enables the hisilicon ACPU CPUfreq driver.
+
+         If in doubt, say N.
+
 config ARM_IMX6Q_CPUFREQ
        tristate "Freescale i.MX6 cpufreq support"
        depends on ARCH_MXC
index 7ea24413cee6855c65daa7954bc4843622402e75..3a0595b41eab950709e376d163645a8b09b9448f 100644 (file)
@@ -23,15 +23,6 @@ config CPU_FREQ_MAPLE
          This adds support for frequency switching on Maple 970FX
          Evaluation Board and compatible boards (IBM JS2x blades).
 
-config PPC_CORENET_CPUFREQ
-       tristate "CPU frequency scaling driver for Freescale E500MC SoCs"
-       depends on PPC_E500MC && OF && COMMON_CLK
-       select CLK_QORIQ
-       help
-         This adds the CPUFreq driver support for Freescale e500mc,
-         e5500 and e6500 series SoCs which are capable of changing
-         the CPU's frequency dynamically.
-
 config CPU_FREQ_PMAC
        bool "Support for Apple PowerBooks"
        depends on ADB_PMU && PPC32
index 82a1821471fd870a9eba9323d63c4b925c06a97c..cdce92ae2e8b7fdb81e4d25e3ab03ced14e63aac 100644 (file)
@@ -59,6 +59,7 @@ arm-exynos-cpufreq-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ)   += exynos4x12-cpufreq.o
 arm-exynos-cpufreq-$(CONFIG_ARM_EXYNOS5250_CPUFREQ)    += exynos5250-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS5440_CPUFREQ)   += exynos5440-cpufreq.o
 obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ)     += highbank-cpufreq.o
+obj-$(CONFIG_ARM_HISI_ACPU_CPUFREQ)    += hisi-acpu-cpufreq.o
 obj-$(CONFIG_ARM_IMX6Q_CPUFREQ)                += imx6q-cpufreq.o
 obj-$(CONFIG_ARM_INTEGRATOR)           += integrator-cpufreq.o
 obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ)     += kirkwood-cpufreq.o
@@ -85,7 +86,7 @@ obj-$(CONFIG_CPU_FREQ_CBE)            += ppc-cbe-cpufreq.o
 ppc-cbe-cpufreq-y                      += ppc_cbe_cpufreq_pervasive.o ppc_cbe_cpufreq.o
 obj-$(CONFIG_CPU_FREQ_CBE_PMI)         += ppc_cbe_cpufreq_pmi.o
 obj-$(CONFIG_CPU_FREQ_MAPLE)           += maple-cpufreq.o
-obj-$(CONFIG_PPC_CORENET_CPUFREQ)   += ppc-corenet-cpufreq.o
+obj-$(CONFIG_QORIQ_CPUFREQ)            += qoriq-cpufreq.o
 obj-$(CONFIG_CPU_FREQ_PMAC)            += pmac32-cpufreq.o
 obj-$(CONFIG_CPU_FREQ_PMAC64)          += pmac64-cpufreq.o
 obj-$(CONFIG_PPC_PASEMI_CPUFREQ)       += pasemi-cpufreq.o
diff --git a/drivers/cpufreq/hisi-acpu-cpufreq.c b/drivers/cpufreq/hisi-acpu-cpufreq.c
new file mode 100644 (file)
index 0000000..026d5b2
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Hisilicon Platforms Using ACPU CPUFreq Support
+ *
+ * Copyright (c) 2015 Hisilicon Limited.
+ * Copyright (c) 2015 Linaro Limited.
+ *
+ * Leo Yan <leo.yan@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+static int __init hisi_acpu_cpufreq_driver_init(void)
+{
+       struct platform_device *pdev;
+
+       if (!of_machine_is_compatible("hisilicon,hi6220"))
+               return -ENODEV;
+
+       pdev = platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
+       return PTR_ERR_OR_ZERO(pdev);
+}
+module_init(hisi_acpu_cpufreq_driver_init);
+
+MODULE_AUTHOR("Leo Yan <leo.yan@linaro.org>");
+MODULE_DESCRIPTION("Hisilicon acpu cpufreq driver");
+MODULE_LICENSE("GPL v2");
index 872c5772c5d358ab8fafcf723579cbf2b020dc47..c5b81beccc8e31e2d7f66a1580e4f206c0cd7297 100644 (file)
@@ -614,6 +614,19 @@ static void core_set_pstate(struct cpudata *cpudata, int pstate)
        wrmsrl_on_cpu(cpudata->cpu, MSR_IA32_PERF_CTL, val);
 }
 
+static int knl_get_turbo_pstate(void)
+{
+       u64 value;
+       int nont, ret;
+
+       rdmsrl(MSR_NHM_TURBO_RATIO_LIMIT, value);
+       nont = core_get_max_pstate();
+       ret = (((value) >> 8) & 0xFF);
+       if (ret <= nont)
+               ret = nont;
+       return ret;
+}
+
 static struct cpu_defaults core_params = {
        .pid_policy = {
                .sample_rate_ms = 10,
@@ -651,6 +664,23 @@ static struct cpu_defaults byt_params = {
        },
 };
 
+static struct cpu_defaults knl_params = {
+       .pid_policy = {
+               .sample_rate_ms = 10,
+               .deadband = 0,
+               .setpoint = 97,
+               .p_gain_pct = 20,
+               .d_gain_pct = 0,
+               .i_gain_pct = 0,
+       },
+       .funcs = {
+               .get_max = core_get_max_pstate,
+               .get_min = core_get_min_pstate,
+               .get_turbo = knl_get_turbo_pstate,
+               .set = core_set_pstate,
+       },
+};
+
 static void intel_pstate_get_min_max(struct cpudata *cpu, int *min, int *max)
 {
        int max_perf = cpu->pstate.turbo_pstate;
@@ -865,6 +895,7 @@ static const struct x86_cpu_id intel_pstate_cpu_ids[] = {
        ICPU(0x4e, core_params),
        ICPU(0x4f, core_params),
        ICPU(0x56, core_params),
+       ICPU(0x57, knl_params),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, intel_pstate_cpu_ids);
@@ -1024,25 +1055,11 @@ static unsigned int force_load;
 
 static int intel_pstate_msrs_not_valid(void)
 {
-       /* Check that all the msr's we are using are valid. */
-       u64 aperf, mperf, tmp;
-
-       rdmsrl(MSR_IA32_APERF, aperf);
-       rdmsrl(MSR_IA32_MPERF, mperf);
-
        if (!pstate_funcs.get_max() ||
            !pstate_funcs.get_min() ||
            !pstate_funcs.get_turbo())
                return -ENODEV;
 
-       rdmsrl(MSR_IA32_APERF, tmp);
-       if (!(tmp - aperf))
-               return -ENODEV;
-
-       rdmsrl(MSR_IA32_MPERF, tmp);
-       if (!(tmp - mperf))
-               return -ENODEV;
-
        return 0;
 }
 
index 2dfd4fdb5a52bd8d82fe2603acf550732803798b..ebef0d8279c77245d1768556ba06d7c3c0375a57 100644 (file)
 #include <asm/smp.h> /* Required for cpu_sibling_mask() in UP configs */
 
 #define POWERNV_MAX_PSTATES    256
+#define PMSR_PSAFE_ENABLE      (1UL << 30)
+#define PMSR_SPR_EM_DISABLE    (1UL << 31)
+#define PMSR_MAX(x)            ((x >> 32) & 0xFF)
+#define PMSR_LP(x)             ((x >> 48) & 0xFF)
 
 static struct cpufreq_frequency_table powernv_freqs[POWERNV_MAX_PSTATES+1];
-static bool rebooting;
+static bool rebooting, throttled;
 
 /*
  * Note: The set of pstates consists of contiguous integers, the
@@ -294,6 +298,44 @@ static inline unsigned int get_nominal_index(void)
        return powernv_pstate_info.max - powernv_pstate_info.nominal;
 }
 
+static void powernv_cpufreq_throttle_check(unsigned int cpu)
+{
+       unsigned long pmsr;
+       int pmsr_pmax, pmsr_lp;
+
+       pmsr = get_pmspr(SPRN_PMSR);
+
+       /* Check for Pmax Capping */
+       pmsr_pmax = (s8)PMSR_MAX(pmsr);
+       if (pmsr_pmax != powernv_pstate_info.max) {
+               throttled = true;
+               pr_info("CPU %d Pmax is reduced to %d\n", cpu, pmsr_pmax);
+               pr_info("Max allowed Pstate is capped\n");
+       }
+
+       /*
+        * Check for Psafe by reading LocalPstate
+        * or check if Psafe_mode_active is set in PMSR.
+        */
+       pmsr_lp = (s8)PMSR_LP(pmsr);
+       if ((pmsr_lp < powernv_pstate_info.min) ||
+                               (pmsr & PMSR_PSAFE_ENABLE)) {
+               throttled = true;
+               pr_info("Pstate set to safe frequency\n");
+       }
+
+       /* Check if SPR_EM_DISABLE is set in PMSR */
+       if (pmsr & PMSR_SPR_EM_DISABLE) {
+               throttled = true;
+               pr_info("Frequency Control disabled from OS\n");
+       }
+
+       if (throttled) {
+               pr_info("PMSR = %16lx\n", pmsr);
+               pr_crit("CPU Frequency could be throttled\n");
+       }
+}
+
 /*
  * powernv_cpufreq_target_index: Sets the frequency corresponding to
  * the cpufreq table entry indexed by new_index on the cpus in the
@@ -307,6 +349,9 @@ static int powernv_cpufreq_target_index(struct cpufreq_policy *policy,
        if (unlikely(rebooting) && new_index != get_nominal_index())
                return 0;
 
+       if (!throttled)
+               powernv_cpufreq_throttle_check(smp_processor_id());
+
        freq_data.pstate_id = powernv_freqs[new_index].driver_data;
 
        /*
diff --git a/drivers/cpufreq/ppc-corenet-cpufreq.c b/drivers/cpufreq/ppc-corenet-cpufreq.c
deleted file mode 100644 (file)
index 7cb4b76..0000000
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Copyright 2013 Freescale Semiconductor, Inc.
- *
- * CPU Frequency Scaling driver for Freescale PowerPC corenet SoCs.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#define pr_fmt(fmt)    KBUILD_MODNAME ": " fmt
-
-#include <linux/clk.h>
-#include <linux/cpufreq.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/of.h>
-#include <linux/slab.h>
-#include <linux/smp.h>
-#include <sysdev/fsl_soc.h>
-
-#include <asm/smp.h>   /* for get_hard_smp_processor_id() in UP configs */
-
-/**
- * struct cpu_data - per CPU data struct
- * @parent: the parent node of cpu clock
- * @table: frequency table
- */
-struct cpu_data {
-       struct device_node *parent;
-       struct cpufreq_frequency_table *table;
-};
-
-/**
- * struct soc_data - SoC specific data
- * @freq_mask: mask the disallowed frequencies
- * @flag: unique flags
- */
-struct soc_data {
-       u32 freq_mask[4];
-       u32 flag;
-};
-
-#define FREQ_MASK      1
-/* see hardware specification for the allowed frqeuencies */
-static const struct soc_data sdata[] = {
-       { /* used by p2041 and p3041 */
-               .freq_mask = {0x8, 0x8, 0x2, 0x2},
-               .flag = FREQ_MASK,
-       },
-       { /* used by p5020 */
-               .freq_mask = {0x8, 0x2},
-               .flag = FREQ_MASK,
-       },
-       { /* used by p4080, p5040 */
-               .freq_mask = {0},
-               .flag = 0,
-       },
-};
-
-/*
- * the minimum allowed core frequency, in Hz
- * for chassis v1.0, >= platform frequency
- * for chassis v2.0, >= platform frequency / 2
- */
-static u32 min_cpufreq;
-static const u32 *fmask;
-
-static DEFINE_PER_CPU(struct cpu_data *, cpu_data);
-
-/* cpumask in a cluster */
-static DEFINE_PER_CPU(cpumask_var_t, cpu_mask);
-
-#ifndef CONFIG_SMP
-static inline const struct cpumask *cpu_core_mask(int cpu)
-{
-       return cpumask_of(0);
-}
-#endif
-
-/* reduce the duplicated frequencies in frequency table */
-static void freq_table_redup(struct cpufreq_frequency_table *freq_table,
-               int count)
-{
-       int i, j;
-
-       for (i = 1; i < count; i++) {
-               for (j = 0; j < i; j++) {
-                       if (freq_table[j].frequency == CPUFREQ_ENTRY_INVALID ||
-                                       freq_table[j].frequency !=
-                                       freq_table[i].frequency)
-                               continue;
-
-                       freq_table[i].frequency = CPUFREQ_ENTRY_INVALID;
-                       break;
-               }
-       }
-}
-
-/* sort the frequencies in frequency table in descenting order */
-static void freq_table_sort(struct cpufreq_frequency_table *freq_table,
-               int count)
-{
-       int i, j, ind;
-       unsigned int freq, max_freq;
-       struct cpufreq_frequency_table table;
-       for (i = 0; i < count - 1; i++) {
-               max_freq = freq_table[i].frequency;
-               ind = i;
-               for (j = i + 1; j < count; j++) {
-                       freq = freq_table[j].frequency;
-                       if (freq == CPUFREQ_ENTRY_INVALID ||
-                                       freq <= max_freq)
-                               continue;
-                       ind = j;
-                       max_freq = freq;
-               }
-
-               if (ind != i) {
-                       /* exchange the frequencies */
-                       table.driver_data = freq_table[i].driver_data;
-                       table.frequency = freq_table[i].frequency;
-                       freq_table[i].driver_data = freq_table[ind].driver_data;
-                       freq_table[i].frequency = freq_table[ind].frequency;
-                       freq_table[ind].driver_data = table.driver_data;
-                       freq_table[ind].frequency = table.frequency;
-               }
-       }
-}
-
-static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy)
-{
-       struct device_node *np;
-       int i, count, ret;
-       u32 freq, mask;
-       struct clk *clk;
-       struct cpufreq_frequency_table *table;
-       struct cpu_data *data;
-       unsigned int cpu = policy->cpu;
-       u64 u64temp;
-
-       np = of_get_cpu_node(cpu, NULL);
-       if (!np)
-               return -ENODEV;
-
-       data = kzalloc(sizeof(*data), GFP_KERNEL);
-       if (!data) {
-               pr_err("%s: no memory\n", __func__);
-               goto err_np;
-       }
-
-       policy->clk = of_clk_get(np, 0);
-       if (IS_ERR(policy->clk)) {
-               pr_err("%s: no clock information\n", __func__);
-               goto err_nomem2;
-       }
-
-       data->parent = of_parse_phandle(np, "clocks", 0);
-       if (!data->parent) {
-               pr_err("%s: could not get clock information\n", __func__);
-               goto err_nomem2;
-       }
-
-       count = of_property_count_strings(data->parent, "clock-names");
-       table = kcalloc(count + 1, sizeof(*table), GFP_KERNEL);
-       if (!table) {
-               pr_err("%s: no memory\n", __func__);
-               goto err_node;
-       }
-
-       if (fmask)
-               mask = fmask[get_hard_smp_processor_id(cpu)];
-       else
-               mask = 0x0;
-
-       for (i = 0; i < count; i++) {
-               clk = of_clk_get(data->parent, i);
-               freq = clk_get_rate(clk);
-               /*
-                * the clock is valid if its frequency is not masked
-                * and large than minimum allowed frequency.
-                */
-               if (freq < min_cpufreq || (mask & (1 << i)))
-                       table[i].frequency = CPUFREQ_ENTRY_INVALID;
-               else
-                       table[i].frequency = freq / 1000;
-               table[i].driver_data = i;
-       }
-       freq_table_redup(table, count);
-       freq_table_sort(table, count);
-       table[i].frequency = CPUFREQ_TABLE_END;
-
-       /* set the min and max frequency properly */
-       ret = cpufreq_table_validate_and_show(policy, table);
-       if (ret) {
-               pr_err("invalid frequency table: %d\n", ret);
-               goto err_nomem1;
-       }
-
-       data->table = table;
-
-       /* update ->cpus if we have cluster, no harm if not */
-       cpumask_copy(policy->cpus, per_cpu(cpu_mask, cpu));
-       for_each_cpu(i, per_cpu(cpu_mask, cpu))
-               per_cpu(cpu_data, i) = data;
-
-       /* Minimum transition latency is 12 platform clocks */
-       u64temp = 12ULL * NSEC_PER_SEC;
-       do_div(u64temp, fsl_get_sys_freq());
-       policy->cpuinfo.transition_latency = u64temp + 1;
-
-       of_node_put(np);
-
-       return 0;
-
-err_nomem1:
-       kfree(table);
-err_node:
-       of_node_put(data->parent);
-err_nomem2:
-       per_cpu(cpu_data, cpu) = NULL;
-       kfree(data);
-err_np:
-       of_node_put(np);
-
-       return -ENODEV;
-}
-
-static int __exit corenet_cpufreq_cpu_exit(struct cpufreq_policy *policy)
-{
-       struct cpu_data *data = per_cpu(cpu_data, policy->cpu);
-       unsigned int cpu;
-
-       of_node_put(data->parent);
-       kfree(data->table);
-       kfree(data);
-
-       for_each_cpu(cpu, per_cpu(cpu_mask, policy->cpu))
-               per_cpu(cpu_data, cpu) = NULL;
-
-       return 0;
-}
-
-static int corenet_cpufreq_target(struct cpufreq_policy *policy,
-               unsigned int index)
-{
-       struct clk *parent;
-       struct cpu_data *data = per_cpu(cpu_data, policy->cpu);
-
-       parent = of_clk_get(data->parent, data->table[index].driver_data);
-       return clk_set_parent(policy->clk, parent);
-}
-
-static struct cpufreq_driver ppc_corenet_cpufreq_driver = {
-       .name           = "ppc_cpufreq",
-       .flags          = CPUFREQ_CONST_LOOPS,
-       .init           = corenet_cpufreq_cpu_init,
-       .exit           = __exit_p(corenet_cpufreq_cpu_exit),
-       .verify         = cpufreq_generic_frequency_table_verify,
-       .target_index   = corenet_cpufreq_target,
-       .get            = cpufreq_generic_get,
-       .attr           = cpufreq_generic_attr,
-};
-
-static const struct of_device_id node_matches[] __initdata = {
-       { .compatible = "fsl,p2041-clockgen", .data = &sdata[0], },
-       { .compatible = "fsl,p3041-clockgen", .data = &sdata[0], },
-       { .compatible = "fsl,p5020-clockgen", .data = &sdata[1], },
-       { .compatible = "fsl,p4080-clockgen", .data = &sdata[2], },
-       { .compatible = "fsl,p5040-clockgen", .data = &sdata[2], },
-       { .compatible = "fsl,qoriq-clockgen-2.0", },
-       {}
-};
-
-static int __init ppc_corenet_cpufreq_init(void)
-{
-       int ret;
-       struct device_node  *np;
-       const struct of_device_id *match;
-       const struct soc_data *data;
-       unsigned int cpu;
-
-       np = of_find_matching_node(NULL, node_matches);
-       if (!np)
-               return -ENODEV;
-
-       for_each_possible_cpu(cpu) {
-               if (!alloc_cpumask_var(&per_cpu(cpu_mask, cpu), GFP_KERNEL))
-                       goto err_mask;
-               cpumask_copy(per_cpu(cpu_mask, cpu), cpu_core_mask(cpu));
-       }
-
-       match = of_match_node(node_matches, np);
-       data = match->data;
-       if (data) {
-               if (data->flag)
-                       fmask = data->freq_mask;
-               min_cpufreq = fsl_get_sys_freq();
-       } else {
-               min_cpufreq = fsl_get_sys_freq() / 2;
-       }
-
-       of_node_put(np);
-
-       ret = cpufreq_register_driver(&ppc_corenet_cpufreq_driver);
-       if (!ret)
-               pr_info("Freescale PowerPC corenet CPU frequency scaling driver\n");
-
-       return ret;
-
-err_mask:
-       for_each_possible_cpu(cpu)
-               free_cpumask_var(per_cpu(cpu_mask, cpu));
-
-       return -ENOMEM;
-}
-module_init(ppc_corenet_cpufreq_init);
-
-static void __exit ppc_corenet_cpufreq_exit(void)
-{
-       unsigned int cpu;
-
-       for_each_possible_cpu(cpu)
-               free_cpumask_var(per_cpu(cpu_mask, cpu));
-
-       cpufreq_unregister_driver(&ppc_corenet_cpufreq_driver);
-}
-module_exit(ppc_corenet_cpufreq_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Tang Yuantian <Yuantian.Tang@freescale.com>");
-MODULE_DESCRIPTION("cpufreq driver for Freescale e500mc series SoCs");
diff --git a/drivers/cpufreq/qoriq-cpufreq.c b/drivers/cpufreq/qoriq-cpufreq.c
new file mode 100644 (file)
index 0000000..88b21ae
--- /dev/null
@@ -0,0 +1,374 @@
+/*
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
+ * CPU Frequency Scaling driver for Freescale QorIQ SoCs.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt)    KBUILD_MODNAME ": " fmt
+
+#include <linux/clk.h>
+#include <linux/cpufreq.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+
+#if !defined(CONFIG_ARM)
+#include <asm/smp.h>   /* for get_hard_smp_processor_id() in UP configs */
+#endif
+
+/**
+ * struct cpu_data
+ * @parent: the parent node of cpu clock
+ * @table: frequency table
+ */
+struct cpu_data {
+       struct device_node *parent;
+       struct cpufreq_frequency_table *table;
+};
+
+/**
+ * struct soc_data - SoC specific data
+ * @freq_mask: mask the disallowed frequencies
+ * @flag: unique flags
+ */
+struct soc_data {
+       u32 freq_mask[4];
+       u32 flag;
+};
+
+#define FREQ_MASK      1
+/* see hardware specification for the allowed frqeuencies */
+static const struct soc_data sdata[] = {
+       { /* used by p2041 and p3041 */
+               .freq_mask = {0x8, 0x8, 0x2, 0x2},
+               .flag = FREQ_MASK,
+       },
+       { /* used by p5020 */
+               .freq_mask = {0x8, 0x2},
+               .flag = FREQ_MASK,
+       },
+       { /* used by p4080, p5040 */
+               .freq_mask = {0},
+               .flag = 0,
+       },
+};
+
+/*
+ * the minimum allowed core frequency, in Hz
+ * for chassis v1.0, >= platform frequency
+ * for chassis v2.0, >= platform frequency / 2
+ */
+static u32 min_cpufreq;
+static const u32 *fmask;
+
+#if defined(CONFIG_ARM)
+static int get_cpu_physical_id(int cpu)
+{
+       return topology_core_id(cpu);
+}
+#else
+static int get_cpu_physical_id(int cpu)
+{
+       return get_hard_smp_processor_id(cpu);
+}
+#endif
+
+static u32 get_bus_freq(void)
+{
+       struct device_node *soc;
+       u32 sysfreq;
+
+       soc = of_find_node_by_type(NULL, "soc");
+       if (!soc)
+               return 0;
+
+       if (of_property_read_u32(soc, "bus-frequency", &sysfreq))
+               sysfreq = 0;
+
+       of_node_put(soc);
+
+       return sysfreq;
+}
+
+static struct device_node *cpu_to_clk_node(int cpu)
+{
+       struct device_node *np, *clk_np;
+
+       if (!cpu_present(cpu))
+               return NULL;
+
+       np = of_get_cpu_node(cpu, NULL);
+       if (!np)
+               return NULL;
+
+       clk_np = of_parse_phandle(np, "clocks", 0);
+       if (!clk_np)
+               return NULL;
+
+       of_node_put(np);
+
+       return clk_np;
+}
+
+/* traverse cpu nodes to get cpu mask of sharing clock wire */
+static void set_affected_cpus(struct cpufreq_policy *policy)
+{
+       struct device_node *np, *clk_np;
+       struct cpumask *dstp = policy->cpus;
+       int i;
+
+       np = cpu_to_clk_node(policy->cpu);
+       if (!np)
+               return;
+
+       for_each_present_cpu(i) {
+               clk_np = cpu_to_clk_node(i);
+               if (!clk_np)
+                       continue;
+
+               if (clk_np == np)
+                       cpumask_set_cpu(i, dstp);
+
+               of_node_put(clk_np);
+       }
+       of_node_put(np);
+}
+
+/* reduce the duplicated frequencies in frequency table */
+static void freq_table_redup(struct cpufreq_frequency_table *freq_table,
+               int count)
+{
+       int i, j;
+
+       for (i = 1; i < count; i++) {
+               for (j = 0; j < i; j++) {
+                       if (freq_table[j].frequency == CPUFREQ_ENTRY_INVALID ||
+                                       freq_table[j].frequency !=
+                                       freq_table[i].frequency)
+                               continue;
+
+                       freq_table[i].frequency = CPUFREQ_ENTRY_INVALID;
+                       break;
+               }
+       }
+}
+
+/* sort the frequencies in frequency table in descenting order */
+static void freq_table_sort(struct cpufreq_frequency_table *freq_table,
+               int count)
+{
+       int i, j, ind;
+       unsigned int freq, max_freq;
+       struct cpufreq_frequency_table table;
+
+       for (i = 0; i < count - 1; i++) {
+               max_freq = freq_table[i].frequency;
+               ind = i;
+               for (j = i + 1; j < count; j++) {
+                       freq = freq_table[j].frequency;
+                       if (freq == CPUFREQ_ENTRY_INVALID ||
+                                       freq <= max_freq)
+                               continue;
+                       ind = j;
+                       max_freq = freq;
+               }
+
+               if (ind != i) {
+                       /* exchange the frequencies */
+                       table.driver_data = freq_table[i].driver_data;
+                       table.frequency = freq_table[i].frequency;
+                       freq_table[i].driver_data = freq_table[ind].driver_data;
+                       freq_table[i].frequency = freq_table[ind].frequency;
+                       freq_table[ind].driver_data = table.driver_data;
+                       freq_table[ind].frequency = table.frequency;
+               }
+       }
+}
+
+static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy)
+{
+       struct device_node *np;
+       int i, count, ret;
+       u32 freq, mask;
+       struct clk *clk;
+       struct cpufreq_frequency_table *table;
+       struct cpu_data *data;
+       unsigned int cpu = policy->cpu;
+       u64 u64temp;
+
+       np = of_get_cpu_node(cpu, NULL);
+       if (!np)
+               return -ENODEV;
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data)
+               goto err_np;
+
+       policy->clk = of_clk_get(np, 0);
+       if (IS_ERR(policy->clk)) {
+               pr_err("%s: no clock information\n", __func__);
+               goto err_nomem2;
+       }
+
+       data->parent = of_parse_phandle(np, "clocks", 0);
+       if (!data->parent) {
+               pr_err("%s: could not get clock information\n", __func__);
+               goto err_nomem2;
+       }
+
+       count = of_property_count_strings(data->parent, "clock-names");
+       table = kcalloc(count + 1, sizeof(*table), GFP_KERNEL);
+       if (!table) {
+               pr_err("%s: no memory\n", __func__);
+               goto err_node;
+       }
+
+       if (fmask)
+               mask = fmask[get_cpu_physical_id(cpu)];
+       else
+               mask = 0x0;
+
+       for (i = 0; i < count; i++) {
+               clk = of_clk_get(data->parent, i);
+               freq = clk_get_rate(clk);
+               /*
+                * the clock is valid if its frequency is not masked
+                * and large than minimum allowed frequency.
+                */
+               if (freq < min_cpufreq || (mask & (1 << i)))
+                       table[i].frequency = CPUFREQ_ENTRY_INVALID;
+               else
+                       table[i].frequency = freq / 1000;
+               table[i].driver_data = i;
+       }
+       freq_table_redup(table, count);
+       freq_table_sort(table, count);
+       table[i].frequency = CPUFREQ_TABLE_END;
+
+       /* set the min and max frequency properly */
+       ret = cpufreq_table_validate_and_show(policy, table);
+       if (ret) {
+               pr_err("invalid frequency table: %d\n", ret);
+               goto err_nomem1;
+       }
+
+       data->table = table;
+
+       /* update ->cpus if we have cluster, no harm if not */
+       set_affected_cpus(policy);
+       policy->driver_data = data;
+
+       /* Minimum transition latency is 12 platform clocks */
+       u64temp = 12ULL * NSEC_PER_SEC;
+       do_div(u64temp, get_bus_freq());
+       policy->cpuinfo.transition_latency = u64temp + 1;
+
+       of_node_put(np);
+
+       return 0;
+
+err_nomem1:
+       kfree(table);
+err_node:
+       of_node_put(data->parent);
+err_nomem2:
+       policy->driver_data = NULL;
+       kfree(data);
+err_np:
+       of_node_put(np);
+
+       return -ENODEV;
+}
+
+static int __exit qoriq_cpufreq_cpu_exit(struct cpufreq_policy *policy)
+{
+       struct cpu_data *data = policy->driver_data;
+
+       of_node_put(data->parent);
+       kfree(data->table);
+       kfree(data);
+       policy->driver_data = NULL;
+
+       return 0;
+}
+
+static int qoriq_cpufreq_target(struct cpufreq_policy *policy,
+               unsigned int index)
+{
+       struct clk *parent;
+       struct cpu_data *data = policy->driver_data;
+
+       parent = of_clk_get(data->parent, data->table[index].driver_data);
+       return clk_set_parent(policy->clk, parent);
+}
+
+static struct cpufreq_driver qoriq_cpufreq_driver = {
+       .name           = "qoriq_cpufreq",
+       .flags          = CPUFREQ_CONST_LOOPS,
+       .init           = qoriq_cpufreq_cpu_init,
+       .exit           = __exit_p(qoriq_cpufreq_cpu_exit),
+       .verify         = cpufreq_generic_frequency_table_verify,
+       .target_index   = qoriq_cpufreq_target,
+       .get            = cpufreq_generic_get,
+       .attr           = cpufreq_generic_attr,
+};
+
+static const struct of_device_id node_matches[] __initconst = {
+       { .compatible = "fsl,p2041-clockgen", .data = &sdata[0], },
+       { .compatible = "fsl,p3041-clockgen", .data = &sdata[0], },
+       { .compatible = "fsl,p5020-clockgen", .data = &sdata[1], },
+       { .compatible = "fsl,p4080-clockgen", .data = &sdata[2], },
+       { .compatible = "fsl,p5040-clockgen", .data = &sdata[2], },
+       { .compatible = "fsl,qoriq-clockgen-2.0", },
+       {}
+};
+
+static int __init qoriq_cpufreq_init(void)
+{
+       int ret;
+       struct device_node  *np;
+       const struct of_device_id *match;
+       const struct soc_data *data;
+
+       np = of_find_matching_node(NULL, node_matches);
+       if (!np)
+               return -ENODEV;
+
+       match = of_match_node(node_matches, np);
+       data = match->data;
+       if (data) {
+               if (data->flag)
+                       fmask = data->freq_mask;
+               min_cpufreq = get_bus_freq();
+       } else {
+               min_cpufreq = get_bus_freq() / 2;
+       }
+
+       of_node_put(np);
+
+       ret = cpufreq_register_driver(&qoriq_cpufreq_driver);
+       if (!ret)
+               pr_info("Freescale QorIQ CPU frequency scaling driver\n");
+
+       return ret;
+}
+module_init(qoriq_cpufreq_init);
+
+static void __exit qoriq_cpufreq_exit(void)
+{
+       cpufreq_unregister_driver(&qoriq_cpufreq_driver);
+}
+module_exit(qoriq_cpufreq_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tang Yuantian <Yuantian.Tang@freescale.com>");
+MODULE_DESCRIPTION("cpufreq driver for Freescale QorIQ series SoCs");
index c5029c1209b4c0bbb6fe52b577345138b788de13..8c7930b5a65fabaa3ae58c8a2224ed056e1fc95f 100644 (file)
@@ -29,15 +29,10 @@ config DT_IDLE_STATES
        bool
 
 menu "ARM CPU Idle Drivers"
-depends on ARM
+depends on ARM || ARM64
 source "drivers/cpuidle/Kconfig.arm"
 endmenu
 
-menu "ARM64 CPU Idle Drivers"
-depends on ARM64
-source "drivers/cpuidle/Kconfig.arm64"
-endmenu
-
 menu "MIPS CPU Idle Drivers"
 depends on MIPS
 source "drivers/cpuidle/Kconfig.mips"
index 8e07c94191539028780754698eaa81692613134e..21340e0be73e7c045dcf878a7ad759713ae026e9 100644 (file)
@@ -1,10 +1,20 @@
 #
 # ARM CPU Idle drivers
 #
+config ARM_CPUIDLE
+        bool "Generic ARM/ARM64 CPU idle Driver"
+        select DT_IDLE_STATES
+        help
+          Select this to enable generic cpuidle driver for ARM.
+          It provides a generic idle driver whose idle states are configured
+          at run-time through DT nodes. The CPUidle suspend backend is
+          initialized by calling the CPU operations init idle hook
+          provided by architecture code.
+
 config ARM_BIG_LITTLE_CPUIDLE
        bool "Support for ARM big.LITTLE processors"
        depends on ARCH_VEXPRESS_TC2_PM || ARCH_EXYNOS
-       depends on MCPM
+       depends on MCPM && !ARM64
        select ARM_CPU_SUSPEND
        select CPU_IDLE_MULTIPLE_DRIVERS
        select DT_IDLE_STATES
@@ -16,51 +26,51 @@ config ARM_BIG_LITTLE_CPUIDLE
 
 config ARM_CLPS711X_CPUIDLE
        bool "CPU Idle Driver for CLPS711X processors"
-       depends on ARCH_CLPS711X || COMPILE_TEST
+       depends on ARCH_CLPS711X && !ARM64 || COMPILE_TEST
        help
          Select this to enable cpuidle on Cirrus Logic CLPS711X SOCs.
 
 config ARM_HIGHBANK_CPUIDLE
        bool "CPU Idle Driver for Calxeda processors"
-       depends on ARM_PSCI
+       depends on ARM_PSCI && !ARM64
        select ARM_CPU_SUSPEND
        help
          Select this to enable cpuidle on Calxeda processors.
 
 config ARM_KIRKWOOD_CPUIDLE
        bool "CPU Idle Driver for Marvell Kirkwood SoCs"
-       depends on MACH_KIRKWOOD
+       depends on MACH_KIRKWOOD && !ARM64
        help
          This adds the CPU Idle driver for Marvell Kirkwood SoCs.
 
 config ARM_ZYNQ_CPUIDLE
        bool "CPU Idle Driver for Xilinx Zynq processors"
-       depends on ARCH_ZYNQ
+       depends on ARCH_ZYNQ && !ARM64
        help
          Select this to enable cpuidle on Xilinx Zynq processors.
 
 config ARM_U8500_CPUIDLE
        bool "Cpu Idle Driver for the ST-E u8500 processors"
-       depends on ARCH_U8500
+       depends on ARCH_U8500 && !ARM64
        help
          Select this to enable cpuidle for ST-E u8500 processors
 
 config ARM_AT91_CPUIDLE
        bool "Cpu Idle Driver for the AT91 processors"
        default y
-       depends on ARCH_AT91
+       depends on ARCH_AT91 && !ARM64
        help
          Select this to enable cpuidle for AT91 processors
 
 config ARM_EXYNOS_CPUIDLE
        bool "Cpu Idle Driver for the Exynos processors"
-       depends on ARCH_EXYNOS
+       depends on ARCH_EXYNOS && !ARM64
        select ARCH_NEEDS_CPU_IDLE_COUPLED if SMP
        help
          Select this to enable cpuidle for Exynos processors
 
 config ARM_MVEBU_V7_CPUIDLE
        bool "CPU Idle Driver for mvebu v7 family processors"
-       depends on ARCH_MVEBU
+       depends on ARCH_MVEBU && !ARM64
        help
          Select this to enable cpuidle on Armada 370, 38x and XP processors.
diff --git a/drivers/cpuidle/Kconfig.arm64 b/drivers/cpuidle/Kconfig.arm64
deleted file mode 100644 (file)
index 6effb36..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#
-# ARM64 CPU Idle drivers
-#
-
-config ARM64_CPUIDLE
-       bool "Generic ARM64 CPU idle Driver"
-       select DT_IDLE_STATES
-       help
-         Select this to enable generic cpuidle driver for ARM64.
-         It provides a generic idle driver whose idle states are configured
-         at run-time through DT nodes. The CPUidle suspend backend is
-         initialized by calling the CPU operations init idle hook
-         provided by architecture code.
index 4d177b916f75224325e0c37991f82d622e8e6392..3ba81b1dffad87db0574f98b7cc4b4a59758891c 100644 (file)
@@ -17,15 +17,12 @@ obj-$(CONFIG_ARM_ZYNQ_CPUIDLE)              += cpuidle-zynq.o
 obj-$(CONFIG_ARM_U8500_CPUIDLE)         += cpuidle-ux500.o
 obj-$(CONFIG_ARM_AT91_CPUIDLE)          += cpuidle-at91.o
 obj-$(CONFIG_ARM_EXYNOS_CPUIDLE)        += cpuidle-exynos.o
+obj-$(CONFIG_ARM_CPUIDLE)              += cpuidle-arm.o
 
 ###############################################################################
 # MIPS drivers
 obj-$(CONFIG_MIPS_CPS_CPUIDLE)         += cpuidle-cps.o
 
-###############################################################################
-# ARM64 drivers
-obj-$(CONFIG_ARM64_CPUIDLE)            += cpuidle-arm64.o
-
 ###############################################################################
 # POWERPC drivers
 obj-$(CONFIG_PSERIES_CPUIDLE)          += cpuidle-pseries.o
diff --git a/drivers/cpuidle/cpuidle-arm.c b/drivers/cpuidle/cpuidle-arm.c
new file mode 100644 (file)
index 0000000..545069d
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * ARM/ARM64 generic CPU idle driver.
+ *
+ * Copyright (C) 2014 ARM Ltd.
+ * Author: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) "CPUidle arm: " fmt
+
+#include <linux/cpuidle.h>
+#include <linux/cpumask.h>
+#include <linux/cpu_pm.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+
+#include <asm/cpuidle.h>
+
+#include "dt_idle_states.h"
+
+/*
+ * arm_enter_idle_state - Programs CPU to enter the specified state
+ *
+ * dev: cpuidle device
+ * drv: cpuidle driver
+ * idx: state index
+ *
+ * Called from the CPUidle framework to program the device to the
+ * specified target state selected by the governor.
+ */
+static int arm_enter_idle_state(struct cpuidle_device *dev,
+                               struct cpuidle_driver *drv, int idx)
+{
+       int ret;
+
+       if (!idx) {
+               cpu_do_idle();
+               return idx;
+       }
+
+       ret = cpu_pm_enter();
+       if (!ret) {
+               /*
+                * Pass idle state index to cpu_suspend which in turn will
+                * call the CPU ops suspend protocol with idle index as a
+                * parameter.
+                */
+               arm_cpuidle_suspend(idx);
+
+               cpu_pm_exit();
+       }
+
+       return ret ? -1 : idx;
+}
+
+static struct cpuidle_driver arm_idle_driver = {
+       .name = "arm_idle",
+       .owner = THIS_MODULE,
+       /*
+        * State at index 0 is standby wfi and considered standard
+        * on all ARM platforms. If in some platforms simple wfi
+        * can't be used as "state 0", DT bindings must be implemented
+        * to work around this issue and allow installing a special
+        * handler for idle state index 0.
+        */
+       .states[0] = {
+               .enter                  = arm_enter_idle_state,
+               .exit_latency           = 1,
+               .target_residency       = 1,
+               .power_usage            = UINT_MAX,
+               .name                   = "WFI",
+               .desc                   = "ARM WFI",
+       }
+};
+
+static const struct of_device_id arm_idle_state_match[] __initconst = {
+       { .compatible = "arm,idle-state",
+         .data = arm_enter_idle_state },
+       { },
+};
+
+/*
+ * arm_idle_init
+ *
+ * Registers the arm specific cpuidle driver with the cpuidle
+ * framework. It relies on core code to parse the idle states
+ * and initialize them using driver data structures accordingly.
+ */
+static int __init arm_idle_init(void)
+{
+       int cpu, ret;
+       struct cpuidle_driver *drv = &arm_idle_driver;
+       struct cpuidle_device *dev;
+
+       /*
+        * Initialize idle states data, starting at index 1.
+        * This driver is DT only, if no DT idle states are detected (ret == 0)
+        * let the driver initialization fail accordingly since there is no
+        * reason to initialize the idle driver if only wfi is supported.
+        */
+       ret = dt_init_idle_driver(drv, arm_idle_state_match, 1);
+       if (ret <= 0)
+               return ret ? : -ENODEV;
+
+       ret = cpuidle_register_driver(drv);
+       if (ret) {
+               pr_err("Failed to register cpuidle driver\n");
+               return ret;
+       }
+
+       /*
+        * Call arch CPU operations in order to initialize
+        * idle states suspend back-end specific data
+        */
+       for_each_possible_cpu(cpu) {
+               ret = arm_cpuidle_init(cpu);
+
+               /*
+                * Skip the cpuidle device initialization if the reported
+                * failure is a HW misconfiguration/breakage (-ENXIO).
+                */
+               if (ret == -ENXIO)
+                       continue;
+
+               if (ret) {
+                       pr_err("CPU %d failed to init idle CPU ops\n", cpu);
+                       goto out_fail;
+               }
+
+               dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+               if (!dev) {
+                       pr_err("Failed to allocate cpuidle device\n");
+                       goto out_fail;
+               }
+               dev->cpu = cpu;
+
+               ret = cpuidle_register_device(dev);
+               if (ret) {
+                       pr_err("Failed to register cpuidle device for CPU %d\n",
+                              cpu);
+                       kfree(dev);
+                       goto out_fail;
+               }
+       }
+
+       return 0;
+out_fail:
+       while (--cpu >= 0) {
+               dev = per_cpu(cpuidle_devices, cpu);
+               cpuidle_unregister_device(dev);
+               kfree(dev);
+       }
+
+       cpuidle_unregister_driver(drv);
+
+       return ret;
+}
+device_initcall(arm_idle_init);
diff --git a/drivers/cpuidle/cpuidle-arm64.c b/drivers/cpuidle/cpuidle-arm64.c
deleted file mode 100644 (file)
index 39a2c62..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * ARM64 generic CPU idle driver.
- *
- * Copyright (C) 2014 ARM Ltd.
- * Author: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#define pr_fmt(fmt) "CPUidle arm64: " fmt
-
-#include <linux/cpuidle.h>
-#include <linux/cpumask.h>
-#include <linux/cpu_pm.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/of.h>
-
-#include <asm/cpuidle.h>
-
-#include "dt_idle_states.h"
-
-/*
- * arm64_enter_idle_state - Programs CPU to enter the specified state
- *
- * dev: cpuidle device
- * drv: cpuidle driver
- * idx: state index
- *
- * Called from the CPUidle framework to program the device to the
- * specified target state selected by the governor.
- */
-static int arm64_enter_idle_state(struct cpuidle_device *dev,
-                                 struct cpuidle_driver *drv, int idx)
-{
-       int ret;
-
-       if (!idx) {
-               cpu_do_idle();
-               return idx;
-       }
-
-       ret = cpu_pm_enter();
-       if (!ret) {
-               /*
-                * Pass idle state index to cpu_suspend which in turn will
-                * call the CPU ops suspend protocol with idle index as a
-                * parameter.
-                */
-               ret = cpu_suspend(idx);
-
-               cpu_pm_exit();
-       }
-
-       return ret ? -1 : idx;
-}
-
-static struct cpuidle_driver arm64_idle_driver = {
-       .name = "arm64_idle",
-       .owner = THIS_MODULE,
-       /*
-        * State at index 0 is standby wfi and considered standard
-        * on all ARM platforms. If in some platforms simple wfi
-        * can't be used as "state 0", DT bindings must be implemented
-        * to work around this issue and allow installing a special
-        * handler for idle state index 0.
-        */
-       .states[0] = {
-               .enter                  = arm64_enter_idle_state,
-               .exit_latency           = 1,
-               .target_residency       = 1,
-               .power_usage            = UINT_MAX,
-               .name                   = "WFI",
-               .desc                   = "ARM64 WFI",
-       }
-};
-
-static const struct of_device_id arm64_idle_state_match[] __initconst = {
-       { .compatible = "arm,idle-state",
-         .data = arm64_enter_idle_state },
-       { },
-};
-
-/*
- * arm64_idle_init
- *
- * Registers the arm64 specific cpuidle driver with the cpuidle
- * framework. It relies on core code to parse the idle states
- * and initialize them using driver data structures accordingly.
- */
-static int __init arm64_idle_init(void)
-{
-       int cpu, ret;
-       struct cpuidle_driver *drv = &arm64_idle_driver;
-
-       /*
-        * Initialize idle states data, starting at index 1.
-        * This driver is DT only, if no DT idle states are detected (ret == 0)
-        * let the driver initialization fail accordingly since there is no
-        * reason to initialize the idle driver if only wfi is supported.
-        */
-       ret = dt_init_idle_driver(drv, arm64_idle_state_match, 1);
-       if (ret <= 0)
-               return ret ? : -ENODEV;
-
-       /*
-        * Call arch CPU operations in order to initialize
-        * idle states suspend back-end specific data
-        */
-       for_each_possible_cpu(cpu) {
-               ret = cpu_init_idle(cpu);
-               if (ret) {
-                       pr_err("CPU %d failed to init idle CPU ops\n", cpu);
-                       return ret;
-               }
-       }
-
-       return cpuidle_register(drv, NULL);
-}
-device_initcall(arm64_idle_init);
index aae7bfc1ea369e0d43607ae35319be6fc6b8dec0..f2446c78d87cf14eda9cec13ab05d9bd0b9198a9 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/cpuidle.h>
 #include <linux/io.h>
 #include <linux/export.h>
-#include <asm/proc-fns.h>
 #include <asm/cpuidle.h>
 
 #define AT91_MAX_STATES        2
index 26f5f29fdb03f8765ed67e22c5e6a97cb222c43d..0c06ea2f50bb906fe44727a534924371b2917c0e 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/of.h>
 #include <linux/platform_data/cpuidle-exynos.h>
 
-#include <asm/proc-fns.h>
 #include <asm/suspend.h>
 #include <asm/cpuidle.h>
 
index cea0a6c4b1db007c09a9819b68cd50212422b11e..d23d8f468c12212136861461cf5ca764c93f5668 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/cpuidle.h>
 #include <linux/io.h>
 #include <linux/export.h>
-#include <asm/proc-fns.h>
 #include <asm/cpuidle.h>
 
 #define KIRKWOOD_MAX_STATES    2
index 66f81e410f0d3b6bc6ce7b3bcb73eaa41cb8d3aa..8bf895c0017df0f7cefbb25d39e4805a7fa21a6a 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/platform_device.h>
 
 #include <asm/cpuidle.h>
-#include <asm/proc-fns.h>
 
 static atomic_t master = ATOMIC_INIT(0);
 static DEFINE_SPINLOCK(master_lock);
index 002b8c9f98f51eb7c663991fcc0b4fe311ce1e71..543292b1d38ea045e9d9504c59d75ba4678a0ce2 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/init.h>
 #include <linux/cpuidle.h>
 #include <linux/platform_device.h>
-#include <asm/proc-fns.h>
 #include <asm/cpuidle.h>
 
 #define ZYNQ_MAX_STATES                2
index 30b538d8cc90a5cb5e6baa88172c5711aa804b93..ca1b362d77e2329c9b6c0d511f754fdf839da095 100644 (file)
@@ -392,7 +392,6 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
 /**
  * _remove_devfreq() - Remove devfreq from the list and release its resources.
  * @devfreq:   the devfreq struct
- * @skip:      skip calling device_unregister().
  */
 static void _remove_devfreq(struct devfreq *devfreq)
 {
index ad8347385f53ba38ab789613c5ce28830c2a9eff..7d99d13bacd8cc2d95d01f4b089ec4e9e419485a 100644 (file)
@@ -194,7 +194,7 @@ static int exynos_ppmu_get_event(struct devfreq_event_dev *edev,
        return 0;
 }
 
-static struct devfreq_event_ops exynos_ppmu_ops = {
+static const struct devfreq_event_ops exynos_ppmu_ops = {
        .disable = exynos_ppmu_disable,
        .set_event = exynos_ppmu_set_event,
        .get_event = exynos_ppmu_get_event,
index 34790961af5a4e855b814767568177c763fb05bd..13a1a6e8108c87e5b8c7653118c1d7798b4c6ac8 100644 (file)
@@ -62,7 +62,8 @@
 #define ACTMON_BELOW_WMARK_WINDOW                              3
 #define ACTMON_BOOST_FREQ_STEP                                 16000
 
-/* activity counter is incremented every 256 memory transactions, and each
+/*
+ * Activity counter is incremented every 256 memory transactions, and each
  * transaction takes 4 EMC clocks for Tegra124; So the COUNT_WEIGHT is
  * 4 * 256 = 1024.
  */
  * struct tegra_devfreq_device_config - configuration specific to an ACTMON
  * device
  *
- * Coefficients and thresholds are in %
+ * Coefficients and thresholds are percentages unless otherwise noted
  */
 struct tegra_devfreq_device_config {
        u32             offset;
        u32             irq_mask;
 
+       /* Factors applied to boost_freq every consecutive watermark breach */
        unsigned int    boost_up_coeff;
        unsigned int    boost_down_coeff;
+
+       /* Define the watermark bounds when applied to the current avg */
        unsigned int    boost_up_threshold;
        unsigned int    boost_down_threshold;
+
+       /*
+        * Threshold of activity (cycles) below which the CPU frequency isn't
+        * to be taken into account. This is to avoid increasing the EMC
+        * frequency when the CPU is very busy but not accessing the bus often.
+        */
        u32             avg_dependency_threshold;
 };
 
@@ -105,7 +115,7 @@ enum tegra_actmon_device {
 
 static struct tegra_devfreq_device_config actmon_device_configs[] = {
        {
-               /* MCALL */
+               /* MCALL: All memory accesses (including from the CPUs) */
                .offset = 0x1c0,
                .irq_mask = 1 << 26,
                .boost_up_coeff = 200,
@@ -114,7 +124,7 @@ static struct tegra_devfreq_device_config actmon_device_configs[] = {
                .boost_down_threshold = 40,
        },
        {
-               /* MCCPU */
+               /* MCCPU: memory accesses from the CPUs */
                .offset = 0x200,
                .irq_mask = 1 << 25,
                .boost_up_coeff = 800,
@@ -132,25 +142,29 @@ static struct tegra_devfreq_device_config actmon_device_configs[] = {
  */
 struct tegra_devfreq_device {
        const struct tegra_devfreq_device_config *config;
+       void __iomem *regs;
+       spinlock_t lock;
+
+       /* Average event count sampled in the last interrupt */
+       u32 avg_count;
 
-       void __iomem    *regs;
-       u32             avg_band_freq;
-       u32             avg_count;
+       /*
+        * Extra frequency to increase the target by due to consecutive
+        * watermark breaches.
+        */
+       unsigned long boost_freq;
 
-       unsigned long   target_freq;
-       unsigned long   boost_freq;
+       /* Optimal frequency calculated from the stats for this device */
+       unsigned long target_freq;
 };
 
 struct tegra_devfreq {
        struct devfreq          *devfreq;
 
-       struct platform_device  *pdev;
        struct reset_control    *reset;
        struct clk              *clock;
        void __iomem            *regs;
 
-       spinlock_t              lock;
-
        struct clk              *emc_clock;
        unsigned long           max_freq;
        unsigned long           cur_freq;
@@ -174,19 +188,43 @@ static struct tegra_actmon_emc_ratio actmon_emc_ratios[] = {
        {  250000,    100000 },
 };
 
+static u32 actmon_readl(struct tegra_devfreq *tegra, u32 offset)
+{
+       return readl(tegra->regs + offset);
+}
+
+static void actmon_writel(struct tegra_devfreq *tegra, u32 val, u32 offset)
+{
+       writel(val, tegra->regs + offset);
+}
+
+static u32 device_readl(struct tegra_devfreq_device *dev, u32 offset)
+{
+       return readl(dev->regs + offset);
+}
+
+static void device_writel(struct tegra_devfreq_device *dev, u32 val,
+                         u32 offset)
+{
+       writel(val, dev->regs + offset);
+}
+
 static unsigned long do_percent(unsigned long val, unsigned int pct)
 {
        return val * pct / 100;
 }
 
-static void tegra_devfreq_update_avg_wmark(struct tegra_devfreq_device *dev)
+static void tegra_devfreq_update_avg_wmark(struct tegra_devfreq *tegra,
+                                          struct tegra_devfreq_device *dev)
 {
        u32 avg = dev->avg_count;
-       u32 band = dev->avg_band_freq * ACTMON_SAMPLING_PERIOD;
+       u32 avg_band_freq = tegra->max_freq * ACTMON_DEFAULT_AVG_BAND / KHZ;
+       u32 band = avg_band_freq * ACTMON_SAMPLING_PERIOD;
+
+       device_writel(dev, avg + band, ACTMON_DEV_AVG_UPPER_WMARK);
 
-       writel(avg + band, dev->regs + ACTMON_DEV_AVG_UPPER_WMARK);
-       avg = max(avg, band);
-       writel(avg - band, dev->regs + ACTMON_DEV_AVG_LOWER_WMARK);
+       avg = max(dev->avg_count, band);
+       device_writel(dev, avg - band, ACTMON_DEV_AVG_LOWER_WMARK);
 }
 
 static void tegra_devfreq_update_wmark(struct tegra_devfreq *tegra,
@@ -194,96 +232,96 @@ static void tegra_devfreq_update_wmark(struct tegra_devfreq *tegra,
 {
        u32 val = tegra->cur_freq * ACTMON_SAMPLING_PERIOD;
 
-       writel(do_percent(val, dev->config->boost_up_threshold),
-              dev->regs + ACTMON_DEV_UPPER_WMARK);
+       device_writel(dev, do_percent(val, dev->config->boost_up_threshold),
+                     ACTMON_DEV_UPPER_WMARK);
 
-       writel(do_percent(val, dev->config->boost_down_threshold),
-              dev->regs + ACTMON_DEV_LOWER_WMARK);
+       device_writel(dev, do_percent(val, dev->config->boost_down_threshold),
+                     ACTMON_DEV_LOWER_WMARK);
 }
 
 static void actmon_write_barrier(struct tegra_devfreq *tegra)
 {
        /* ensure the update has reached the ACTMON */
        wmb();
-       readl(tegra->regs + ACTMON_GLB_STATUS);
+       actmon_readl(tegra, ACTMON_GLB_STATUS);
 }
 
-static irqreturn_t actmon_isr(int irq, void *data)
+static void actmon_isr_device(struct tegra_devfreq *tegra,
+                             struct tegra_devfreq_device *dev)
 {
-       struct tegra_devfreq *tegra = data;
-       struct tegra_devfreq_device *dev = NULL;
        unsigned long flags;
-       u32 val;
-       unsigned int i;
-
-       val = readl(tegra->regs + ACTMON_GLB_STATUS);
-
-       for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) {
-               if (val & tegra->devices[i].config->irq_mask) {
-                       dev = tegra->devices + i;
-                       break;
-               }
-       }
-
-       if (!dev)
-               return IRQ_NONE;
+       u32 intr_status, dev_ctrl;
 
-       spin_lock_irqsave(&tegra->lock, flags);
+       spin_lock_irqsave(&dev->lock, flags);
 
-       dev->avg_count = readl(dev->regs + ACTMON_DEV_AVG_COUNT);
-       tegra_devfreq_update_avg_wmark(dev);
+       dev->avg_count = device_readl(dev, ACTMON_DEV_AVG_COUNT);
+       tegra_devfreq_update_avg_wmark(tegra, dev);
 
-       val = readl(dev->regs + ACTMON_DEV_INTR_STATUS);
-       if (val & ACTMON_DEV_INTR_CONSECUTIVE_UPPER) {
-               val = readl(dev->regs + ACTMON_DEV_CTRL) |
-                       ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN |
-                       ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN;
+       intr_status = device_readl(dev, ACTMON_DEV_INTR_STATUS);
+       dev_ctrl = device_readl(dev, ACTMON_DEV_CTRL);
 
+       if (intr_status & ACTMON_DEV_INTR_CONSECUTIVE_UPPER) {
                /*
                 * new_boost = min(old_boost * up_coef + step, max_freq)
                 */
                dev->boost_freq = do_percent(dev->boost_freq,
                                             dev->config->boost_up_coeff);
                dev->boost_freq += ACTMON_BOOST_FREQ_STEP;
-               if (dev->boost_freq >= tegra->max_freq) {
-                       dev->boost_freq = tegra->max_freq;
-                       val &= ~ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN;
-               }
-               writel(val, dev->regs + ACTMON_DEV_CTRL);
-       } else if (val & ACTMON_DEV_INTR_CONSECUTIVE_LOWER) {
-               val = readl(dev->regs + ACTMON_DEV_CTRL) |
-                       ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN |
-                       ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN;
 
+               dev_ctrl |= ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN;
+
+               if (dev->boost_freq >= tegra->max_freq)
+                       dev->boost_freq = tegra->max_freq;
+               else
+                       dev_ctrl |= ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN;
+       } else if (intr_status & ACTMON_DEV_INTR_CONSECUTIVE_LOWER) {
                /*
                 * new_boost = old_boost * down_coef
                 * or 0 if (old_boost * down_coef < step / 2)
                 */
                dev->boost_freq = do_percent(dev->boost_freq,
                                             dev->config->boost_down_coeff);
-               if (dev->boost_freq < (ACTMON_BOOST_FREQ_STEP >> 1)) {
+
+               dev_ctrl |= ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN;
+
+               if (dev->boost_freq < (ACTMON_BOOST_FREQ_STEP >> 1))
                        dev->boost_freq = 0;
-                       val &= ~ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN;
-               }
-               writel(val, dev->regs + ACTMON_DEV_CTRL);
+               else
+                       dev_ctrl |= ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN;
        }
 
        if (dev->config->avg_dependency_threshold) {
-               val = readl(dev->regs + ACTMON_DEV_CTRL);
                if (dev->avg_count >= dev->config->avg_dependency_threshold)
-                       val |= ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN;
+                       dev_ctrl |= ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN;
                else if (dev->boost_freq == 0)
-                       val &= ~ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN;
-               writel(val, dev->regs + ACTMON_DEV_CTRL);
+                       dev_ctrl &= ~ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN;
        }
 
-       writel(ACTMON_INTR_STATUS_CLEAR, dev->regs + ACTMON_DEV_INTR_STATUS);
+       device_writel(dev, dev_ctrl, ACTMON_DEV_CTRL);
+
+       device_writel(dev, ACTMON_INTR_STATUS_CLEAR, ACTMON_DEV_INTR_STATUS);
 
        actmon_write_barrier(tegra);
 
-       spin_unlock_irqrestore(&tegra->lock, flags);
+       spin_unlock_irqrestore(&dev->lock, flags);
+}
 
-       return IRQ_WAKE_THREAD;
+static irqreturn_t actmon_isr(int irq, void *data)
+{
+       struct tegra_devfreq *tegra = data;
+       bool handled = false;
+       unsigned int i;
+       u32 val;
+
+       val = actmon_readl(tegra, ACTMON_GLB_STATUS);
+       for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) {
+               if (val & tegra->devices[i].config->irq_mask) {
+                       actmon_isr_device(tegra, tegra->devices + i);
+                       handled = true;
+               }
+       }
+
+       return handled ? IRQ_WAKE_THREAD : IRQ_NONE;
 }
 
 static unsigned long actmon_cpu_to_emc_rate(struct tegra_devfreq *tegra,
@@ -317,7 +355,7 @@ static void actmon_update_target(struct tegra_devfreq *tegra,
                static_cpu_emc_freq = actmon_cpu_to_emc_rate(tegra, cpu_freq);
        }
 
-       spin_lock_irqsave(&tegra->lock, flags);
+       spin_lock_irqsave(&dev->lock, flags);
 
        dev->target_freq = dev->avg_count / ACTMON_SAMPLING_PERIOD;
        avg_sustain_coef = 100 * 100 / dev->config->boost_up_threshold;
@@ -327,7 +365,7 @@ static void actmon_update_target(struct tegra_devfreq *tegra,
        if (dev->avg_count >= dev->config->avg_dependency_threshold)
                dev->target_freq = max(dev->target_freq, static_cpu_emc_freq);
 
-       spin_unlock_irqrestore(&tegra->lock, flags);
+       spin_unlock_irqrestore(&dev->lock, flags);
 }
 
 static irqreturn_t actmon_thread_isr(int irq, void *data)
@@ -345,131 +383,110 @@ static int tegra_actmon_rate_notify_cb(struct notifier_block *nb,
                                       unsigned long action, void *ptr)
 {
        struct clk_notifier_data *data = ptr;
-       struct tegra_devfreq *tegra = container_of(nb, struct tegra_devfreq,
-                                                  rate_change_nb);
+       struct tegra_devfreq *tegra;
+       struct tegra_devfreq_device *dev;
        unsigned int i;
        unsigned long flags;
 
-       spin_lock_irqsave(&tegra->lock, flags);
+       if (action != POST_RATE_CHANGE)
+               return NOTIFY_OK;
 
-       switch (action) {
-       case POST_RATE_CHANGE:
-               tegra->cur_freq = data->new_rate / KHZ;
+       tegra = container_of(nb, struct tegra_devfreq, rate_change_nb);
 
-               for (i = 0; i < ARRAY_SIZE(tegra->devices); i++)
-                       tegra_devfreq_update_wmark(tegra, tegra->devices + i);
+       tegra->cur_freq = data->new_rate / KHZ;
 
-               actmon_write_barrier(tegra);
-               break;
-       case PRE_RATE_CHANGE:
-               /* fall through */
-       case ABORT_RATE_CHANGE:
-               break;
-       };
+       for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) {
+               dev = &tegra->devices[i];
 
-       spin_unlock_irqrestore(&tegra->lock, flags);
+               spin_lock_irqsave(&dev->lock, flags);
+               tegra_devfreq_update_wmark(tegra, dev);
+               spin_unlock_irqrestore(&dev->lock, flags);
+       }
+
+       actmon_write_barrier(tegra);
 
        return NOTIFY_OK;
 }
 
-static void tegra_actmon_configure_device(struct tegra_devfreq *tegra,
-                                         struct tegra_devfreq_device *dev)
+static void tegra_actmon_enable_interrupts(struct tegra_devfreq *tegra)
 {
+       struct tegra_devfreq_device *dev;
        u32 val;
+       unsigned int i;
 
-       dev->avg_band_freq = tegra->max_freq * ACTMON_DEFAULT_AVG_BAND / KHZ;
-       dev->target_freq = tegra->cur_freq;
-
-       dev->avg_count = tegra->cur_freq * ACTMON_SAMPLING_PERIOD;
-       writel(dev->avg_count, dev->regs + ACTMON_DEV_INIT_AVG);
-
-       tegra_devfreq_update_avg_wmark(dev);
-       tegra_devfreq_update_wmark(tegra, dev);
-
-       writel(ACTMON_COUNT_WEIGHT, dev->regs + ACTMON_DEV_COUNT_WEIGHT);
-       writel(ACTMON_INTR_STATUS_CLEAR, dev->regs + ACTMON_DEV_INTR_STATUS);
-
-       val = 0;
-       val |= ACTMON_DEV_CTRL_ENB_PERIODIC |
-              ACTMON_DEV_CTRL_AVG_ABOVE_WMARK_EN |
-              ACTMON_DEV_CTRL_AVG_BELOW_WMARK_EN;
-       val |= (ACTMON_AVERAGE_WINDOW_LOG2 - 1)
-               << ACTMON_DEV_CTRL_K_VAL_SHIFT;
-       val |= (ACTMON_BELOW_WMARK_WINDOW - 1)
-               << ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_NUM_SHIFT;
-       val |= (ACTMON_ABOVE_WMARK_WINDOW - 1)
-               << ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_NUM_SHIFT;
-       val |= ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN |
-              ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN;
-
-       writel(val, dev->regs + ACTMON_DEV_CTRL);
+       for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) {
+               dev = &tegra->devices[i];
 
-       actmon_write_barrier(tegra);
+               val = device_readl(dev, ACTMON_DEV_CTRL);
+               val |= ACTMON_DEV_CTRL_AVG_ABOVE_WMARK_EN;
+               val |= ACTMON_DEV_CTRL_AVG_BELOW_WMARK_EN;
+               val |= ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN;
+               val |= ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN;
 
-       val = readl(dev->regs + ACTMON_DEV_CTRL);
-       val |= ACTMON_DEV_CTRL_ENB;
-       writel(val, dev->regs + ACTMON_DEV_CTRL);
+               device_writel(dev, val, ACTMON_DEV_CTRL);
+       }
 
        actmon_write_barrier(tegra);
 }
 
-static int tegra_devfreq_suspend(struct device *dev)
+static void tegra_actmon_disable_interrupts(struct tegra_devfreq *tegra)
 {
-       struct platform_device *pdev;
-       struct tegra_devfreq *tegra;
-       struct tegra_devfreq_device *actmon_dev;
-       unsigned int i;
+       struct tegra_devfreq_device *dev;
        u32 val;
-
-       pdev = container_of(dev, struct platform_device, dev);
-       tegra = platform_get_drvdata(pdev);
+       unsigned int i;
 
        for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) {
-               actmon_dev = &tegra->devices[i];
-
-               val = readl(actmon_dev->regs + ACTMON_DEV_CTRL);
-               val &= ~ACTMON_DEV_CTRL_ENB;
-               writel(val, actmon_dev->regs + ACTMON_DEV_CTRL);
+               dev = &tegra->devices[i];
 
-               writel(ACTMON_INTR_STATUS_CLEAR,
-                      actmon_dev->regs + ACTMON_DEV_INTR_STATUS);
+               val = device_readl(dev, ACTMON_DEV_CTRL);
+               val &= ~ACTMON_DEV_CTRL_AVG_ABOVE_WMARK_EN;
+               val &= ~ACTMON_DEV_CTRL_AVG_BELOW_WMARK_EN;
+               val &= ~ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN;
+               val &= ~ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN;
 
-               actmon_write_barrier(tegra);
+               device_writel(dev, val, ACTMON_DEV_CTRL);
        }
 
-       return 0;
+       actmon_write_barrier(tegra);
 }
 
-static int tegra_devfreq_resume(struct device *dev)
+static void tegra_actmon_configure_device(struct tegra_devfreq *tegra,
+                                         struct tegra_devfreq_device *dev)
 {
-       struct platform_device *pdev;
-       struct tegra_devfreq *tegra;
-       struct tegra_devfreq_device *actmon_dev;
-       unsigned int i;
+       u32 val = 0;
 
-       pdev = container_of(dev, struct platform_device, dev);
-       tegra = platform_get_drvdata(pdev);
+       dev->target_freq = tegra->cur_freq;
 
-       for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) {
-               actmon_dev = &tegra->devices[i];
+       dev->avg_count = tegra->cur_freq * ACTMON_SAMPLING_PERIOD;
+       device_writel(dev, dev->avg_count, ACTMON_DEV_INIT_AVG);
 
-               tegra_actmon_configure_device(tegra, actmon_dev);
-       }
+       tegra_devfreq_update_avg_wmark(tegra, dev);
+       tegra_devfreq_update_wmark(tegra, dev);
 
-       return 0;
+       device_writel(dev, ACTMON_COUNT_WEIGHT, ACTMON_DEV_COUNT_WEIGHT);
+       device_writel(dev, ACTMON_INTR_STATUS_CLEAR, ACTMON_DEV_INTR_STATUS);
+
+       val |= ACTMON_DEV_CTRL_ENB_PERIODIC;
+       val |= (ACTMON_AVERAGE_WINDOW_LOG2 - 1)
+               << ACTMON_DEV_CTRL_K_VAL_SHIFT;
+       val |= (ACTMON_BELOW_WMARK_WINDOW - 1)
+               << ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_NUM_SHIFT;
+       val |= (ACTMON_ABOVE_WMARK_WINDOW - 1)
+               << ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_NUM_SHIFT;
+       val |= ACTMON_DEV_CTRL_ENB;
+
+       device_writel(dev, val, ACTMON_DEV_CTRL);
+
+       actmon_write_barrier(tegra);
 }
 
 static int tegra_devfreq_target(struct device *dev, unsigned long *freq,
                                u32 flags)
 {
-       struct platform_device *pdev;
-       struct tegra_devfreq *tegra;
+       struct tegra_devfreq *tegra = dev_get_drvdata(dev);
        struct dev_pm_opp *opp;
        unsigned long rate = *freq * KHZ;
 
-       pdev = container_of(dev, struct platform_device, dev);
-       tegra = platform_get_drvdata(pdev);
-
        rcu_read_lock();
        opp = devfreq_recommended_opp(dev, &rate, flags);
        if (IS_ERR(opp)) {
@@ -480,10 +497,8 @@ static int tegra_devfreq_target(struct device *dev, unsigned long *freq,
        rate = dev_pm_opp_get_freq(opp);
        rcu_read_unlock();
 
-       /* TODO: Once we have per-user clk constraints, set a floor */
-       clk_set_rate(tegra->emc_clock, rate);
-
-       /* TODO: Set voltage as well */
+       clk_set_min_rate(tegra->emc_clock, rate);
+       clk_set_rate(tegra->emc_clock, 0);
 
        return 0;
 }
@@ -491,13 +506,9 @@ static int tegra_devfreq_target(struct device *dev, unsigned long *freq,
 static int tegra_devfreq_get_dev_status(struct device *dev,
                                        struct devfreq_dev_status *stat)
 {
-       struct platform_device *pdev;
-       struct tegra_devfreq *tegra;
+       struct tegra_devfreq *tegra = dev_get_drvdata(dev);
        struct tegra_devfreq_device *actmon_dev;
 
-       pdev = container_of(dev, struct platform_device, dev);
-       tegra = platform_get_drvdata(pdev);
-
        stat->current_frequency = tegra->cur_freq;
 
        /* To be used by the tegra governor */
@@ -508,7 +519,7 @@ static int tegra_devfreq_get_dev_status(struct device *dev,
        actmon_dev = &tegra->devices[MCALL];
 
        /* Number of cycles spent on memory access */
-       stat->busy_time = actmon_dev->avg_count;
+       stat->busy_time = device_readl(actmon_dev, ACTMON_DEV_AVG_COUNT);
 
        /* The bus can be considered to be saturated way before 100% */
        stat->busy_time *= 100 / BUS_SATURATION_RATIO;
@@ -516,11 +527,19 @@ static int tegra_devfreq_get_dev_status(struct device *dev,
        /* Number of cycles in a sampling period */
        stat->total_time = ACTMON_SAMPLING_PERIOD * tegra->cur_freq;
 
+       stat->busy_time = min(stat->busy_time, stat->total_time);
+
        return 0;
 }
 
-static int tegra_devfreq_get_target(struct devfreq *devfreq,
-                                   unsigned long *freq)
+static struct devfreq_dev_profile tegra_devfreq_profile = {
+       .polling_ms     = 0,
+       .target         = tegra_devfreq_target,
+       .get_dev_status = tegra_devfreq_get_dev_status,
+};
+
+static int tegra_governor_get_target(struct devfreq *devfreq,
+                                    unsigned long *freq)
 {
        struct devfreq_dev_status stat;
        struct tegra_devfreq *tegra;
@@ -548,22 +567,43 @@ static int tegra_devfreq_get_target(struct devfreq *devfreq,
        return 0;
 }
 
-static int tegra_devfreq_event_handler(struct devfreq *devfreq,
-                                      unsigned int event, void *data)
+static int tegra_governor_event_handler(struct devfreq *devfreq,
+                                       unsigned int event, void *data)
 {
-       return 0;
+       struct tegra_devfreq *tegra;
+       int ret = 0;
+
+       tegra = dev_get_drvdata(devfreq->dev.parent);
+
+       switch (event) {
+       case DEVFREQ_GOV_START:
+               devfreq_monitor_start(devfreq);
+               tegra_actmon_enable_interrupts(tegra);
+               break;
+
+       case DEVFREQ_GOV_STOP:
+               tegra_actmon_disable_interrupts(tegra);
+               devfreq_monitor_stop(devfreq);
+               break;
+
+       case DEVFREQ_GOV_SUSPEND:
+               tegra_actmon_disable_interrupts(tegra);
+               devfreq_monitor_suspend(devfreq);
+               break;
+
+       case DEVFREQ_GOV_RESUME:
+               devfreq_monitor_resume(devfreq);
+               tegra_actmon_enable_interrupts(tegra);
+               break;
+       }
+
+       return ret;
 }
 
 static struct devfreq_governor tegra_devfreq_governor = {
-       .name = "tegra",
-       .get_target_freq = tegra_devfreq_get_target,
-       .event_handler = tegra_devfreq_event_handler,
-};
-
-static struct devfreq_dev_profile tegra_devfreq_profile = {
-       .polling_ms     = 0,
-       .target         = tegra_devfreq_target,
-       .get_dev_status = tegra_devfreq_get_dev_status,
+       .name = "tegra_actmon",
+       .get_target_freq = tegra_governor_get_target,
+       .event_handler = tegra_governor_event_handler,
 };
 
 static int tegra_devfreq_probe(struct platform_device *pdev)
@@ -571,8 +611,8 @@ static int tegra_devfreq_probe(struct platform_device *pdev)
        struct tegra_devfreq *tegra;
        struct tegra_devfreq_device *dev;
        struct resource *res;
-       unsigned long max_freq;
        unsigned int i;
+       unsigned long rate;
        int irq;
        int err;
 
@@ -580,19 +620,11 @@ static int tegra_devfreq_probe(struct platform_device *pdev)
        if (!tegra)
                return -ENOMEM;
 
-       spin_lock_init(&tegra->lock);
-
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "Failed to get regs resource\n");
-               return -ENODEV;
-       }
 
        tegra->regs = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(tegra->regs)) {
-               dev_err(&pdev->dev, "Failed to get IO memory\n");
+       if (IS_ERR(tegra->regs))
                return PTR_ERR(tegra->regs);
-       }
 
        tegra->reset = devm_reset_control_get(&pdev->dev, "actmon");
        if (IS_ERR(tegra->reset)) {
@@ -612,11 +644,7 @@ static int tegra_devfreq_probe(struct platform_device *pdev)
                return PTR_ERR(tegra->emc_clock);
        }
 
-       err = of_init_opp_table(&pdev->dev);
-       if (err) {
-               dev_err(&pdev->dev, "Failed to init operating point table\n");
-               return err;
-       }
+       clk_set_rate(tegra->emc_clock, ULONG_MAX);
 
        tegra->rate_change_nb.notifier_call = tegra_actmon_rate_notify_cb;
        err = clk_notifier_register(tegra->emc_clock, &tegra->rate_change_nb);
@@ -630,43 +658,41 @@ static int tegra_devfreq_probe(struct platform_device *pdev)
 
        err = clk_prepare_enable(tegra->clock);
        if (err) {
-               reset_control_deassert(tegra->reset);
+               dev_err(&pdev->dev,
+                       "Failed to prepare and enable ACTMON clock\n");
                return err;
        }
 
        reset_control_deassert(tegra->reset);
 
-       max_freq = clk_round_rate(tegra->emc_clock, ULONG_MAX);
-       tegra->max_freq = max_freq / KHZ;
-
-       clk_set_rate(tegra->emc_clock, max_freq);
-
+       tegra->max_freq = clk_round_rate(tegra->emc_clock, ULONG_MAX) / KHZ;
        tegra->cur_freq = clk_get_rate(tegra->emc_clock) / KHZ;
 
-       writel(ACTMON_SAMPLING_PERIOD - 1,
-              tegra->regs + ACTMON_GLB_PERIOD_CTRL);
+       actmon_writel(tegra, ACTMON_SAMPLING_PERIOD - 1,
+                     ACTMON_GLB_PERIOD_CTRL);
 
        for (i = 0; i < ARRAY_SIZE(actmon_device_configs); i++) {
                dev = tegra->devices + i;
                dev->config = actmon_device_configs + i;
                dev->regs = tegra->regs + dev->config->offset;
+               spin_lock_init(&dev->lock);
 
-               tegra_actmon_configure_device(tegra, tegra->devices + i);
+               tegra_actmon_configure_device(tegra, dev);
        }
 
-       err = devfreq_add_governor(&tegra_devfreq_governor);
-       if (err) {
-               dev_err(&pdev->dev, "Failed to add governor\n");
-               return err;
+       for (rate = 0; rate <= tegra->max_freq * KHZ; rate++) {
+               rate = clk_round_rate(tegra->emc_clock, rate);
+               dev_pm_opp_add(&pdev->dev, rate, 0);
        }
 
-       tegra_devfreq_profile.initial_freq = clk_get_rate(tegra->emc_clock);
-       tegra->devfreq = devm_devfreq_add_device(&pdev->dev,
-                                                &tegra_devfreq_profile,
-                                                "tegra",
-                                                NULL);
-
        irq = platform_get_irq(pdev, 0);
+       if (irq <= 0) {
+               dev_err(&pdev->dev, "Failed to get IRQ\n");
+               return -ENODEV;
+       }
+
+       platform_set_drvdata(pdev, tegra);
+
        err = devm_request_threaded_irq(&pdev->dev, irq, actmon_isr,
                                        actmon_thread_isr, IRQF_SHARED,
                                        "tegra-devfreq", tegra);
@@ -675,7 +701,11 @@ static int tegra_devfreq_probe(struct platform_device *pdev)
                return err;
        }
 
-       platform_set_drvdata(pdev, tegra);
+       tegra_devfreq_profile.initial_freq = clk_get_rate(tegra->emc_clock);
+       tegra->devfreq = devm_devfreq_add_device(&pdev->dev,
+                                                &tegra_devfreq_profile,
+                                                "tegra_actmon",
+                                                NULL);
 
        return 0;
 }
@@ -683,6 +713,19 @@ static int tegra_devfreq_probe(struct platform_device *pdev)
 static int tegra_devfreq_remove(struct platform_device *pdev)
 {
        struct tegra_devfreq *tegra = platform_get_drvdata(pdev);
+       int irq = platform_get_irq(pdev, 0);
+       u32 val;
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(actmon_device_configs); i++) {
+               val = device_readl(&tegra->devices[i], ACTMON_DEV_CTRL);
+               val &= ~ACTMON_DEV_CTRL_ENB;
+               device_writel(&tegra->devices[i], val, ACTMON_DEV_CTRL);
+       }
+
+       actmon_write_barrier(tegra);
+
+       devm_free_irq(&pdev->dev, irq, tegra);
 
        clk_notifier_unregister(tegra->emc_clock, &tegra->rate_change_nb);
 
@@ -691,28 +734,52 @@ static int tegra_devfreq_remove(struct platform_device *pdev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(tegra_devfreq_pm_ops,
-                        tegra_devfreq_suspend,
-                        tegra_devfreq_resume);
-
-static struct of_device_id tegra_devfreq_of_match[] = {
+static const struct of_device_id tegra_devfreq_of_match[] = {
        { .compatible = "nvidia,tegra124-actmon" },
        { },
 };
 
+MODULE_DEVICE_TABLE(of, tegra_devfreq_of_match);
+
 static struct platform_driver tegra_devfreq_driver = {
        .probe  = tegra_devfreq_probe,
        .remove = tegra_devfreq_remove,
        .driver = {
-               .name           = "tegra-devfreq",
-               .owner          = THIS_MODULE,
+               .name = "tegra-devfreq",
                .of_match_table = tegra_devfreq_of_match,
-               .pm             = &tegra_devfreq_pm_ops,
        },
 };
-module_platform_driver(tegra_devfreq_driver);
 
-MODULE_LICENSE("GPL");
+static int __init tegra_devfreq_init(void)
+{
+       int ret = 0;
+
+       ret = devfreq_add_governor(&tegra_devfreq_governor);
+       if (ret) {
+               pr_err("%s: failed to add governor: %d\n", __func__, ret);
+               return ret;
+       }
+
+       ret = platform_driver_register(&tegra_devfreq_driver);
+       if (ret)
+               devfreq_remove_governor(&tegra_devfreq_governor);
+
+       return ret;
+}
+module_init(tegra_devfreq_init)
+
+static void __exit tegra_devfreq_exit(void)
+{
+       int ret = 0;
+
+       platform_driver_unregister(&tegra_devfreq_driver);
+
+       ret = devfreq_remove_governor(&tegra_devfreq_governor);
+       if (ret)
+               pr_err("%s: failed to remove governor: %d\n", __func__, ret);
+}
+module_exit(tegra_devfreq_exit)
+
+MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Tegra devfreq driver");
 MODULE_AUTHOR("Tomeu Vizoso <tomeu.vizoso@collabora.com>");
-MODULE_DEVICE_TABLE(of, tegra_devfreq_of_match);
index 550a5eafbd38ce6f1ed5a1d9a899649df75b2fa0..ab892be26dc21005e22e42f00221f647bb2e2923 100644 (file)
@@ -17,6 +17,8 @@
 
 enum of_gpio_flags;
 
+struct acpi_device;
+
 /**
  * struct acpi_gpio_info - ACPI GPIO specific information
  * @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo
index fa4e2b521f0d6f7b77951cf442aaa307a1b66109..0a80e4aabaed9783b74c9d0d157a3d38178945e7 100644 (file)
@@ -164,7 +164,7 @@ static int dw_i2c_probe(struct platform_device *pdev)
        /* fast mode by default because of legacy reasons */
        clk_freq = 400000;
 
-       if (ACPI_COMPANION(&pdev->dev)) {
+       if (has_acpi_companion(&pdev->dev)) {
                dw_i2c_acpi_configure(pdev);
        } else if (pdev->dev.of_node) {
                of_property_read_u32(pdev->dev.of_node,
@@ -284,7 +284,7 @@ static int dw_i2c_remove(struct platform_device *pdev)
        pm_runtime_put(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
 
-       if (ACPI_COMPANION(&pdev->dev))
+       if (has_acpi_companion(&pdev->dev))
                dw_i2c_acpi_unconfigure(pdev);
 
        return 0;
index 68f687733379e5b06aeef3ac37fed7359d3fd397..1672e6b127747d5adc266e5a5d13e68ad53b03b7 100644 (file)
@@ -133,7 +133,7 @@ static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level,
                return AE_OK;
 
        memset(&info, 0, sizeof(info));
-       info.acpi_node.companion = adev;
+       info.fwnode = acpi_fwnode_handle(adev);
        info.irq = -1;
 
        INIT_LIST_HEAD(&resource_list);
@@ -971,7 +971,7 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
        client->dev.bus = &i2c_bus_type;
        client->dev.type = &i2c_client_type;
        client->dev.of_node = info->of_node;
-       ACPI_COMPANION_SET(&client->dev, info->acpi_node.companion);
+       client->dev.fwnode = info->fwnode;
 
        i2c_dev_set_name(adap, client);
        status = device_register(&client->dev);
index e5f3db8313733ce8ce9b682cc7b63dc3e5558d38..f5f2b62471da919e4ffd859b8a96ae738d38cea8 100644 (file)
@@ -96,17 +96,5 @@ static struct pnp_driver idepnp_driver = {
        .remove         = idepnp_remove,
 };
 
-static int __init pnpide_init(void)
-{
-       return pnp_register_driver(&idepnp_driver);
-}
-
-static void __exit pnpide_exit(void)
-{
-       pnp_unregister_driver(&idepnp_driver);
-}
-
-module_init(pnpide_init);
-module_exit(pnpide_exit);
-
+module_pnp_driver(idepnp_driver);
 MODULE_LICENSE("GPL");
index 5c979d0667a2210d2d73873e8766d07ea0facb22..2a36a95d95cfa0ccba47924a69c00b3ce58de017 100644 (file)
@@ -217,19 +217,11 @@ static struct cpuidle_state byt_cstates[] = {
                .target_residency = 1,
                .enter = &intel_idle,
                .enter_freeze = intel_idle_freeze, },
-       {
-               .name = "C1E-BYT",
-               .desc = "MWAIT 0x01",
-               .flags = MWAIT2flg(0x01),
-               .exit_latency = 15,
-               .target_residency = 30,
-               .enter = &intel_idle,
-               .enter_freeze = intel_idle_freeze, },
        {
                .name = "C6N-BYT",
                .desc = "MWAIT 0x58",
                .flags = MWAIT2flg(0x58) | CPUIDLE_FLAG_TLB_FLUSHED,
-               .exit_latency = 40,
+               .exit_latency = 300,
                .target_residency = 275,
                .enter = &intel_idle,
                .enter_freeze = intel_idle_freeze, },
@@ -237,7 +229,7 @@ static struct cpuidle_state byt_cstates[] = {
                .name = "C6S-BYT",
                .desc = "MWAIT 0x52",
                .flags = MWAIT2flg(0x52) | CPUIDLE_FLAG_TLB_FLUSHED,
-               .exit_latency = 140,
+               .exit_latency = 500,
                .target_residency = 560,
                .enter = &intel_idle,
                .enter_freeze = intel_idle_freeze, },
@@ -246,7 +238,7 @@ static struct cpuidle_state byt_cstates[] = {
                .desc = "MWAIT 0x60",
                .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED,
                .exit_latency = 1200,
-               .target_residency = 1500,
+               .target_residency = 4000,
                .enter = &intel_idle,
                .enter_freeze = intel_idle_freeze, },
        {
@@ -261,6 +253,51 @@ static struct cpuidle_state byt_cstates[] = {
                .enter = NULL }
 };
 
+static struct cpuidle_state cht_cstates[] = {
+       {
+               .name = "C1-CHT",
+               .desc = "MWAIT 0x00",
+               .flags = MWAIT2flg(0x00),
+               .exit_latency = 1,
+               .target_residency = 1,
+               .enter = &intel_idle,
+               .enter_freeze = intel_idle_freeze, },
+       {
+               .name = "C6N-CHT",
+               .desc = "MWAIT 0x58",
+               .flags = MWAIT2flg(0x58) | CPUIDLE_FLAG_TLB_FLUSHED,
+               .exit_latency = 80,
+               .target_residency = 275,
+               .enter = &intel_idle,
+               .enter_freeze = intel_idle_freeze, },
+       {
+               .name = "C6S-CHT",
+               .desc = "MWAIT 0x52",
+               .flags = MWAIT2flg(0x52) | CPUIDLE_FLAG_TLB_FLUSHED,
+               .exit_latency = 200,
+               .target_residency = 560,
+               .enter = &intel_idle,
+               .enter_freeze = intel_idle_freeze, },
+       {
+               .name = "C7-CHT",
+               .desc = "MWAIT 0x60",
+               .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED,
+               .exit_latency = 1200,
+               .target_residency = 4000,
+               .enter = &intel_idle,
+               .enter_freeze = intel_idle_freeze, },
+       {
+               .name = "C7S-CHT",
+               .desc = "MWAIT 0x64",
+               .flags = MWAIT2flg(0x64) | CPUIDLE_FLAG_TLB_FLUSHED,
+               .exit_latency = 10000,
+               .target_residency = 20000,
+               .enter = &intel_idle,
+               .enter_freeze = intel_idle_freeze, },
+       {
+               .enter = NULL }
+};
+
 static struct cpuidle_state ivb_cstates[] = {
        {
                .name = "C1-IVB",
@@ -747,6 +784,12 @@ static const struct idle_cpu idle_cpu_byt = {
        .byt_auto_demotion_disable_flag = true,
 };
 
+static const struct idle_cpu idle_cpu_cht = {
+       .state_table = cht_cstates,
+       .disable_promotion_to_c1e = true,
+       .byt_auto_demotion_disable_flag = true,
+};
+
 static const struct idle_cpu idle_cpu_ivb = {
        .state_table = ivb_cstates,
        .disable_promotion_to_c1e = true,
@@ -775,7 +818,7 @@ static const struct idle_cpu idle_cpu_avn = {
 #define ICPU(model, cpu) \
        { X86_VENDOR_INTEL, 6, model, X86_FEATURE_MWAIT, (unsigned long)&cpu }
 
-static const struct x86_cpu_id intel_idle_ids[] = {
+static const struct x86_cpu_id intel_idle_ids[] __initconst = {
        ICPU(0x1a, idle_cpu_nehalem),
        ICPU(0x1e, idle_cpu_nehalem),
        ICPU(0x1f, idle_cpu_nehalem),
@@ -789,6 +832,7 @@ static const struct x86_cpu_id intel_idle_ids[] = {
        ICPU(0x2d, idle_cpu_snb),
        ICPU(0x36, idle_cpu_atom),
        ICPU(0x37, idle_cpu_byt),
+       ICPU(0x4c, idle_cpu_cht),
        ICPU(0x3a, idle_cpu_ivb),
        ICPU(0x3e, idle_cpu_ivt),
        ICPU(0x3c, idle_cpu_hsw),
index 2d1e05bdbb53f5901035294a71c65231b004a338..4fc1f8a7f98e455dc8741a0895c8f279972dee16 100644 (file)
@@ -684,7 +684,7 @@ static struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devf
        if (dev_is_pci(dev)) {
                pdev = to_pci_dev(dev);
                segment = pci_domain_nr(pdev->bus);
-       } else if (ACPI_COMPANION(dev))
+       } else if (has_acpi_companion(dev))
                dev = &ACPI_COMPANION(dev)->dev;
 
        rcu_read_lock();
index e80f2c6c5f1abf040428f4f6c14666de271ee016..8d77e1c4a141e54cc860bc35f0ef2a12f0390a0f 100644 (file)
@@ -1195,16 +1195,6 @@ static struct pnp_driver ene_driver = {
        .shutdown = ene_shutdown,
 };
 
-static int __init ene_init(void)
-{
-       return pnp_register_driver(&ene_driver);
-}
-
-static void ene_exit(void)
-{
-       pnp_unregister_driver(&ene_driver);
-}
-
 module_param(sample_period, int, S_IRUGO);
 MODULE_PARM_DESC(sample_period, "Hardware sample period (50 us default)");
 
@@ -1226,5 +1216,4 @@ MODULE_DESCRIPTION
 MODULE_AUTHOR("Maxim Levitsky");
 MODULE_LICENSE("GPL");
 
-module_init(ene_init);
-module_exit(ene_exit);
+module_pnp_driver(ene_driver);
index b5167573240e3631cd8d3ae74ccc6ec1893eed08..5c63c2ec6183a57b966db39b32a3ad0e7531952e 100644 (file)
@@ -684,16 +684,6 @@ static struct pnp_driver fintek_driver = {
        .shutdown       = fintek_shutdown,
 };
 
-static int __init fintek_init(void)
-{
-       return pnp_register_driver(&fintek_driver);
-}
-
-static void __exit fintek_exit(void)
-{
-       pnp_unregister_driver(&fintek_driver);
-}
-
 module_param(debug, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Enable debugging output");
 
@@ -703,5 +693,4 @@ MODULE_DESCRIPTION(FINTEK_DESCRIPTION " driver");
 MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
 MODULE_LICENSE("GPL");
 
-module_init(fintek_init);
-module_exit(fintek_exit);
+module_pnp_driver(fintek_driver);
index 56abf9120cc27491d20857958fa10b1111ce573e..0f301903aa6ffd43209c2b03854c2c8bef87d368 100644 (file)
@@ -1708,21 +1708,10 @@ static struct pnp_driver ite_driver = {
        .shutdown       = ite_shutdown,
 };
 
-static int __init ite_init(void)
-{
-       return pnp_register_driver(&ite_driver);
-}
-
-static void __exit ite_exit(void)
-{
-       pnp_unregister_driver(&ite_driver);
-}
-
 MODULE_DEVICE_TABLE(pnp, ite_ids);
 MODULE_DESCRIPTION("ITE Tech Inc. IT8712F/ITE8512F CIR driver");
 
 MODULE_AUTHOR("Juan J. Garcia de Soria <skandalfo@gmail.com>");
 MODULE_LICENSE("GPL");
 
-module_init(ite_init);
-module_exit(ite_exit);
+module_pnp_driver(ite_driver);
index 9c2c8635ff3326841178f8f04d65466886424e8b..85af7a8691677a9b3965f469f37bc49b741de6b7 100644 (file)
@@ -1219,16 +1219,6 @@ static struct pnp_driver nvt_driver = {
        .shutdown       = nvt_shutdown,
 };
 
-static int __init nvt_init(void)
-{
-       return pnp_register_driver(&nvt_driver);
-}
-
-static void __exit nvt_exit(void)
-{
-       pnp_unregister_driver(&nvt_driver);
-}
-
 module_param(debug, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Enable debugging output");
 
@@ -1238,5 +1228,4 @@ MODULE_DESCRIPTION("Nuvoton W83667HG-A & W83677HG-I CIR driver");
 MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
 MODULE_LICENSE("GPL");
 
-module_init(nvt_init);
-module_exit(nvt_exit);
+module_pnp_driver(nvt_driver);
index 66c2f1a01963c27f9e7b3f1e50e01c964e0429e2..aad0b59d41e304c6481c0b58e04afd1db2b51918 100644 (file)
@@ -1175,17 +1175,4 @@ MODULE_AUTHOR("Franco Venturi <fventuri@mediaone.net>");
 MODULE_DESCRIPTION("General Instruments SB1000 driver");
 MODULE_LICENSE("GPL");
 
-static int __init
-sb1000_init(void)
-{
-       return pnp_register_driver(&sb1000_driver);
-}
-
-static void __exit
-sb1000_exit(void)
-{
-       pnp_unregister_driver(&sb1000_driver);
-}
-
-module_init(sb1000_init);
-module_exit(sb1000_exit);
+module_pnp_driver(sb1000_driver);
index b9429fbf1cd82a403c65bddd09acc6e11078b66a..66d6d22c239c2b2231ca6837bc36d4cd89a9edb7 100644 (file)
@@ -624,19 +624,7 @@ static struct pnp_driver gmux_pnp_driver = {
        },
 };
 
-static int __init apple_gmux_init(void)
-{
-       return pnp_register_driver(&gmux_pnp_driver);
-}
-
-static void __exit apple_gmux_exit(void)
-{
-       pnp_unregister_driver(&gmux_pnp_driver);
-}
-
-module_init(apple_gmux_init);
-module_exit(apple_gmux_exit);
-
+module_pnp_driver(gmux_pnp_driver);
 MODULE_AUTHOR("Seth Forshee <seth.forshee@canonical.com>");
 MODULE_DESCRIPTION("Apple Gmux Driver");
 MODULE_LICENSE("GPL");
index c8873b0ca551d9fc93add48ae212e7bbf3ef7662..3151fd16461497f7f6eeba816994add2b04e2e24 100644 (file)
@@ -3,7 +3,7 @@
  *     Bjorn Helgaas <bjorn.helgaas@hp.com>
  */
 
-extern spinlock_t pnp_lock;
+extern struct mutex pnp_lock;
 extern const struct attribute_group *pnp_dev_groups[];
 void *pnp_alloc(long size);
 
index 874c236ac1a7abd4a3200008ce8242f759f67c2f..31ad9fc3f701a3e8ed7b0c37c916c5f98f07248a 100644 (file)
@@ -5,6 +5,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/ctype.h>
 #include <linux/slab.h>
 #include <linux/pnp.h>
@@ -244,10 +245,10 @@ int pnp_add_card(struct pnp_card *card)
        }
 
        pnp_interface_attach_card(card);
-       spin_lock(&pnp_lock);
+       mutex_lock(&pnp_lock);
        list_add_tail(&card->global_list, &pnp_cards);
        list_add_tail(&card->protocol_list, &card->protocol->cards);
-       spin_unlock(&pnp_lock);
+       mutex_unlock(&pnp_lock);
 
        /* we wait until now to add devices in order to ensure the drivers
         * will be able to use all of the related devices on the card
@@ -276,10 +277,10 @@ void pnp_remove_card(struct pnp_card *card)
        struct list_head *pos, *temp;
 
        device_unregister(&card->dev);
-       spin_lock(&pnp_lock);
+       mutex_lock(&pnp_lock);
        list_del(&card->global_list);
        list_del(&card->protocol_list);
-       spin_unlock(&pnp_lock);
+       mutex_unlock(&pnp_lock);
        list_for_each_safe(pos, temp, &card->devices) {
                struct pnp_dev *dev = card_to_pnp_dev(pos);
                pnp_remove_card_device(dev);
@@ -297,10 +298,10 @@ int pnp_add_card_device(struct pnp_card *card, struct pnp_dev *dev)
        dev->card_link = NULL;
        dev_set_name(&dev->dev, "%02x:%02x.%02x",
                     dev->protocol->number, card->number, dev->number);
-       spin_lock(&pnp_lock);
+       mutex_lock(&pnp_lock);
        dev->card = card;
        list_add_tail(&dev->card_list, &card->devices);
-       spin_unlock(&pnp_lock);
+       mutex_unlock(&pnp_lock);
        return 0;
 }
 
@@ -310,10 +311,10 @@ int pnp_add_card_device(struct pnp_card *card, struct pnp_dev *dev)
  */
 void pnp_remove_card_device(struct pnp_dev *dev)
 {
-       spin_lock(&pnp_lock);
+       mutex_lock(&pnp_lock);
        dev->card = NULL;
        list_del(&dev->card_list);
-       spin_unlock(&pnp_lock);
+       mutex_unlock(&pnp_lock);
        __pnp_remove_device(dev);
 }
 
@@ -426,9 +427,9 @@ int pnp_register_card_driver(struct pnp_card_driver *drv)
        if (error < 0)
                return error;
 
-       spin_lock(&pnp_lock);
+       mutex_lock(&pnp_lock);
        list_add_tail(&drv->global_list, &pnp_card_drivers);
-       spin_unlock(&pnp_lock);
+       mutex_unlock(&pnp_lock);
 
        list_for_each_safe(pos, temp, &pnp_cards) {
                struct pnp_card *card =
@@ -444,9 +445,9 @@ int pnp_register_card_driver(struct pnp_card_driver *drv)
  */
 void pnp_unregister_card_driver(struct pnp_card_driver *drv)
 {
-       spin_lock(&pnp_lock);
+       mutex_lock(&pnp_lock);
        list_del(&drv->global_list);
-       spin_unlock(&pnp_lock);
+       mutex_unlock(&pnp_lock);
        pnp_unregister_driver(&drv->link);
 }
 
index cb6ce42f8e77d577eb1e9ac07388ab2bd0dbeb1b..b54620e53830da9745ef21e1c6352be972a7189d 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/list.h>
 #include <linux/device.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/init.h>
 #include <linux/string.h>
 #include <linux/slab.h>
@@ -19,7 +20,7 @@
 
 static LIST_HEAD(pnp_protocols);
 LIST_HEAD(pnp_global);
-DEFINE_SPINLOCK(pnp_lock);
+DEFINE_MUTEX(pnp_lock);
 
 /*
  * ACPI or PNPBIOS should tell us about all platform devices, so we can
@@ -41,6 +42,13 @@ void *pnp_alloc(long size)
        return result;
 }
 
+static void pnp_remove_protocol(struct pnp_protocol *protocol)
+{
+       mutex_lock(&pnp_lock);
+       list_del(&protocol->protocol_list);
+       mutex_unlock(&pnp_lock);
+}
+
 /**
  * pnp_protocol_register - adds a pnp protocol to the pnp layer
  * @protocol: pointer to the corresponding pnp_protocol structure
@@ -49,13 +57,14 @@ void *pnp_alloc(long size)
  */
 int pnp_register_protocol(struct pnp_protocol *protocol)
 {
-       int nodenum;
        struct list_head *pos;
+       int nodenum, ret;
 
        INIT_LIST_HEAD(&protocol->devices);
        INIT_LIST_HEAD(&protocol->cards);
        nodenum = 0;
-       spin_lock(&pnp_lock);
+
+       mutex_lock(&pnp_lock);
 
        /* assign the lowest unused number */
        list_for_each(pos, &pnp_protocols) {
@@ -66,12 +75,18 @@ int pnp_register_protocol(struct pnp_protocol *protocol)
                }
        }
 
-       list_add_tail(&protocol->protocol_list, &pnp_protocols);
-       spin_unlock(&pnp_lock);
-
        protocol->number = nodenum;
        dev_set_name(&protocol->dev, "pnp%d", nodenum);
-       return device_register(&protocol->dev);
+
+       list_add_tail(&protocol->protocol_list, &pnp_protocols);
+
+       mutex_unlock(&pnp_lock);
+
+       ret = device_register(&protocol->dev);
+       if (ret)
+               pnp_remove_protocol(protocol);
+
+       return ret;
 }
 
 /**
@@ -80,9 +95,7 @@ int pnp_register_protocol(struct pnp_protocol *protocol)
  */
 void pnp_unregister_protocol(struct pnp_protocol *protocol)
 {
-       spin_lock(&pnp_lock);
-       list_del(&protocol->protocol_list);
-       spin_unlock(&pnp_lock);
+       pnp_remove_protocol(protocol);
        device_unregister(&protocol->dev);
 }
 
@@ -157,18 +170,36 @@ struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *protocol, int id,
        return dev;
 }
 
+static void pnp_delist_device(struct pnp_dev *dev)
+{
+       mutex_lock(&pnp_lock);
+       list_del(&dev->global_list);
+       list_del(&dev->protocol_list);
+       mutex_unlock(&pnp_lock);
+}
+
 int __pnp_add_device(struct pnp_dev *dev)
 {
+       int ret;
+
        pnp_fixup_device(dev);
        dev->status = PNP_READY;
-       spin_lock(&pnp_lock);
+
+       mutex_lock(&pnp_lock);
+
        list_add_tail(&dev->global_list, &pnp_global);
        list_add_tail(&dev->protocol_list, &dev->protocol->devices);
-       spin_unlock(&pnp_lock);
-       if (dev->protocol->can_wakeup)
+
+       mutex_unlock(&pnp_lock);
+
+       ret = device_register(&dev->dev);
+       if (ret)
+               pnp_delist_device(dev);
+       else if (dev->protocol->can_wakeup)
                device_set_wakeup_capable(&dev->dev,
                                dev->protocol->can_wakeup(dev));
-       return device_register(&dev->dev);
+
+       return ret;
 }
 
 /*
@@ -203,10 +234,7 @@ int pnp_add_device(struct pnp_dev *dev)
 
 void __pnp_remove_device(struct pnp_dev *dev)
 {
-       spin_lock(&pnp_lock);
-       list_del(&dev->global_list);
-       list_del(&dev->protocol_list);
-       spin_unlock(&pnp_lock);
+       pnp_delist_device(dev);
        device_unregister(&dev->dev);
 }
 
index 4e57d3370368f597bb27ed4bcc4693153ce0e0de..153a493b5413e06482dd9909bf0301e6d26eae1f 100644 (file)
@@ -58,22 +58,22 @@ static const struct pnp_device_id *match_device(struct pnp_driver *drv,
 
 int pnp_device_attach(struct pnp_dev *pnp_dev)
 {
-       spin_lock(&pnp_lock);
+       mutex_lock(&pnp_lock);
        if (pnp_dev->status != PNP_READY) {
-               spin_unlock(&pnp_lock);
+               mutex_unlock(&pnp_lock);
                return -EBUSY;
        }
        pnp_dev->status = PNP_ATTACHED;
-       spin_unlock(&pnp_lock);
+       mutex_unlock(&pnp_lock);
        return 0;
 }
 
 void pnp_device_detach(struct pnp_dev *pnp_dev)
 {
-       spin_lock(&pnp_lock);
+       mutex_lock(&pnp_lock);
        if (pnp_dev->status == PNP_ATTACHED)
                pnp_dev->status = PNP_READY;
-       spin_unlock(&pnp_lock);
+       mutex_unlock(&pnp_lock);
        pnp_disable_dev(pnp_dev);
 }
 
index d2b780aade895e2baf44a7960f064025f7063dc6..5153d1d69aee8e0472c21ec63ff393f6fb9b7682 100644 (file)
@@ -248,6 +248,7 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
        if (!dev)
                return -ENOMEM;
 
+       ACPI_COMPANION_SET(&dev->dev, device);
        dev->data = device;
        /* .enabled means the device can decode the resources */
        dev->active = device->status.enabled;
@@ -290,11 +291,9 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
                return error;
        }
 
-       error = acpi_bind_one(&dev->dev, device);
-
        num++;
 
-       return error;
+       return 0;
 }
 
 static acpi_status __init pnpacpi_add_device_handler(acpi_handle handle,
index 63d4033eb683868738dedca38e838fe7e4b56cea..e03877c4b1958c853563705087faf52a918193b6 100644 (file)
@@ -1054,7 +1054,7 @@ static const struct rapl_defaults rapl_defaults_atom = {
                .driver_data = (kernel_ulong_t)&_ops,   \
                }
 
-static const struct x86_cpu_id rapl_ids[] = {
+static const struct x86_cpu_id rapl_ids[] __initconst = {
        RAPL_CPU(0x2a, rapl_defaults_core),/* Sandy Bridge */
        RAPL_CPU(0x2d, rapl_defaults_core),/* Sandy Bridge EP */
        RAPL_CPU(0x37, rapl_defaults_atom),/* Valleyview */
@@ -1062,6 +1062,7 @@ static const struct x86_cpu_id rapl_ids[] = {
        RAPL_CPU(0x3c, rapl_defaults_core),/* Haswell */
        RAPL_CPU(0x3d, rapl_defaults_core),/* Broadwell */
        RAPL_CPU(0x3f, rapl_defaults_hsw_server),/* Haswell servers */
+       RAPL_CPU(0x4f, rapl_defaults_hsw_server),/* Broadwell servers */
        RAPL_CPU(0x45, rapl_defaults_core),/* Haswell ULT */
        RAPL_CPU(0x4C, rapl_defaults_atom),/* Braswell */
        RAPL_CPU(0x4A, rapl_defaults_atom),/* Tangier */
index 1e6899bc9429012e177de03b68435ded26c4c6a0..5815e81b5fc603cdad8463bcdd5cfe0880186376 100644 (file)
@@ -234,18 +234,7 @@ static struct pnp_driver fintek_8250_driver = {
        .id_table       = fintek_dev_table,
 };
 
-static int fintek_8250_init(void)
-{
-       return pnp_register_driver(&fintek_8250_driver);
-}
-module_init(fintek_8250_init);
-
-static void fintek_8250_exit(void)
-{
-       pnp_unregister_driver(&fintek_8250_driver);
-}
-module_exit(fintek_8250_exit);
-
+module_pnp_driver(fintek_8250_driver);
 MODULE_DESCRIPTION("Fintek F812164 module");
 MODULE_AUTHOR("Ricardo Ribalda <ricardo.ribalda@gmail.com>");
 MODULE_LICENSE("GPL");
index 05ee0bf88ce975f796eaf100d9ea54d529165dd8..3c3fd417ddeb135db14f50a9de9a5d8411bab8e8 100644 (file)
@@ -51,6 +51,7 @@
 #define DRV_VERSION    "1.11"
 
 /* Includes */
+#include <linux/acpi.h>                        /* For ACPI support */
 #include <linux/module.h>              /* For module specific items */
 #include <linux/moduleparam.h>         /* For new moduleparam's */
 #include <linux/types.h>               /* For standard types (like size_t) */
@@ -103,6 +104,8 @@ static struct {             /* this is private data for the iTCO_wdt device */
        struct platform_device *dev;
        /* the PCI-device */
        struct pci_dev *pdev;
+       /* whether or not the watchdog has been suspended */
+       bool suspended;
 } iTCO_wdt_private;
 
 /* module parameters */
@@ -571,12 +574,60 @@ static void iTCO_wdt_shutdown(struct platform_device *dev)
        iTCO_wdt_stop(NULL);
 }
 
+#ifdef CONFIG_PM_SLEEP
+/*
+ * Suspend-to-idle requires this, because it stops the ticks and timekeeping, so
+ * the watchdog cannot be pinged while in that state.  In ACPI sleep states the
+ * watchdog is stopped by the platform firmware.
+ */
+
+#ifdef CONFIG_ACPI
+static inline bool need_suspend(void)
+{
+       return acpi_target_system_state() == ACPI_STATE_S0;
+}
+#else
+static inline bool need_suspend(void) { return true; }
+#endif
+
+static int iTCO_wdt_suspend_noirq(struct device *dev)
+{
+       int ret = 0;
+
+       iTCO_wdt_private.suspended = false;
+       if (watchdog_active(&iTCO_wdt_watchdog_dev) && need_suspend()) {
+               ret = iTCO_wdt_stop(&iTCO_wdt_watchdog_dev);
+               if (!ret)
+                       iTCO_wdt_private.suspended = true;
+       }
+       return ret;
+}
+
+static int iTCO_wdt_resume_noirq(struct device *dev)
+{
+       if (iTCO_wdt_private.suspended)
+               iTCO_wdt_start(&iTCO_wdt_watchdog_dev);
+
+       return 0;
+}
+
+static struct dev_pm_ops iTCO_wdt_pm = {
+       .suspend_noirq = iTCO_wdt_suspend_noirq,
+       .resume_noirq = iTCO_wdt_resume_noirq,
+};
+
+#define ITCO_WDT_PM_OPS        (&iTCO_wdt_pm)
+#else
+#define ITCO_WDT_PM_OPS        NULL
+#endif /* CONFIG_PM_SLEEP */
+
 static struct platform_driver iTCO_wdt_driver = {
        .probe          = iTCO_wdt_probe,
        .remove         = iTCO_wdt_remove,
        .shutdown       = iTCO_wdt_shutdown,
        .driver         = {
                .name   = DRV_NAME,
+               .pm     = ITCO_WDT_PM_OPS,
        },
 };
 
index 61e32ec1fc4d40230965e4d2915b4701ec54b5c4..8de4fa90e8c4add33967c8dbec6b7cfe2d01b2c4 100644 (file)
@@ -252,6 +252,7 @@ struct acpi_device_pnp {
 #define acpi_device_bid(d)     ((d)->pnp.bus_id)
 #define acpi_device_adr(d)     ((d)->pnp.bus_address)
 const char *acpi_device_hid(struct acpi_device *device);
+#define acpi_device_uid(d)     ((d)->pnp.unique_id)
 #define acpi_device_name(d)    ((d)->pnp.device_name)
 #define acpi_device_class(d)   ((d)->pnp.device_class)
 
@@ -386,7 +387,8 @@ static inline bool is_acpi_node(struct fwnode_handle *fwnode)
 
 static inline struct acpi_device *acpi_node(struct fwnode_handle *fwnode)
 {
-       return fwnode ? container_of(fwnode, struct acpi_device, fwnode) : NULL;
+       return is_acpi_node(fwnode) ?
+               container_of(fwnode, struct acpi_device, fwnode) : NULL;
 }
 
 static inline struct fwnode_handle *acpi_fwnode_handle(struct acpi_device *adev)
index f8e8b34dc4274ee8fd105565fd8d731d3615e109..392c74c400569a8b14937501fd87ce2aed69c503 100644 (file)
 #define IOMMU_OF_TABLES()      OF_TABLE(CONFIG_OF_IOMMU, iommu)
 #define RESERVEDMEM_OF_TABLES()        OF_TABLE(CONFIG_OF_RESERVED_MEM, reservedmem)
 #define CPU_METHOD_OF_TABLES() OF_TABLE(CONFIG_SMP, cpu_method)
+#define CPUIDLE_METHOD_OF_TABLES() OF_TABLE(CONFIG_CPU_IDLE, cpuidle_method)
 #define EARLYCON_OF_TABLES()   OF_TABLE(CONFIG_SERIAL_EARLYCON, earlycon)
 
 #define KERNEL_DTB()                                                   \
        CLKSRC_OF_TABLES()                                              \
        IOMMU_OF_TABLES()                                               \
        CPU_METHOD_OF_TABLES()                                          \
+       CPUIDLE_METHOD_OF_TABLES()                                      \
        KERNEL_DTB()                                                    \
        IRQCHIP_OF_MATCH_TABLE()                                        \
        EARLYCON_OF_TABLES()
index 24c7aa8b1d20c6fce9dd7ede9d051d04afc7c07d..dd12127f171c7569fd169915d01dd24e7af97aba 100644 (file)
@@ -53,10 +53,16 @@ static inline acpi_handle acpi_device_handle(struct acpi_device *adev)
        return adev ? adev->handle : NULL;
 }
 
-#define ACPI_COMPANION(dev)            ((dev)->acpi_node.companion)
-#define ACPI_COMPANION_SET(dev, adev)  ACPI_COMPANION(dev) = (adev)
+#define ACPI_COMPANION(dev)            acpi_node((dev)->fwnode)
+#define ACPI_COMPANION_SET(dev, adev)  set_primary_fwnode(dev, (adev) ? \
+       acpi_fwnode_handle(adev) : NULL)
 #define ACPI_HANDLE(dev)               acpi_device_handle(ACPI_COMPANION(dev))
 
+static inline bool has_acpi_companion(struct device *dev)
+{
+       return is_acpi_node(dev->fwnode);
+}
+
 static inline void acpi_preset_companion(struct device *dev,
                                         struct acpi_device *parent, u64 addr)
 {
@@ -471,6 +477,11 @@ static inline struct fwnode_handle *acpi_fwnode_handle(struct acpi_device *adev)
        return NULL;
 }
 
+static inline bool has_acpi_companion(struct device *dev)
+{
+       return false;
+}
+
 static inline const char *acpi_dev_name(struct acpi_device *adev)
 {
        return NULL;
index 602fbbfcfeedcf415bd09574a73e24798fe0feb1..0a83a1e648b088c1acc8a7304eb6be71be146026 100644 (file)
@@ -91,7 +91,7 @@ struct devfreq_event_desc {
        const char *name;
        void *driver_data;
 
-       struct devfreq_event_ops *ops;
+       const struct devfreq_event_ops *ops;
 };
 
 #if defined(CONFIG_PM_DEVFREQ_EVENT)
index f3f2c7e38060245e8e40df56d9d924168c795abd..6558af90c8fe3b9263441dc401b3689940d3453e 100644 (file)
@@ -38,6 +38,7 @@ struct class;
 struct subsys_private;
 struct bus_type;
 struct device_node;
+struct fwnode_handle;
 struct iommu_ops;
 struct iommu_group;
 
@@ -650,14 +651,6 @@ struct device_dma_parameters {
        unsigned long segment_boundary_mask;
 };
 
-struct acpi_device;
-
-struct acpi_dev_node {
-#ifdef CONFIG_ACPI
-       struct acpi_device *companion;
-#endif
-};
-
 /**
  * struct device - The basic device structure
  * @parent:    The device's "parent" device, the device to which it is attached.
@@ -703,7 +696,7 @@ struct acpi_dev_node {
  * @cma_area:  Contiguous memory area for dma allocations
  * @archdata:  For arch-specific additions.
  * @of_node:   Associated device tree node.
- * @acpi_node: Associated ACPI device node.
+ * @fwnode:    Associated device node supplied by platform firmware.
  * @devt:      For creating the sysfs "dev".
  * @id:                device instance
  * @devres_lock: Spinlock to protect the resource of the device.
@@ -779,7 +772,7 @@ struct device {
        struct dev_archdata     archdata;
 
        struct device_node      *of_node; /* associated device tree node */
-       struct acpi_dev_node    acpi_node; /* associated ACPI device node */
+       struct fwnode_handle    *fwnode; /* firmware device node */
 
        dev_t                   devt;   /* dev_t, creates the sysfs "dev" */
        u32                     id;     /* device instance */
@@ -954,6 +947,9 @@ extern void unlock_device_hotplug(void);
 extern int lock_device_hotplug_sysfs(void);
 extern int device_offline(struct device *dev);
 extern int device_online(struct device *dev);
+extern void set_primary_fwnode(struct device *dev, struct fwnode_handle *fwnode);
+extern void set_secondary_fwnode(struct device *dev, struct fwnode_handle *fwnode);
+
 /*
  * Root device objects for grouping under /sys/devices
  */
diff --git a/include/linux/fwnode.h b/include/linux/fwnode.h
new file mode 100644 (file)
index 0000000..0408545
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * fwnode.h - Firmware device node object handle type definition.
+ *
+ * Copyright (C) 2015, Intel Corporation
+ * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _LINUX_FWNODE_H_
+#define _LINUX_FWNODE_H_
+
+enum fwnode_type {
+       FWNODE_INVALID = 0,
+       FWNODE_OF,
+       FWNODE_ACPI,
+       FWNODE_PDATA,
+};
+
+struct fwnode_handle {
+       enum fwnode_type type;
+       struct fwnode_handle *secondary;
+};
+
+#endif
index 898033f41d767dda360b6a1d0a4b8361c8a1a5a3..e83a738a3b8741c9fe6401d6d89d8d2e02900f52 100644 (file)
@@ -278,7 +278,7 @@ static inline int i2c_slave_event(struct i2c_client *client,
  * @platform_data: stored in i2c_client.dev.platform_data
  * @archdata: copied into i2c_client.dev.archdata
  * @of_node: pointer to OpenFirmware device node
- * @acpi_node: ACPI device node
+ * @fwnode: device node supplied by the platform firmware
  * @irq: stored in i2c_client.irq
  *
  * I2C doesn't actually support hardware probing, although controllers and
@@ -299,7 +299,7 @@ struct i2c_board_info {
        void            *platform_data;
        struct dev_archdata     *archdata;
        struct device_node *of_node;
-       struct acpi_dev_node acpi_node;
+       struct fwnode_handle *fwnode;
        int             irq;
 };
 
index ae4882ca4a6423fc6f26a0da9b6e22f41871a353..58f1e75ba105ca9096f8fbf1d60b808e08087c03 100644 (file)
@@ -59,7 +59,7 @@ extern int platform_add_devices(struct platform_device **, int);
 
 struct platform_device_info {
                struct device *parent;
-               struct acpi_dev_node acpi_node;
+               struct fwnode_handle *fwnode;
 
                const char *name;
                int id;
diff --git a/include/linux/pm-trace.h b/include/linux/pm-trace.h
new file mode 100644 (file)
index 0000000..ecbde7a
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef PM_TRACE_H
+#define PM_TRACE_H
+
+#ifdef CONFIG_PM_TRACE
+#include <asm/pm-trace.h>
+#include <linux/types.h>
+
+extern int pm_trace_enabled;
+
+static inline int pm_trace_is_enabled(void)
+{
+       return pm_trace_enabled;
+}
+
+struct device;
+extern void set_trace_device(struct device *);
+extern void generate_pm_trace(const void *tracedata, unsigned int user);
+extern int show_trace_dev_match(char *buf, size_t size);
+
+#define TRACE_DEVICE(dev) do { \
+       if (pm_trace_enabled) \
+               set_trace_device(dev); \
+       } while(0)
+
+#else
+
+static inline int pm_trace_is_enabled(void) { return 0; }
+
+#define TRACE_DEVICE(dev) do { } while (0)
+#define TRACE_RESUME(dev) do { } while (0)
+#define TRACE_SUSPEND(dev) do { } while (0)
+
+#endif
+
+#endif
index e2f1be6dd9dd386fb1c3e6e8c62580454ff85670..2d29c64f8fb1ee73b454ff8f428e5d67cb7bf57c 100644 (file)
@@ -603,10 +603,18 @@ extern void dev_pm_put_subsys_data(struct device *dev);
  * Power domains provide callbacks that are executed during system suspend,
  * hibernation, system resume and during runtime PM transitions along with
  * subsystem-level and driver-level callbacks.
+ *
+ * @detach: Called when removing a device from the domain.
+ * @activate: Called before executing probe routines for bus types and drivers.
+ * @sync: Called after successful driver probe.
+ * @dismiss: Called after unsuccessful driver probe and after driver removal.
  */
 struct dev_pm_domain {
        struct dev_pm_ops       ops;
        void (*detach)(struct device *dev, bool power_off);
+       int (*activate)(struct device *dev);
+       void (*sync)(struct device *dev);
+       void (*dismiss)(struct device *dev);
 };
 
 /*
index 080e778118ba85dfab3a1bd99dd0967917837312..681ccb053f72474ae4424bf9e083194f5384cec5 100644 (file)
@@ -127,7 +127,7 @@ static inline struct generic_pm_domain_data *dev_gpd_data(struct device *dev)
        return to_gpd_data(dev->power.subsys_data->domain_data);
 }
 
-extern struct generic_pm_domain *dev_to_genpd(struct device *dev);
+extern struct generic_pm_domain *pm_genpd_lookup_dev(struct device *dev);
 extern int __pm_genpd_add_device(struct generic_pm_domain *genpd,
                                 struct device *dev,
                                 struct gpd_timing_data *td);
@@ -163,9 +163,9 @@ static inline struct generic_pm_domain_data *dev_gpd_data(struct device *dev)
 {
        return ERR_PTR(-ENOSYS);
 }
-static inline struct generic_pm_domain *dev_to_genpd(struct device *dev)
+static inline struct generic_pm_domain *pm_genpd_lookup_dev(struct device *dev)
 {
-       return ERR_PTR(-ENOSYS);
+       return NULL;
 }
 static inline int __pm_genpd_add_device(struct generic_pm_domain *genpd,
                                        struct device *dev,
index 6512e9cbc6d57ca6abe80cc61a15db606c240cb7..5df733b8f704d268995ace95857a7c93528e460f 100644 (file)
@@ -510,4 +510,16 @@ static inline void pnp_unregister_driver(struct pnp_driver *drv) { }
 
 #endif /* CONFIG_PNP */
 
+/**
+ * module_pnp_driver() - Helper macro for registering a PnP driver
+ * @__pnp_driver: pnp_driver struct
+ *
+ * Helper macro for PnP drivers which do not do anything special in module
+ * init/exit. This eliminates a lot of boilerplate. Each module may only
+ * use this macro once, and calling it replaces module_init() and module_exit()
+ */
+#define module_pnp_driver(__pnp_driver) \
+       module_driver(__pnp_driver, pnp_register_driver, \
+                                   pnp_unregister_driver)
+
 #endif /* _LINUX_PNP_H */
index a6a3d98bd7e9af19ffb3b5be510ba015d7b000b3..de8bdf417a35adc745e37fc1df1de7453d518895 100644 (file)
@@ -13,6 +13,7 @@
 #ifndef _LINUX_PROPERTY_H_
 #define _LINUX_PROPERTY_H_
 
+#include <linux/fwnode.h>
 #include <linux/types.h>
 
 struct device;
@@ -40,16 +41,6 @@ int device_property_read_string_array(struct device *dev, const char *propname,
 int device_property_read_string(struct device *dev, const char *propname,
                                const char **val);
 
-enum fwnode_type {
-       FWNODE_INVALID = 0,
-       FWNODE_OF,
-       FWNODE_ACPI,
-};
-
-struct fwnode_handle {
-       enum fwnode_type type;
-};
-
 bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname);
 int fwnode_property_read_u8_array(struct fwnode_handle *fwnode,
                                  const char *propname, u8 *val,
@@ -140,4 +131,37 @@ static inline int fwnode_property_read_u64(struct fwnode_handle *fwnode,
        return fwnode_property_read_u64_array(fwnode, propname, val, 1);
 }
 
+/**
+ * struct property_entry - "Built-in" device property representation.
+ * @name: Name of the property.
+ * @type: Type of the property.
+ * @nval: Number of items of type @type making up the value.
+ * @value: Value of the property (an array of @nval items of type @type).
+ */
+struct property_entry {
+       const char *name;
+       enum dev_prop_type type;
+       size_t nval;
+       union {
+               void *raw_data;
+               u8 *u8_data;
+               u16 *u16_data;
+               u32 *u32_data;
+               u64 *u64_data;
+               const char **str;
+       } value;
+};
+
+/**
+ * struct property_set - Collection of "built-in" device properties.
+ * @fwnode: Handle to be pointed to by the fwnode field of struct device.
+ * @properties: Array of properties terminated with a null entry.
+ */
+struct property_set {
+       struct fwnode_handle fwnode;
+       struct property_entry *properties;
+};
+
+void device_add_property_set(struct device *dev, struct property_set *pset);
+
 #endif /* _LINUX_PROPERTY_H_ */
diff --git a/include/linux/resume-trace.h b/include/linux/resume-trace.h
deleted file mode 100644 (file)
index f31db23..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef RESUME_TRACE_H
-#define RESUME_TRACE_H
-
-#ifdef CONFIG_PM_TRACE
-#include <asm/resume-trace.h>
-#include <linux/types.h>
-
-extern int pm_trace_enabled;
-
-static inline int pm_trace_is_enabled(void)
-{
-       return pm_trace_enabled;
-}
-
-struct device;
-extern void set_trace_device(struct device *);
-extern void generate_resume_trace(const void *tracedata, unsigned int user);
-extern int show_trace_dev_match(char *buf, size_t size);
-
-#define TRACE_DEVICE(dev) do { \
-       if (pm_trace_enabled) \
-               set_trace_device(dev); \
-       } while(0)
-
-#else
-
-static inline int pm_trace_is_enabled(void) { return 0; }
-
-#define TRACE_DEVICE(dev) do { } while (0)
-#define TRACE_RESUME(dev) do { } while (0)
-
-#endif
-
-#endif
index 9a59d042ea84f67c40537f2bfbcf7593a05d8716..86e8157a450f51c1ac592d9c8d2fa4a09e47c21f 100644 (file)
@@ -11,7 +11,7 @@
 #include <linux/export.h>
 #include <linux/kobject.h>
 #include <linux/string.h>
-#include <linux/resume-trace.h>
+#include <linux/pm-trace.h>
 #include <linux/workqueue.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
index b7d6b3a721b196ed581293a9a657ef54b7cb2798..8d7a1ef7275855089957f877d6743b653dd7f076 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/ftrace.h>
 #include <trace/events/power.h>
 #include <linux/compiler.h>
+#include <linux/moduleparam.h>
 
 #include "power.h"
 
@@ -233,12 +234,20 @@ static bool platform_suspend_again(suspend_state_t state)
                suspend_ops->suspend_again() : false;
 }
 
+#ifdef CONFIG_PM_DEBUG
+static unsigned int pm_test_delay = 5;
+module_param(pm_test_delay, uint, 0644);
+MODULE_PARM_DESC(pm_test_delay,
+                "Number of seconds to wait before resuming from suspend test");
+#endif
+
 static int suspend_test(int level)
 {
 #ifdef CONFIG_PM_DEBUG
        if (pm_test_level == level) {
-               printk(KERN_INFO "suspend debug: Waiting for 5 seconds.\n");
-               mdelay(5000);
+               printk(KERN_INFO "suspend debug: Waiting for %d second(s).\n",
+                               pm_test_delay);
+               mdelay(pm_test_delay * 1000);
                return 1;
        }
 #endif /* !CONFIG_PM_DEBUG */